async def fetch_metrics( url: str, fmt: str = None, interval: float = 1.0, loop: BaseEventLoop = None ): """ Fetch metrics from the service endpoint using different formats. This coroutine runs 'n' times, with a brief interval in between, before exiting. """ if fmt is None: # Randomly choose a format to request metrics in. choice = random.choice((TEXT, BINARY)) else: assert fmt in header_kinds choice = fmt print(f"fetching metrics in {choice} format") async with aiohttp.ClientSession() as session: async with session.get(url, headers={ACCEPT: header_kinds[choice]}) as resp: assert resp.status == 200 content = await resp.read() content_type = resp.headers.get(CONTENT_TYPE) print("Content-Type: {}".format(content_type)) print("size: {}".format(len(content))) if choice == "text": print(content.decode()) else: print(content) # Decode the binary metrics into protobuf objects print(prometheus_metrics_proto.decode(content)) # schedule another fetch loop.call_later(interval, fetch_task, url, fmt, interval, loop)
async def test_counter(self): """ check counter metric export """ # Add some metrics data = ( ({ "data": 1 }, 100), ({ "data": "2" }, 200), ({ "data": 3 }, 300), ({ "data": 1 }, 400), ) c = Counter("test_counter", "Test Counter.", {"test": "test_counter"}) self.server.register(c) for i in data: c.set(i[0], i[1]) expected_data = """# HELP test_counter Test Counter. # TYPE test_counter counter test_counter{data="1",test="test_counter"} 400 test_counter{data="2",test="test_counter"} 200 test_counter{data="3",test="test_counter"} 300 """ async with aiohttp.ClientSession() as session: # Fetch as text async with session.get(self.metrics_url, headers={ACCEPT: text.TEXT_CONTENT_TYPE}) as resp: self.assertEqual(resp.status, 200) content = await resp.read() self.assertEqual(text.TEXT_CONTENT_TYPE, resp.headers.get(CONTENT_TYPE)) self.assertEqual(expected_data, content.decode()) # Fetch as binary async with session.get(self.metrics_url, headers={ ACCEPT: binary.BINARY_CONTENT_TYPE }) as resp: self.assertEqual(resp.status, 200) content = await resp.read() self.assertEqual(binary.BINARY_CONTENT_TYPE, resp.headers.get(CONTENT_TYPE)) metrics = pmp.decode(content) self.assertEqual(len(metrics), 1) mf = metrics[0] self.assertIsInstance(mf, pmp.MetricFamily) self.assertEqual(mf.type, pmp.COUNTER) self.assertEqual(len(mf.metric), 3)
async def test_histogram(self): """ check histogram metric export """ # Add some metrics data = [3, 5.2, 13, 4] label = {"data": 1} h = Histogram( "histogram_test", "Test Histogram.", {"type": "test_histogram"}, buckets=[5.0, 10.0, 15.0], ) self.server.register(h) for i in data: h.add(label, i) expected_data = """# HELP histogram_test Test Histogram. # TYPE histogram_test histogram histogram_test_bucket{data="1",le="5.0",type="test_histogram"} 2.0 histogram_test_bucket{data="1",le="10.0",type="test_histogram"} 3.0 histogram_test_bucket{data="1",le="15.0",type="test_histogram"} 4.0 histogram_test_bucket{data="1",le="+Inf",type="test_histogram"} 4.0 histogram_test_count{data="1",type="test_histogram"} 4.0 histogram_test_sum{data="1",type="test_histogram"} 25.2 """ async with aiohttp.ClientSession() as session: # Fetch as text async with session.get(self.metrics_url, headers={ACCEPT: text.TEXT_CONTENT_TYPE}) as resp: self.assertEqual(resp.status, 200) content = await resp.read() self.assertEqual(text.TEXT_CONTENT_TYPE, resp.headers.get(CONTENT_TYPE)) self.assertEqual(expected_data, content.decode()) # Fetch as binary async with session.get(self.metrics_url, headers={ ACCEPT: binary.BINARY_CONTENT_TYPE }) as resp: self.assertEqual(resp.status, 200) content = await resp.read() self.assertEqual(binary.BINARY_CONTENT_TYPE, resp.headers.get(CONTENT_TYPE)) metrics = pmp.decode(content) self.assertEqual(len(metrics), 1) mf = metrics[0] self.assertIsInstance(mf, pmp.MetricFamily) self.assertEqual(mf.type, pmp.HISTOGRAM) self.assertEqual(len(mf.metric), 1) self.assertEqual(len(mf.metric[0].histogram.bucket), 4)
async def test_histogram(self): """ check histogram metric export """ # Add some metrics data = [3, 5.2, 13, 4] label = {"data": 1} h = Histogram( "histogram_test", "Test Histogram.", {"type": "test_histogram"}, buckets=[5.0, 10.0, 15.0], ) self.server.register(h) for i in data: h.add(label, i) expected_data = """# HELP histogram_test Test Histogram. # TYPE histogram_test histogram histogram_test_bucket{data="1",le="5.0",type="test_histogram"} 2.0 histogram_test_bucket{data="1",le="10.0",type="test_histogram"} 3.0 histogram_test_bucket{data="1",le="15.0",type="test_histogram"} 4.0 histogram_test_bucket{data="1",le="+Inf",type="test_histogram"} 4.0 histogram_test_count{data="1",type="test_histogram"} 4.0 histogram_test_sum{data="1",type="test_histogram"} 25.2 """ async with aiohttp.ClientSession() as session: # Fetch as text async with session.get( self.metrics_url, headers={ACCEPT: TEXT_CONTENT_TYPE} ) as resp: self.assertEqual(resp.status, 200) content = await resp.read() self.assertEqual(TEXT_CONTENT_TYPE, resp.headers.get(CONTENT_TYPE)) self.assertEqual(expected_data, content.decode()) # Fetch as binary async with session.get( self.metrics_url, headers={ACCEPT: BINARY_CONTENT_TYPE} ) as resp: self.assertEqual(resp.status, 200) content = await resp.read() self.assertEqual(BINARY_CONTENT_TYPE, resp.headers.get(CONTENT_TYPE)) metrics = pmp.decode(content) self.assertEqual(len(metrics), 1) mf = metrics[0] self.assertIsInstance(mf, pmp.MetricFamily) self.assertEqual(mf.type, pmp.HISTOGRAM) self.assertEqual(len(mf.metric), 1) self.assertEqual(len(mf.metric[0].histogram.bucket), 4)
async def test_summary(self): """ check summary metric export """ # Add some metrics data = [3, 5.2, 13, 4] label = {"data": 1} s = Summary("test_summary", "Test Summary.", {"test": "test_summary"}) self.server.register(s) for i in data: s.add(label, i) expected_data = """# HELP test_summary Test Summary. # TYPE test_summary summary test_summary{data="1",quantile="0.5",test="test_summary"} 4.0 test_summary{data="1",quantile="0.9",test="test_summary"} 5.2 test_summary{data="1",quantile="0.99",test="test_summary"} 5.2 test_summary_count{data="1",test="test_summary"} 4 test_summary_sum{data="1",test="test_summary"} 25.2 """ async with aiohttp.ClientSession() as session: # Fetch as text async with session.get(self.metrics_url, headers={ACCEPT: text.TEXT_CONTENT_TYPE}) as resp: self.assertEqual(resp.status, 200) content = await resp.read() self.assertEqual(text.TEXT_CONTENT_TYPE, resp.headers.get(CONTENT_TYPE)) self.assertEqual(expected_data, content.decode()) # Fetch as binary async with session.get(self.metrics_url, headers={ ACCEPT: binary.BINARY_CONTENT_TYPE }) as resp: self.assertEqual(resp.status, 200) content = await resp.read() self.assertEqual(binary.BINARY_CONTENT_TYPE, resp.headers.get(CONTENT_TYPE)) metrics = pmp.decode(content) self.assertEqual(len(metrics), 1) mf = metrics[0] self.assertIsInstance(mf, pmp.MetricFamily) self.assertEqual(mf.type, pmp.SUMMARY) self.assertEqual(len(mf.metric), 1) self.assertEqual(len(mf.metric[0].summary.quantile), 3)
async def test_summary(self): """ check summary metric export """ # Add some metrics data = [3, 5.2, 13, 4] label = {"data": 1} s = Summary("test_summary", "Test Summary.", {"test": "test_summary"}) self.server.register(s) for i in data: s.add(label, i) expected_data = """# HELP test_summary Test Summary. # TYPE test_summary summary test_summary{data="1",quantile="0.5",test="test_summary"} 4.0 test_summary{data="1",quantile="0.9",test="test_summary"} 5.2 test_summary{data="1",quantile="0.99",test="test_summary"} 5.2 test_summary_count{data="1",test="test_summary"} 4 test_summary_sum{data="1",test="test_summary"} 25.2 """ async with aiohttp.ClientSession() as session: # Fetch as text async with session.get( self.metrics_url, headers={ACCEPT: TEXT_CONTENT_TYPE} ) as resp: self.assertEqual(resp.status, 200) content = await resp.read() self.assertEqual(TEXT_CONTENT_TYPE, resp.headers.get(CONTENT_TYPE)) self.assertEqual(expected_data, content.decode()) # Fetch as binary async with session.get( self.metrics_url, headers={ACCEPT: BINARY_CONTENT_TYPE} ) as resp: self.assertEqual(resp.status, 200) content = await resp.read() self.assertEqual(BINARY_CONTENT_TYPE, resp.headers.get(CONTENT_TYPE)) metrics = pmp.decode(content) self.assertEqual(len(metrics), 1) mf = metrics[0] self.assertIsInstance(mf, pmp.MetricFamily) self.assertEqual(mf.type, pmp.SUMMARY) self.assertEqual(len(mf.metric), 1) self.assertEqual(len(mf.metric[0].summary.quantile), 3)
async def test_gauge(self): """ check gauge metric export """ # Add some metrics data = ( ({"data": 1}, 100), ({"data": "2"}, 200), ({"data": 3}, 300), ({"data": 1}, 400), ) g = Gauge("test_gauge", "Test Gauge.", {"test": "test_gauge"}) self.server.register(g) for i in data: g.set(i[0], i[1]) expected_data = """# HELP test_gauge Test Gauge. # TYPE test_gauge gauge test_gauge{data="1",test="test_gauge"} 400 test_gauge{data="2",test="test_gauge"} 200 test_gauge{data="3",test="test_gauge"} 300 """ async with aiohttp.ClientSession() as session: # Fetch as text async with session.get( self.metrics_url, headers={ACCEPT: TEXT_CONTENT_TYPE} ) as resp: self.assertEqual(resp.status, 200) content = await resp.read() self.assertEqual(TEXT_CONTENT_TYPE, resp.headers.get(CONTENT_TYPE)) self.assertEqual(expected_data, content.decode()) # Fetch as binary async with session.get( self.metrics_url, headers={ACCEPT: BINARY_CONTENT_TYPE} ) as resp: self.assertEqual(resp.status, 200) content = await resp.read() self.assertEqual(BINARY_CONTENT_TYPE, resp.headers.get(CONTENT_TYPE)) metrics = pmp.decode(content) self.assertEqual(len(metrics), 1) mf = metrics[0] self.assertIsInstance(mf, pmp.MetricFamily) self.assertEqual(mf.type, pmp.GAUGE) self.assertEqual(len(mf.metric), 3)
def test_encode_histogram(self): """ check encode of histogram matches expected output """ valid_result = (b"\x97\x01\n\x0ehistogram_test\x12\x0cA histogram." b'\x18\x04"u\n\r\n\x08h_sample\x12\x011\n\x10\n' b"\x0bh_subsample\x12\x01b\n\x11\n\x04type\x12\t" b"histogram:?\x08\x06\x11\x00\x00\x00\x00\x00\x00G@" b"\x1a\x0b\x08\x03\x11\x00\x00\x00\x00\x00\x00\x14@" b"\x1a\x0b\x08\x02\x11\x00\x00\x00\x00\x00\x00$@\x1a" b"\x0b\x08\x01\x11\x00\x00\x00\x00\x00\x00.@\x1a\x0b" b"\x08\x00\x11\x00\x00\x00\x00\x00\x00\xf0\x7f") metric_name = "histogram_test" metric_help = "A histogram." metric_type = pmp.HISTOGRAM # buckets typically have a POS_INF upper bound to catch values # beyond the largest bucket bound. Simulate this behavior. POS_INF = float("inf") metric_data = (( { "h_sample": "1", "h_subsample": "b" }, { 5.0: 3, 10.0: 2, 15.0: 1, POS_INF: 0, "count": 6, "sum": 46.0 }, ), ) mf = pmp.utils.create_metric_family( metric_name, metric_help, metric_type, metric_data, const_labels={"type": "histogram"}, ) payload = pmp.encode(mf) self.assertIsInstance(payload, bytes) self.assertEqual(valid_result, payload) # Check Histogram can be round-tripped through encode and decode _mf = pmp.decode(payload)[0] self.assertEqual(mf, _mf)
def test_encode_summary(self): """ check encode of summary matches expected output """ valid_result = (b"\x99\x01\n\x0csummary_test\x12\nA summary." b'\x18\x02"{\n\r\n\x08s_sample\x12\x011\n\x10\n' b"\x0bs_subsample\x12\x01b\n\x0f\n\x04type\x12\x07" b'summary"G\x08\x16\x11\x00\x00\x00\x00\x90"\xf8@' b"\x1a\x12\t\x00\x00\x00\x00\x00\x00\xe0?\x11\x00" b"\x00\x00\x00\x00\x8b\xb0@\x1a\x12\t\xcd\xcc\xcc" b"\xcc\xcc\xcc\xec?\x11\x00\x00\x00\x00\x00v\xb1@" b"\x1a\x12\t\xaeG\xe1z\x14\xae\xef?\x11\x00\x00\x00" b"\x00\x00\xa5\xb1@") metric_name = "summary_test" metric_help = "A summary." metric_type = pmp.SUMMARY metric_data = (( { "s_sample": "1", "s_subsample": "b" }, { 0.5: 4235.0, 0.9: 4470.0, 0.99: 4517.0, "count": 22, "sum": 98857.0 }, ), ) mf = pmp.utils.create_metric_family( metric_name, metric_help, metric_type, metric_data, const_labels={"type": "summary"}, ) payload = pmp.encode(mf) self.assertIsInstance(payload, bytes) self.assertEqual(valid_result, payload) # Check Summary can be round-tripped through encode and decode _mf = pmp.decode(payload)[0] self.assertEqual(mf, _mf)
def test_encode_gauge(self): ''' check encode of gauge matches expected output ''' valid_result = (b'U\n\ngauge_test\x12\x08A gauge.\x18\x01";' b'\n\r\n\x08g_sample\x12\x011\n\x10\n\x0bg_subsample' b'\x12\x01b\n\r\n\x04type\x12\x05gauge\x12\t\t\x00' b'\x00\x00\x00\x00\x00\x89@') metric_name = "gauge_test" metric_help = "A gauge." metric_type = pmp.GAUGE metric_data = (({'g_sample': '1', 'g_subsample': 'b'}, 800), ) mf = pmp.utils.create_metric_family(metric_name, metric_help, metric_type, metric_data, const_labels={'type': "gauge"}) payload = pmp.encode(mf) self.assertIsInstance(payload, bytes) self.assertEqual(valid_result, payload) # Check Gauge can be round-tripped through encode and decode _mf = pmp.decode(payload)[0] self.assertEqual(mf, _mf)
def test_encode_counter(self): ''' check encode of counter matches expected output ''' valid_result = (b'[\n\x0ccounter_test\x12\nA counter.\x18\x00"=\n\r' b'\n\x08c_sample\x12\x011\n\x10\n\x0bc_subsample\x12' b'\x01b\n\x0f\n\x04type\x12\x07counter\x1a\t\t\x00\x00' b'\x00\x00\x00\x00y@') metric_name = "counter_test" metric_help = "A counter." metric_type = pmp.COUNTER metric_data = (({'c_sample': '1', 'c_subsample': 'b'}, 400), ) mf = pmp.utils.create_metric_family(metric_name, metric_help, metric_type, metric_data, const_labels={'type': "counter"}) payload = pmp.encode(mf) self.assertIsInstance(payload, bytes) self.assertEqual(valid_result, payload) # Check Counter can be round-tripped through encode and decode _mf = pmp.decode(payload)[0] self.assertEqual(mf, _mf)
def test_histogram(self): ''' check creating histogram using utils functions ''' # Create a metrics with no metric instances mf = pmp.utils.create_metric_family(self.histogram_metric_name, self.histogram_metric_help, self.histogram_metric_type, []) self.assertIsInstance(mf, pmp.MetricFamily) self.assertEqual(len(mf.metric), 0) # Create it with metrics mf = pmp.utils.create_metric_family(self.histogram_metric_name, self.histogram_metric_help, self.histogram_metric_type, self.histogram_metric_data) self.assertIsInstance(mf, pmp.MetricFamily) self.assertEqual(mf.name, self.histogram_metric_name) self.assertEqual(mf.help, self.histogram_metric_help) self.assertEqual(mf.type, self.histogram_metric_type) # Create another and check equal mf_ = pmp.utils.create_metric_family(self.histogram_metric_name, self.histogram_metric_help, self.histogram_metric_type, self.histogram_metric_data) self.assertIsInstance(mf_, pmp.MetricFamily) self.assertEqual(mf, mf_) for m in mf_.metric: self.assertEqual(m.timestamp_ms, 0) # Create another with timestamp mf_ = pmp.create_histogram(self.histogram_metric_name, self.histogram_metric_help, self.histogram_metric_data, timestamp=True) self.assertIsInstance(mf_, pmp.MetricFamily) for m in mf_.metric: self.assertNotEqual(m.timestamp_ms, 0) self.assertNotEqual(mf, mf_) # Create Histogram with const_labels mf_ = pmp.utils.create_metric_family(self.histogram_metric_name, self.histogram_metric_help, self.histogram_metric_type, self.histogram_metric_data, const_labels=self.const_labels) self.assertIsInstance(mf_, pmp.MetricFamily) # Check that const_label is present in the LabelPair associated # with each metric instance. for m in mf_.metric: labels = [lp.name for lp in m.label] self.assertIn('app', labels) self.assertNotEqual(mf, mf_) # Check Histogram can be round-tripped through encode and decode payload = pmp.encode(mf) self.assertIsInstance(payload, bytes) _mf = pmp.decode(payload)[0] self.assertEqual(mf, _mf)
def main(): # Define some labels that we want added to all metrics. These labels are # independent of the instance labels that define a metric as unique. # These could be used to add hostname, app name, etc. const_labels = {'host': 'examplehost', 'app': 'my_app'} # Create a Counter metric to track logged in users. This counter has # 5 separate instances. # We'll make use of the optional const_labels argument to add extra # constant labels. # We will also add a timestamp to the metric instances. # We will request that the labels be sorted. cm = pmp.create_counter('logged_users_total', 'Logged users in the application.', ( ({ 'country': "sp", "device": "desktop" }, 520), ({ 'country': "us", "device": "mobile" }, 654), ({ 'country': "uk", "device": "desktop" }, 1001), ({ 'country': "de", "device": "desktop" }, 995), ({ 'country': "zh", "device": "desktop" }, 520), ), timestamp=True, const_labels=const_labels, ordered=True) # Create a Gauge metric, similar to the counter above. gm = pmp.create_gauge('logged_users_total', 'Logged users in the application.', ( ({ 'country': "sp", "device": "desktop" }, 520), ({ 'country': "us", "device": "mobile" }, 654), ({ 'country': "uk", "device": "desktop" }, 1001), ({ 'country': "de", "device": "desktop" }, 995), ({ 'country': "zh", "device": "desktop" }, 520), ), timestamp=True, const_labels=const_labels, ordered=True) # Now lets create a Summary and Histogram metric object. These forms # of metrics are slightly more complicated. # # Remember, the collection of metrics and the management of Summary # Quantiles and Histogram Buckets are outside the scope of # functionality provided by this package. # # The following examples assume they are taking the data values from # a management library that can also emit the sum and count fields # expected for both Summary and Histogram metrics. # Create a Summary metric. The values for a summary are slightly # different to a Counter or Gauge. They are composed of a dict representing # the various quantile values of the metric. The count and sum are # expected to be present in this dict. sm = pmp.create_summary('request_payload_size_bytes', 'Request payload size in bytes.', ( ({ 'route': '/' }, { 0.5: 4.0, 0.9: 5.2, 0.99: 5.2, 'sum': 25.2, 'count': 4 }), ({ 'route': '/data' }, { 0.5: 4.0, 0.9: 5.2, 0.99: 5.2, 'sum': 25.2, 'count': 4 }), ), timestamp=True, const_labels=const_labels, ordered=True) # Create a Histogram metric. The values for a histogram are slightly # different to a Counter or Gauge. They are composed of a dict representing # the various bucket values of the metric. The cumulative count and sum # values are expected to be present in this dict. # # Libraries manageing buckets typically have add a POS_INF upper bound to # catch values beyond the largest bucket bound. Simulate this behavior in # the data below. POS_INF = float("inf") hm = pmp.create_histogram('request_latency_seconds', 'Request latency in seconds.', ( ({ 'route': '/' }, { 5.0: 3, 10.0: 2, 15.0: 1, POS_INF: 0, 'count': 6, 'sum': 46.0 }), ({ 'route': '/data' }, { 5.0: 3, 10.0: 2, 15.0: 1, POS_INF: 0, 'count': 6, 'sum': 46.0 }), ), timestamp=True, const_labels=const_labels, ordered=True) # Serialize a sequence of metrics into a payload suitable for network # transmission. input_metrics = (cm, gm, sm, hm) payload = pmp.encode(*input_metrics) assert isinstance(payload, bytes) # De-serialize the payload into a sequence of MetricsFamily objects. recovered_metrics = pmp.decode(payload) # Confirm that the round trip re-produced the same number of metrics # and that the metrics are identical. assert len(recovered_metrics) == len(input_metrics) for recovered_metric, input_metric in zip(recovered_metrics, input_metrics): assert recovered_metric == input_metric for metric in input_metrics: print(metric)
def test_encode_decode(self): ''' check encode and decode functions ''' # check passing no metrics raises an exception input_metrics = None with self.assertRaises(Exception) as ctx: payload = pmp.encode(input_metrics) self.assertIn('Expected metrics to be instances of MetricFamily, got ', str(ctx.exception)) cm = pmp.create_counter(self.counter_metric_name, self.counter_metric_help, self.counter_metric_data) self.assertIsInstance(cm, pmp.MetricFamily) gm = pmp.create_gauge(self.gauge_metric_name, self.gauge_metric_help, self.gauge_metric_data) self.assertIsInstance(gm, pmp.MetricFamily) sm = pmp.create_summary(self.summary_metric_name, self.summary_metric_help, self.summary_metric_data) self.assertIsInstance(sm, pmp.MetricFamily) hm = pmp.create_histogram(self.histogram_metric_name, self.histogram_metric_help, self.histogram_metric_data) self.assertIsInstance(hm, pmp.MetricFamily) # check encode can take a single valid metric input_metrics = [cm] payload = pmp.encode(input_metrics[0]) self.assertIsInstance(payload, bytes) # check round-trip metrics = pmp.decode(payload) self.assertIsInstance(metrics, list) self.assertEqual(len(metrics), len(input_metrics)) for m_in, m_out in zip(input_metrics, metrics): self.assertEqual(m_in, m_out) # check passing invalid type raises an exception input_metrics = ['a'] with self.assertRaises(Exception) as ctx: payload = pmp.encode(*input_metrics) self.assertIn('Expected metrics to be instances of MetricFamily, got ', str(ctx.exception)) # check parser can take multiple valid metrics input_metrics = (cm, gm, sm, hm) payload = pmp.encode(*input_metrics) self.assertIsInstance(payload, bytes) # check round-trip metrics = pmp.decode(payload) self.assertIsInstance(metrics, list) self.assertEqual(len(metrics), len(input_metrics)) for m_in, m_out in zip(input_metrics, metrics): self.assertEqual(m_in, m_out) # check decoding empty bytes returns empty list metrics = pmp.decode(b'') self.assertIsInstance(metrics, list) self.assertEqual(len(metrics), 0)
async def test_all(self): counter_data = ( ({"c_sample": "1"}, 100), ({"c_sample": "2"}, 200), ({"c_sample": "3"}, 300), ({"c_sample": "1", "c_subsample": "b"}, 400), ) gauge_data = ( ({"g_sample": "1"}, 500), ({"g_sample": "2"}, 600), ({"g_sample": "3"}, 700), ({"g_sample": "1", "g_subsample": "b"}, 800), ) summary_data = ( ({"s_sample": "1"}, range(1000, 2000, 4)), ({"s_sample": "2"}, range(2000, 3000, 20)), ({"s_sample": "3"}, range(3000, 4000, 13)), ({"s_sample": "1", "s_subsample": "b"}, range(4000, 5000, 47)), ) histogram_data = ( ({"h_sample": "1"}, [3, 14]), ({"h_sample": "2"}, range(1, 20, 2)), ({"h_sample": "3"}, range(1, 20, 2)), ({"h_sample": "1", "h_subsample": "b"}, range(1, 20, 2)), ) counter = Counter("counter_test", "A counter.", {"type": "counter"}) gauge = Gauge("gauge_test", "A gauge.", {"type": "gauge"}) summary = Summary("summary_test", "A summary.", {"type": "summary"}) histogram = Histogram( "histogram_test", "A histogram.", {"type": "histogram"}, buckets=[5.0, 10.0, 15.0], ) self.server.register(counter) self.server.register(gauge) self.server.register(summary) self.server.register(histogram) # Add data [counter.set(c[0], c[1]) for c in counter_data] [gauge.set(g[0], g[1]) for g in gauge_data] [summary.add(i[0], s) for i in summary_data for s in i[1]] [histogram.observe(i[0], h) for i in histogram_data for h in i[1]] expected_data = """# HELP counter_test A counter. # TYPE counter_test counter counter_test{c_sample="1",type="counter"} 100 counter_test{c_sample="2",type="counter"} 200 counter_test{c_sample="3",type="counter"} 300 counter_test{c_sample="1",c_subsample="b",type="counter"} 400 # HELP gauge_test A gauge. # TYPE gauge_test gauge gauge_test{g_sample="1",type="gauge"} 500 gauge_test{g_sample="2",type="gauge"} 600 gauge_test{g_sample="3",type="gauge"} 700 gauge_test{g_sample="1",g_subsample="b",type="gauge"} 800 # HELP histogram_test A histogram. # TYPE histogram_test histogram histogram_test_bucket{h_sample="1",le="5.0",type="histogram"} 1.0 histogram_test_bucket{h_sample="1",le="10.0",type="histogram"} 1.0 histogram_test_bucket{h_sample="1",le="15.0",type="histogram"} 2.0 histogram_test_bucket{h_sample="1",le="+Inf",type="histogram"} 2.0 histogram_test_count{h_sample="1",type="histogram"} 2.0 histogram_test_sum{h_sample="1",type="histogram"} 17.0 histogram_test_bucket{h_sample="2",le="5.0",type="histogram"} 3.0 histogram_test_bucket{h_sample="2",le="10.0",type="histogram"} 5.0 histogram_test_bucket{h_sample="2",le="15.0",type="histogram"} 8.0 histogram_test_bucket{h_sample="2",le="+Inf",type="histogram"} 10.0 histogram_test_count{h_sample="2",type="histogram"} 10.0 histogram_test_sum{h_sample="2",type="histogram"} 100.0 histogram_test_bucket{h_sample="3",le="5.0",type="histogram"} 3.0 histogram_test_bucket{h_sample="3",le="10.0",type="histogram"} 5.0 histogram_test_bucket{h_sample="3",le="15.0",type="histogram"} 8.0 histogram_test_bucket{h_sample="3",le="+Inf",type="histogram"} 10.0 histogram_test_count{h_sample="3",type="histogram"} 10.0 histogram_test_sum{h_sample="3",type="histogram"} 100.0 histogram_test_bucket{h_sample="1",h_subsample="b",le="5.0",type="histogram"} 3.0 histogram_test_bucket{h_sample="1",h_subsample="b",le="10.0",type="histogram"} 5.0 histogram_test_bucket{h_sample="1",h_subsample="b",le="15.0",type="histogram"} 8.0 histogram_test_bucket{h_sample="1",h_subsample="b",le="+Inf",type="histogram"} 10.0 histogram_test_count{h_sample="1",h_subsample="b",type="histogram"} 10.0 histogram_test_sum{h_sample="1",h_subsample="b",type="histogram"} 100.0 # HELP summary_test A summary. # TYPE summary_test summary summary_test{quantile="0.5",s_sample="1",type="summary"} 1272.0 summary_test{quantile="0.9",s_sample="1",type="summary"} 1452.0 summary_test{quantile="0.99",s_sample="1",type="summary"} 1496.0 summary_test_count{s_sample="1",type="summary"} 250 summary_test_sum{s_sample="1",type="summary"} 374500.0 summary_test{quantile="0.5",s_sample="2",type="summary"} 2260.0 summary_test{quantile="0.9",s_sample="2",type="summary"} 2440.0 summary_test{quantile="0.99",s_sample="2",type="summary"} 2500.0 summary_test_count{s_sample="2",type="summary"} 50 summary_test_sum{s_sample="2",type="summary"} 124500.0 summary_test{quantile="0.5",s_sample="3",type="summary"} 3260.0 summary_test{quantile="0.9",s_sample="3",type="summary"} 3442.0 summary_test{quantile="0.99",s_sample="3",type="summary"} 3494.0 summary_test_count{s_sample="3",type="summary"} 77 summary_test_sum{s_sample="3",type="summary"} 269038.0 summary_test{quantile="0.5",s_sample="1",s_subsample="b",type="summary"} 4235.0 summary_test{quantile="0.9",s_sample="1",s_subsample="b",type="summary"} 4470.0 summary_test{quantile="0.99",s_sample="1",s_subsample="b",type="summary"} 4517.0 summary_test_count{s_sample="1",s_subsample="b",type="summary"} 22 summary_test_sum{s_sample="1",s_subsample="b",type="summary"} 98857.0 """ async with aiohttp.ClientSession() as session: # Fetch as text async with session.get( self.metrics_url, headers={ACCEPT: TEXT_CONTENT_TYPE} ) as resp: self.assertEqual(resp.status, 200) content = await resp.read() self.assertEqual(TEXT_CONTENT_TYPE, resp.headers.get(CONTENT_TYPE)) self.assertEqual(expected_data, content.decode()) # Fetch as binary async with session.get( self.metrics_url, headers={ACCEPT: BINARY_CONTENT_TYPE} ) as resp: self.assertEqual(resp.status, 200) content = await resp.read() self.assertEqual(BINARY_CONTENT_TYPE, resp.headers.get(CONTENT_TYPE)) metrics = pmp.decode(content) self.assertEqual(len(metrics), 4) for mf in metrics: self.assertIsInstance(mf, pmp.MetricFamily) if mf.type == pmp.COUNTER: self.assertEqual(len(mf.metric), 4) elif mf.type == pmp.GAUGE: self.assertEqual(len(mf.metric), 4) elif mf.type == pmp.SUMMARY: self.assertEqual(len(mf.metric), 4) self.assertEqual(len(mf.metric[0].summary.quantile), 3) elif mf.type == pmp.HISTOGRAM: self.assertEqual(len(mf.metric), 4) self.assertEqual(len(mf.metric[0].histogram.bucket), 4)
async def test_all(self): counter_data = ( ({ "c_sample": "1" }, 100), ({ "c_sample": "2" }, 200), ({ "c_sample": "3" }, 300), ({ "c_sample": "1", "c_subsample": "b" }, 400), ) gauge_data = ( ({ "g_sample": "1" }, 500), ({ "g_sample": "2" }, 600), ({ "g_sample": "3" }, 700), ({ "g_sample": "1", "g_subsample": "b" }, 800), ) summary_data = ( ({ "s_sample": "1" }, range(1000, 2000, 4)), ({ "s_sample": "2" }, range(2000, 3000, 20)), ({ "s_sample": "3" }, range(3000, 4000, 13)), ({ "s_sample": "1", "s_subsample": "b" }, range(4000, 5000, 47)), ) histogram_data = ( ({ "h_sample": "1" }, [3, 14]), ({ "h_sample": "2" }, range(1, 20, 2)), ({ "h_sample": "3" }, range(1, 20, 2)), ({ "h_sample": "1", "h_subsample": "b" }, range(1, 20, 2)), ) counter = Counter("counter_test", "A counter.", {"type": "counter"}) gauge = Gauge("gauge_test", "A gauge.", {"type": "gauge"}) summary = Summary("summary_test", "A summary.", {"type": "summary"}) histogram = Histogram( "histogram_test", "A histogram.", {"type": "histogram"}, buckets=[5.0, 10.0, 15.0], ) self.server.register(counter) self.server.register(gauge) self.server.register(summary) self.server.register(histogram) # Add data [counter.set(c[0], c[1]) for c in counter_data] [gauge.set(g[0], g[1]) for g in gauge_data] [summary.add(i[0], s) for i in summary_data for s in i[1]] [histogram.observe(i[0], h) for i in histogram_data for h in i[1]] expected_data = """# HELP counter_test A counter. # TYPE counter_test counter counter_test{c_sample="1",type="counter"} 100 counter_test{c_sample="2",type="counter"} 200 counter_test{c_sample="3",type="counter"} 300 counter_test{c_sample="1",c_subsample="b",type="counter"} 400 # HELP gauge_test A gauge. # TYPE gauge_test gauge gauge_test{g_sample="1",type="gauge"} 500 gauge_test{g_sample="2",type="gauge"} 600 gauge_test{g_sample="3",type="gauge"} 700 gauge_test{g_sample="1",g_subsample="b",type="gauge"} 800 # HELP histogram_test A histogram. # TYPE histogram_test histogram histogram_test_bucket{h_sample="1",le="5.0",type="histogram"} 1.0 histogram_test_bucket{h_sample="1",le="10.0",type="histogram"} 1.0 histogram_test_bucket{h_sample="1",le="15.0",type="histogram"} 2.0 histogram_test_bucket{h_sample="1",le="+Inf",type="histogram"} 2.0 histogram_test_count{h_sample="1",type="histogram"} 2.0 histogram_test_sum{h_sample="1",type="histogram"} 17.0 histogram_test_bucket{h_sample="2",le="5.0",type="histogram"} 3.0 histogram_test_bucket{h_sample="2",le="10.0",type="histogram"} 5.0 histogram_test_bucket{h_sample="2",le="15.0",type="histogram"} 8.0 histogram_test_bucket{h_sample="2",le="+Inf",type="histogram"} 10.0 histogram_test_count{h_sample="2",type="histogram"} 10.0 histogram_test_sum{h_sample="2",type="histogram"} 100.0 histogram_test_bucket{h_sample="3",le="5.0",type="histogram"} 3.0 histogram_test_bucket{h_sample="3",le="10.0",type="histogram"} 5.0 histogram_test_bucket{h_sample="3",le="15.0",type="histogram"} 8.0 histogram_test_bucket{h_sample="3",le="+Inf",type="histogram"} 10.0 histogram_test_count{h_sample="3",type="histogram"} 10.0 histogram_test_sum{h_sample="3",type="histogram"} 100.0 histogram_test_bucket{h_sample="1",h_subsample="b",le="5.0",type="histogram"} 3.0 histogram_test_bucket{h_sample="1",h_subsample="b",le="10.0",type="histogram"} 5.0 histogram_test_bucket{h_sample="1",h_subsample="b",le="15.0",type="histogram"} 8.0 histogram_test_bucket{h_sample="1",h_subsample="b",le="+Inf",type="histogram"} 10.0 histogram_test_count{h_sample="1",h_subsample="b",type="histogram"} 10.0 histogram_test_sum{h_sample="1",h_subsample="b",type="histogram"} 100.0 # HELP summary_test A summary. # TYPE summary_test summary summary_test{quantile="0.5",s_sample="1",type="summary"} 1272.0 summary_test{quantile="0.9",s_sample="1",type="summary"} 1452.0 summary_test{quantile="0.99",s_sample="1",type="summary"} 1496.0 summary_test_count{s_sample="1",type="summary"} 250 summary_test_sum{s_sample="1",type="summary"} 374500.0 summary_test{quantile="0.5",s_sample="2",type="summary"} 2260.0 summary_test{quantile="0.9",s_sample="2",type="summary"} 2440.0 summary_test{quantile="0.99",s_sample="2",type="summary"} 2500.0 summary_test_count{s_sample="2",type="summary"} 50 summary_test_sum{s_sample="2",type="summary"} 124500.0 summary_test{quantile="0.5",s_sample="3",type="summary"} 3260.0 summary_test{quantile="0.9",s_sample="3",type="summary"} 3442.0 summary_test{quantile="0.99",s_sample="3",type="summary"} 3494.0 summary_test_count{s_sample="3",type="summary"} 77 summary_test_sum{s_sample="3",type="summary"} 269038.0 summary_test{quantile="0.5",s_sample="1",s_subsample="b",type="summary"} 4235.0 summary_test{quantile="0.9",s_sample="1",s_subsample="b",type="summary"} 4470.0 summary_test{quantile="0.99",s_sample="1",s_subsample="b",type="summary"} 4517.0 summary_test_count{s_sample="1",s_subsample="b",type="summary"} 22 summary_test_sum{s_sample="1",s_subsample="b",type="summary"} 98857.0 """ async with aiohttp.ClientSession() as session: # Fetch as text async with session.get(self.metrics_url, headers={ACCEPT: text.TEXT_CONTENT_TYPE}) as resp: self.assertEqual(resp.status, 200) content = await resp.read() self.assertEqual(text.TEXT_CONTENT_TYPE, resp.headers.get(CONTENT_TYPE)) self.assertEqual(expected_data, content.decode()) # Fetch as binary async with session.get(self.metrics_url, headers={ ACCEPT: binary.BINARY_CONTENT_TYPE }) as resp: self.assertEqual(resp.status, 200) content = await resp.read() self.assertEqual(binary.BINARY_CONTENT_TYPE, resp.headers.get(CONTENT_TYPE)) metrics = pmp.decode(content) self.assertEqual(len(metrics), 4) for mf in metrics: self.assertIsInstance(mf, pmp.MetricFamily) if mf.type == pmp.COUNTER: self.assertEqual(len(mf.metric), 4) elif mf.type == pmp.GAUGE: self.assertEqual(len(mf.metric), 4) elif mf.type == pmp.SUMMARY: self.assertEqual(len(mf.metric), 4) self.assertEqual(len(mf.metric[0].summary.quantile), 3) elif mf.type == pmp.HISTOGRAM: self.assertEqual(len(mf.metric), 4) self.assertEqual(len(mf.metric[0].histogram.bucket), 4)