def test_create_histogram(self): ''' check creating histogram using api functions ''' # Create a metrics with no metric instances mf = pmp.create_histogram(self.histogram_metric_name, self.histogram_metric_help, []) self.assertIsInstance(mf, pmp.MetricFamily) self.assertEqual(len(mf.metric), 0) # Create it with metrics mf = pmp.create_histogram(self.histogram_metric_name, self.histogram_metric_help, 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) mf_ = pmp.create_histogram(self.histogram_metric_name, self.histogram_metric_help, 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.create_histogram(self.histogram_metric_name, self.histogram_metric_help, 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_)
def test_histogram_format_binary(self): h = Histogram( name=self.histogram_metric_name, doc=self.histogram_metric_help, buckets=self.histogram_metric_buckets, ) # Add data to the collector for labels, values in self.histogram_metric_data_values: for value in values: h.add(labels, value) f = binary.BinaryFormatter() result = f.marshall_collector(h) self.assertIsInstance(result, pmp.MetricFamily) self.assertEqual(len(result.metric), 1) # Construct the result to expected to receive when the histogram # collector is marshalled. expected_result = pmp.create_histogram( self.histogram_metric_name, self.histogram_metric_help, self.histogram_metric_data, ) self.assertEqual(result, expected_result) ###################################################################### # Check metric with constant labels h = Histogram( name=self.histogram_metric_name, doc=self.histogram_metric_help, const_labels=self.const_labels, buckets=self.histogram_metric_buckets, ) # Add data to the collector for labels, values in self.histogram_metric_data_values: for value in values: h.add(labels, value) f = binary.BinaryFormatter() result = f.marshall_collector(h) self.assertIsInstance(result, pmp.MetricFamily) self.assertEqual(len(result.metric), 1) # Construct the result to expected to receive when the histogram # collector is marshalled. expected_result = pmp.create_histogram( self.histogram_metric_name, self.histogram_metric_help, self.histogram_metric_data, const_labels=self.const_labels, ) self.assertEqual(result, expected_result) ###################################################################### # Check metric with timestamps with unittest.mock.patch.object(pmp.utils, "_timestamp_ms", return_value=TEST_TIMESTAMP): h = Histogram( name=self.histogram_metric_name, doc=self.histogram_metric_help, buckets=self.histogram_metric_buckets, ) # Add data to the collector for labels, values in self.histogram_metric_data_values: for value in values: h.add(labels, value) f = binary.BinaryFormatter(timestamp=True) result = f.marshall_collector(h) self.assertIsInstance(result, pmp.MetricFamily) self.assertEqual(len(result.metric), 1) # Construct the result to expected to receive when the histogram # collector is marshalled. expected_result = pmp.create_histogram( self.histogram_metric_name, self.histogram_metric_help, self.histogram_metric_data, timestamp=True, ) self.assertEqual(result, expected_result)
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)