|
4 | 4 | import time
|
5 | 5 | import unittest
|
6 | 6 |
|
7 |
| - |
8 |
| -from prometheus_client import Gauge, Counter, Summary, Histogram, Metric |
9 |
| -from prometheus_client import CollectorRegistry, generate_latest, ProcessCollector |
10 |
| -from prometheus_client import push_to_gateway, pushadd_to_gateway, delete_from_gateway |
11 |
| -from prometheus_client import CONTENT_TYPE_LATEST, instance_ip_grouping_key |
12 |
| - |
13 |
| -try: |
14 |
| - from BaseHTTPServer import BaseHTTPRequestHandler |
15 |
| - from BaseHTTPServer import HTTPServer |
16 |
| -except ImportError: |
17 |
| - # Python 3 |
18 |
| - from http.server import BaseHTTPRequestHandler |
19 |
| - from http.server import HTTPServer |
20 |
| - |
21 |
| - |
| 7 | +from prometheus_client.core import * |
22 | 8 |
|
23 | 9 | class TestCounter(unittest.TestCase):
|
24 | 10 | def setUp(self):
|
@@ -304,178 +290,83 @@ def test_invalid_names_raise(self):
|
304 | 290 | self.assertRaises(ValueError, Summary, 'c', '', labelnames=['quantile'])
|
305 | 291 |
|
306 | 292 |
|
307 |
| -class TestGenerateText(unittest.TestCase): |
| 293 | +class TestMetricFamilies(unittest.TestCase): |
308 | 294 | def setUp(self):
|
309 | 295 | self.registry = CollectorRegistry()
|
310 | 296 |
|
| 297 | + def custom_collector(self, metric_family): |
| 298 | + class CustomCollector(object): |
| 299 | + def collect(self): |
| 300 | + return [metric_family] |
| 301 | + self.registry.register(CustomCollector()) |
| 302 | + |
311 | 303 | def test_counter(self):
|
312 |
| - c = Counter('cc', 'A counter', registry=self.registry) |
313 |
| - c.inc() |
314 |
| - self.assertEqual(b'# HELP cc A counter\n# TYPE cc counter\ncc 1.0\n', generate_latest(self.registry)) |
| 304 | + self.custom_collector(CounterMetricFamily('c', 'help', value=1)) |
| 305 | + self.assertEqual(1, self.registry.get_sample_value('c', {})) |
| 306 | + |
| 307 | + def test_counter_labels(self): |
| 308 | + cmf = CounterMetricFamily('c', 'help', labels=['a', 'c']) |
| 309 | + cmf.add_metric(['b', 'd'], 2) |
| 310 | + self.custom_collector(cmf) |
| 311 | + self.assertEqual(2, self.registry.get_sample_value('c', {'a': 'b', 'c': 'd'})) |
315 | 312 |
|
316 | 313 | def test_gauge(self):
|
317 |
| - g = Gauge('gg', 'A gauge', registry=self.registry) |
318 |
| - g.set(17) |
319 |
| - self.assertEqual(b'# HELP gg A gauge\n# TYPE gg gauge\ngg 17.0\n', generate_latest(self.registry)) |
| 314 | + self.custom_collector(GaugeMetricFamily('g', 'help', value=1)) |
| 315 | + self.assertEqual(1, self.registry.get_sample_value('g', {})) |
| 316 | + |
| 317 | + def test_gauge_labels(self): |
| 318 | + cmf = GaugeMetricFamily('g', 'help', labels=['a']) |
| 319 | + cmf.add_metric(['b'], 2) |
| 320 | + self.custom_collector(cmf) |
| 321
179B
| + self.assertEqual(2, self.registry.get_sample_value('g', {'a':'b'})) |
320 | 322 |
|
321 | 323 | def test_summary(self):
|
322 |
| - s = Summary('ss', 'A summary', ['a', 'b'], registry=self.registry) |
323 |
| - s.labels('c', 'd').observe(17) |
324 |
| - self.assertEqual(b'# HELP ss A summary\n# TYPE ss summary\nss_count{a="c",b="d"} 1.0\nss_sum{a="c",b="d"} 17.0\n', generate_latest(self.registry)) |
325 |
| - |
326 |
| - def test_unicode(self): |
327 |
| - c = Counter('cc', '\u4500', ['l'], registry=self.registry) |
328 |
| - c.labels('\u4500').inc() |
329 |
| - self.assertEqual(b'# HELP cc \xe4\x94\x80\n# TYPE cc counter\ncc{l="\xe4\x94\x80"} 1.0\n', generate_latest(self.registry)) |
330 |
| - |
331 |
| - def test_escaping(self): |
332 |
| - c = Counter('cc', 'A\ncount\\er', ['a'], registry=self.registry) |
333 |
| - c.labels('\\x\n"').inc(1) |
334 |
| - self.assertEqual(b'# HELP cc A\\ncount\\\\er\n# TYPE cc counter\ncc{a="\\\\x\\n\\""} 1.0\n', generate_latest(self.registry)) |
335 |
| - |
336 |
| - def test_nonnumber(self): |
337 |
| - class MyNumber(): |
338 |
| - def __repr__(self): |
339 |
| - return "MyNumber(123)" |
340 |
| - def __float__(self): |
341 |
| - return 123.0 |
342 |
| - class MyCollector(): |
343 |
| - def collect(self): |
344 |
| - metric = Metric("nonnumber", "Non number", 'untyped') |
345 |
| - metric.add_sample("nonnumber", {}, MyNumber()) |
346 |
| - yield metric |
347 |
| - self.registry.register(MyCollector()) |
348 |
| - self.assertEqual(b'# HELP nonnumber Non number\n# TYPE nonnumber untyped\nnonnumber 123.0\n', generate_latest(self.registry)) |
| 324 | + self.custom_collector(SummaryMetricFamily('s', 'help', count_value=1, sum_value=2)) |
| 325 | + self.assertEqual(1, self.registry.get_sample_value('s_count', {})) |
| 326 | + self.assertEqual(2, self.registry.get_sample_value('s_sum', {})) |
349 | 327 |
|
| 328 | + def test_summary_labels(self): |
| 329 | + cmf = SummaryMetricFamily('s', 'help', labels=['a']) |
| 330 | + cmf.add_metric(['b'], count_value=1, sum_value=2) |
| 331 | + self.custom_collector(cmf) |
| 332 | + self.assertEqual(1, self.registry.get_sample_value('s_count', {'a': 'b'})) |
| 333 | + self.assertEqual(2, self.registry.get_sample_value('s_sum', {'a': 'b'})) |
350 | 334 |
|
351 |
| -class TestProcessCollector(unittest.TestCase): |
352 |
| - def setUp(self): |
353 |
| - self.registry = CollectorRegistry() |
354 |
| - self.test_proc = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'proc') |
355 |
| - |
356 |
| - def test_working(self): |
357 |
| - collector = ProcessCollector(proc=self.test_proc, pid=lambda: 26231, registry=self.registry) |
358 |
| - collector._ticks = 100 |
359 |
| - |
360 |
| - self.assertEqual(17.21, self.registry.get_sample_value('process_cpu_seconds_total')) |
361 |
| - self.assertEqual(56274944.0, self.registry.get_sample_value('process_virtual_memory_bytes')) |
362 |
| - self.assertEqual(8114176, self.registry.get_sample_value('process_resident_memory_bytes')) |
363 |
| - self.assertEqual(1418184099.75, self.registry.get_sample_value('process_start_time_seconds')) |
364 |
| - self.assertEqual(2048.0, self.registry.get_sample_value('process_max_fds')) |
365 |
| - self.assertEqual(5.0, self.registry.get_sample_value('process_open_fds')) |
366 |
| - self.assertEqual(None, self.registry.get_sample_value('process_fake_namespace')) |
367 |
| - |
368 |
| - def test_namespace(self): |
369 |
| - collector = ProcessCollector(proc=self.test_proc, pid=lambda: 26231, registry=self.registry, namespace='n') |
370 |
| - collector._ticks = 100 |
371 |
| - |
372 |
| - self.assertEqual(17.21, self.registry.get_sample_value('n_process_cpu_seconds_total')) |
373 |
| - self.assertEqual(56274944.0, self.registry.get_sample_value('n_process_virtual_memory_bytes')) |
374 |
| - self.assertEqual(8114176, self.registry.get_sample_value('n_process_resident_memory_bytes')) |
375 |
| - self.assertEqual(1418184099.75, self.registry.get_sample_value('n_process_start_time_seconds')) |
376 |
| - self.assertEqual(2048.0, self.registry.get_sample_value('n_process_max_fds')) |
377 |
| - self.assertEqual(5.0, self.registry.get_sample_value('n_process_open_fds')) |
378 |
| - self.assertEqual(None, self.registry.get_sample_value('process_cpu_seconds_total')) |
379 |
| - |
380 |
| - def test_working_584(self): |
381 |
| - collector = ProcessCollector(proc=self.test_proc, pid=lambda: "584\n", registry=self.registry) |
382 |
| - collector._ticks = 100 |
383 |
| - |
384 |
| - self.assertEqual(0.0, self.registry.get_sample_value('process_cpu_seconds_total')) |
385 |
| - self.assertEqual(10395648.0, self.registry.get_sample_value('process_virtual_memory_bytes')) |
386 |
| - self.assertEqual(634880, self.registry.get_sample_value('process_resident_memory_bytes')) |
387 |
| - self.assertEqual(1418291667.75, self.registry.get_sample_value('process_start_time_seconds')) |
388 |
| - self.assertEqual(None, self.registry.get_sample_value('process_max_fds')) |
389 |
| - self.assertEqual(None, self.registry.get_sample_value('process_open_fds')) |
390 |
| - |
391 |
| - def test_working_fake_pid(self): |
392 |
| - collector = ProcessCollector(proc=self.test_proc, pid=lambda: 123, registry=self.registry) |
393 |
| - collector._ticks = 100 |
394 |
| - |
395 |
| - self.assertEqual(None, self.registry.get_sample_value('process_cpu_seconds_total')) |
396 |
| - self.assertEqual(None, self.registry.get_sample_value('process_virtual_memory_bytes')) |
397 |
| - self.assertEqual(None, self.registry.get_sample_value('process_resident_memory_bytes')) |
398 |
| - self.assertEqual(None, self.registry.get_sample_value('process_start_time_seconds')) |
399 |
| - self.assertEqual(None, self.registry.get_sample_value('process_max_fds')) |
400 |
| - self.assertEqual(None, self.registry.get_sample_value('process_open_fds')) |
401 |
| - self.assertEqual(None, self.registry.get_sample_value('process_fake_namespace')) |
402 |
| - |
403 |
| - |
404 |
| -class TestPushGateway(unittest.TestCase): |
405 |
| - def setUp(self): |
406 |
| - self.registry = CollectorRegistry() |
407 |
| - self.counter = Gauge('g', 'help', registry=self.registry) |
408 |
| - self.requests = requests = [] |
409 |
| - class TestHandler(BaseHTTPRequestHandler): |
410 |
| - def do_PUT(self): |
411 |
| - length = int(self.headers['content-length']) |
412 |
| - requests.append((self, self.rfile.read(length))) |
413 |
| - self.send_response(201) |
414 |
| - self.end_headers() |
415 |
| - |
416 |
| - do_POST = do_PUT |
417 |
| - do_DELETE = do_PUT |
418 |
| - |
419 |
| - httpd = HTTPServer(('', 0), TestHandler) |
420 |
| - self.address = 'localhost:' + str(httpd.server_address[1]) |
421 |
| - class TestServer(threading.Thread): |
422 |
| - def run(self): |
423 |
| - httpd.handle_request() |
424 |
| - self.server = TestServer() |
425 |
| - self.server.daemon = True |
426 |
| - self.server.start() |
427 |
| - |
428 |
| - def test_push(self): |
429 |
| - push_to_gateway(self.address, "my_job", self.registry) |
430 |
| - self.assertEqual(self.requests[0][0].command, 'PUT') |
431 |
| - self.assertEqual(self.requests[0][0].path, '/job/my_job') |
432 |
| - self.assertEqual(self.requests[0][0].headers.get('content-type'), CONTENT_TYPE_LATEST) |
433 |
| - self.assertEqual(self.requests[0][1], b'# HELP g help\n# TYPE g gauge\ng 0.0\n') |
434 |
| - |
435 |
| - def test_push_with_groupingkey(self): |
436 |
| - push_to_gateway(self.address, "my_job", self.registry, {'a': 9}) |
437 |
| - self.assertEqual(self.requests[0][0].command, 'PUT') |
438 |
| - self.assertEqual(self.requests[0][0].path, '/job/my_job/a/9') |
439 |
| - self.assertEqual(self.requests[0][0].headers.get('content-type'), CONTENT_TYPE_LATEST) |
440 |
| - self.assertEqual(self.requests[0][1], b'# HELP g help\n# TYPE g gauge\ng 0.0\n') |
441 |
| - |
442 |
| - def test_push_with_complex_groupingkey(self): |
443 |
| - push_to_gateway(self.address, "my_job", self.registry, {'a': 9, 'b': 'a/ z'}) |
444 |
| - self.assertEqual(self.requests[0][0].command, 'PUT') |
445 |
| - self.assertEqual(self.requests[0][0].path, '/job/my_job/a/9/b/a%2F+z') |
446 |
| - self.assertEqual(self.requests[0][0].headers.get('content-type'), CONTENT_TYPE_LATEST) |
447 |
| - self.assertEqual(self.requests[0][1], b'# HELP g help\n# TYPE g gauge\ng 0.0\n') |
448 |
| - |
449 |
| - def test_pushadd(self): |
450 |
| - pushadd_to_gateway(self.address, "my_job", self.registry) |
451 |
| - self.assertEqual(self.requests[0][0].command, 'POST') |
452 |
| - self.assertEqual(self.requests[0][0].path, '/job/my_job') |
453 |
| - self.assertEqual(self.requests[0][0].headers.get('content-type'), CONTENT_TYPE_LATEST) |
454 |
| - self.assertEqual(self.requests[0][1], b'# HELP g help\n# TYPE g gauge\ng 0.0\n') |
455 |
| - |
456 |
| - def test_pushadd_with_groupingkey(self): |
457 |
| - pushadd_to_gateway(self.address, "my_job", self.registry, {'a': 9}) |
458 |
| - self.assertEqual(self.requests[0][0].command, 'POST') |
459 |
| - self.assertEqual(self.requests[0][0].path, '/job/my_job/a/9') |
460 |
| - self.assertEqual(self.requests[0][0].headers.get('content-type'), CONTENT_TYPE_LATEST) |
461 |
| - self.assertEqual(self.requests[0][1], b'# HELP g help\n# TYPE g gauge\ng 0.0\n') |
462 |
| - |
463 |
| - def test_delete(self): |
464 |
| - delete_from_gateway(self.address, "my_job") |
465 |
| - self.assertEqual(self.requests[0][0].command, 'DELETE') |
466 |
| - self.assertEqual(self.requests[0][0].path, '/job/my_job') |
467 |
| - self.assertEqual(self.requests[0][0].headers.get('content-type'), CONTENT_TYPE_LATEST) |
468 |
| - self.assertEqual(self.requests[0][1], b'') |
469 |
| - |
470 |
| - def test_delete_with_groupingkey(self): |
471 |
| - delete_from_gateway(self.address, "my_job", {'a': 9}) |
472 |
| - self.assertEqual(self.requests[0][0].command, 'DELETE') |
473 |
| - self.assertEqual(self.requests[0][0].path, '/job/my_job/a/9') |
474 |
| - self.assertEqual(self.requests[0][0].headers.get('content-type'), CONTENT_TYPE_LATEST) |
475 |
| - self.assertEqual(self.requests[0][1], b'') |
476 |
| - |
477 |
| - def test_instance_ip_grouping_key(self): |
478 |
| - self.assertTrue('' != instance_ip_grouping_key()['instance']) |
| 335 | + def test_histogram(self): |
| 336 | + self.custom_collector(HistogramMetricFamily('h', 'help', buckets=[('0', 1), ('+Inf', 2)], sum_value=3)) |
| 337 | + self.assertEqual(1, self.registry.get_sample_value('h_bucket', {'le': '0'})) |
| 338 | + self.assertEqual(2, self.registry.get_sample_value('h_bucket', {'le': '+Inf'})) |
| 339 | + self.assertEqual(2, self.registry.get_sample_value('h_count', {})) |
| 340 | + self.assertEqual(3, self.registry.get_sample_value('h_sum', {})) |
| 341 | + |
| 342 | + def test_histogram_labels(self): |
| 343 | + cmf = HistogramMetricFamily('h', 'help', labels=['a']) |
| 344 | + cmf.add_metric(['b'], buckets=[('0', 1), ('+Inf', 2)], sum_value=3) |
| 345 | + self.custom_collector(cmf) |
| 346 | + self.assertEqual(1, self.registry.get_sample_value('h_bucket', {'a': 'b', 'le': '0'})) |
| 347 | + self.assertEqual(2, self.registry.get_sample_value('h_bucket', {'a': 'b', 'le': '+Inf'})) |
| 348 | + self.assertEqual(2, self.registry.get_sample_value('h_count', {'a': 'b'})) |
| 349 | + self.assertEqual(3, self.registry.get_sample_value('h_sum', {'a': 'b'})) |
| 350 | + |
| 351 | + def test_bad_constructors(self): |
| 352 | + self.assertRaises(ValueError, CounterMetricFamily, 'c', 'help', value=1, labels=[]) |
| 353 | + self.assertRaises(ValueError, CounterMetricFamily, 'c', 'help', value=1, labels=['a']) |
| 354 | + |
| 355 | + self.assertRaises(ValueError, GaugeMetricFamily, 'g', 'help', value=1, labels=[]) |
| 356 | + self.assertRaises(ValueError, GaugeMetricFamily, 'g', 'help', value=1, labels=['a']) |
| 357 | + |
| 358 | + self.assertRaises(ValueError, SummaryMetricFamily, 's', 'help', sum_value=1) |
| 359 | + self.assertRaises(ValueError, SummaryMetricFamily, 's', 'help', count_value=1) |
| 360 | + self.assertRaises(ValueError, SummaryMetricFamily, 's', 'help', count_value=1, labels=['a']) |
| 361 | + self.assertRaises(ValueError, SummaryMetricFamily, 's', 'help', sum_value=1, labels=['a']) |
| 362 | + self.assertRaises(ValueError, SummaryMetricFamily, 's', 'help', count_value=1, sum_value=1, labels=['a']) |
| 363 | + |
| 364 | + self.assertRaises(ValueError, HistogramMetricFamily, 'h', 'help', sum_value=1) |
| 365 | + self.assertRaises(ValueError, HistogramMetricFamily, 'h', 'help', buckets={}) |
| 366 | + self.assertRaises(ValueError, HistogramMetricFamily, 'h', 'help', sum_value=1, labels=['a']) |
| 367 | + self.assertRaises(ValueError, HistogramMetricFamily, 'h', 'help', buckets={}, labels=['a']) |
| 368 | + self.assertRaises(ValueError, HistogramMetricFamily, 'h', 'help', buckets={}, sum_value=1, labels=['a']) |
| 369 | + self.assertRaises(KeyError, HistogramMetricFamily, 'h', 'help', buckets={}, sum_value=1) |
479 | 370 |
|
480 | 371 |
|
481 | 372 | if __name__ == '__main__':
|
|
0 commit comments