OLD | NEW |
---|---|
1 # Copyright 2015 The Chromium Authors. All rights reserved. | 1 # Copyright 2015 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """Classes representing individual metrics that can be sent.""" | 5 """Classes representing individual metrics that can be sent.""" |
6 | 6 |
7 import copy | 7 import copy |
8 | 8 |
9 from infra_libs.ts_mon.protos import metrics_pb2 | 9 from infra_libs.ts_mon.protos import metrics_pb2 |
10 | 10 |
(...skipping 13 matching lines...) Expand all Loading... | |
24 process may keep track of many metrics. | 24 process may keep track of many metrics. |
25 | 25 |
26 Note that Metric objects may be initialized at any time (for example, at the | 26 Note that Metric objects may be initialized at any time (for example, at the |
27 top of a library), but cannot be sent until the underlying Monitor object | 27 top of a library), but cannot be sent until the underlying Monitor object |
28 has been set up (usually by the top-level process parsing the command line). | 28 has been set up (usually by the top-level process parsing the command line). |
29 | 29 |
30 A Metric can actually store multiple values that are identified by a set of | 30 A Metric can actually store multiple values that are identified by a set of |
31 fields (which are themselves key-value pairs). Fields can be passed to the | 31 fields (which are themselves key-value pairs). Fields can be passed to the |
32 set() or increment() methods to modify a particular value, or passed to the | 32 set() or increment() methods to modify a particular value, or passed to the |
33 constructor in which case they will be used as the defaults for this Metric. | 33 constructor in which case they will be used as the defaults for this Metric. |
34 | 34 |
agable
2016/06/29 18:25:23
Please update this docstring to reference units as
ddoman
2016/07/06 03:35:37
Done.
| |
35 Do not directly instantiate an object of this class. | 35 Do not directly instantiate an object of this class. |
36 Use the concrete child classes instead: | 36 Use the concrete child classes instead: |
37 * StringMetric for metrics with string value | 37 * StringMetric for metrics with string value |
38 * BooleanMetric for metrics with boolean values | 38 * BooleanMetric for metrics with boolean values |
39 * CounterMetric for metrics with monotonically increasing integer values | 39 * CounterMetric for metrics with monotonically increasing integer values |
40 * GaugeMetric for metrics with arbitrarily varying integer values | 40 * GaugeMetric for metrics with arbitrarily varying integer values |
41 * CumulativeMetric for metrics with monotonically increasing float values | 41 * CumulativeMetric for metrics with monotonically increasing float values |
42 * FloatMetric for metrics with arbitrarily varying float values | 42 * FloatMetric for metrics with arbitrarily varying float values |
43 | 43 |
44 See http://go/inframon-doc for help designing and using your metrics. | 44 See http://go/inframon-doc for help designing and using your metrics. |
45 """ | 45 """ |
46 | 46 |
47 def __init__(self, name, fields=None, description=None): | 47 def __init__(self, name, fields=None, description=None, units=None): |
48 """Create an instance of a Metric. | 48 """Create an instance of a Metric. |
49 | 49 |
50 Args: | 50 Args: |
51 name (str): the file-like name of this metric | 51 name (str): the file-like name of this metric |
52 fields (dict): a set of key-value pairs to be set as default metric fields | 52 fields (dict): a set of key-value pairs to be set as default metric fields |
53 description (string): help string for the metric. Should be enough to | 53 description (string): help string for the metric. Should be enough to |
54 know what the metric is about. | 54 know what the metric is about. |
55 units (int): the unit used to measure data for given | |
56 metric. Please use the attributes of MetricDataUnit to find | |
57 valid integer values for this argument. | |
55 """ | 58 """ |
56 self._name = name.lstrip('/') | 59 self._name = name.lstrip('/') |
57 self._start_time = None | 60 self._start_time = None |
58 fields = fields or {} | 61 fields = fields or {} |
59 if len(fields) > 7: | 62 if len(fields) > 7: |
60 raise errors.MonitoringTooManyFieldsError(self._name, fields) | 63 raise errors.MonitoringTooManyFieldsError(self._name, fields) |
61 self._fields = fields | 64 self._fields = fields |
62 self._normalized_fields = self._normalize_fields(self._fields) | 65 self._normalized_fields = self._normalize_fields(self._fields) |
63 self._description = description | 66 self._description = description |
67 self._units = units | |
64 | 68 |
65 interface.register(self) | 69 interface.register(self) |
66 | 70 |
67 @property | 71 @property |
68 def name(self): | 72 def name(self): |
69 return self._name | 73 return self._name |
70 | 74 |
71 @property | 75 @property |
72 def start_time(self): | 76 def start_time(self): |
73 return self._start_time | 77 return self._start_time |
(...skipping 17 matching lines...) Expand all Loading... | |
91 to add the current metric values. | 95 to add the current metric values. |
92 start_time (int): timestamp in microseconds since UNIX epoch. | 96 start_time (int): timestamp in microseconds since UNIX epoch. |
93 target (Target): a Target to use. | 97 target (Target): a Target to use. |
94 """ | 98 """ |
95 | 99 |
96 metric_pb = collection_pb.data.add() | 100 metric_pb = collection_pb.data.add() |
97 metric_pb.metric_name_prefix = '/chrome/infra/' | 101 metric_pb.metric_name_prefix = '/chrome/infra/' |
98 metric_pb.name = self._name | 102 metric_pb.name = self._name |
99 if self._description is not None: | 103 if self._description is not None: |
100 metric_pb.description = self._description | 104 metric_pb.description = self._description |
105 if self._units is not None: | |
106 metric_pb.units = self._units | |
101 | 107 |
102 self._populate_value(metric_pb, value, start_time) | 108 self._populate_value(metric_pb, value, start_time) |
103 self._populate_fields(metric_pb, fields) | 109 self._populate_fields(metric_pb, fields) |
104 | 110 |
105 target._populate_target_pb(metric_pb) | 111 target._populate_target_pb(metric_pb) |
106 | 112 |
107 def _populate_fields(self, metric, fields): | 113 def _populate_fields(self, metric, fields): |
108 """Fill in the fields attribute of a metric protocol buffer. | 114 """Fill in the fields attribute of a metric protocol buffer. |
109 | 115 |
110 Args: | 116 Args: |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
240 def increment(self, fields=None, target_fields=None): | 246 def increment(self, fields=None, target_fields=None): |
241 self._incr(fields, target_fields, 1) | 247 self._incr(fields, target_fields, 1) |
242 | 248 |
243 def increment_by(self, step, fields=None, target_fields=None): | 249 def increment_by(self, step, fields=None, target_fields=None): |
244 self._incr(fields, target_fields, step) | 250 self._incr(fields, target_fields, step) |
245 | 251 |
246 | 252 |
247 class CounterMetric(NumericMetric): | 253 class CounterMetric(NumericMetric): |
248 """A metric whose value type is a monotonically increasing integer.""" | 254 """A metric whose value type is a monotonically increasing integer.""" |
249 | 255 |
250 def __init__(self, name, fields=None, start_time=None, description=None): | 256 def __init__(self, name, fields=None, start_time=None, description=None, |
257 units=None): | |
251 super(CounterMetric, self).__init__( | 258 super(CounterMetric, self).__init__( |
252 name, fields=fields, description=description) | 259 name, fields=fields, description=description, units=units) |
253 self._start_time = start_time | 260 self._start_time = start_time |
254 | 261 |
255 def _populate_value(self, metric, value, start_time): | 262 def _populate_value(self, metric, value, start_time): |
256 metric.counter = value | 263 metric.counter = value |
257 metric.start_timestamp_us = int(start_time * MICROSECONDS_PER_SECOND) | 264 metric.start_timestamp_us = int(start_time * MICROSECONDS_PER_SECOND) |
258 | 265 |
259 def set(self, value, fields=None, target_fields=None): | 266 def set(self, value, fields=None, target_fields=None): |
260 if not isinstance(value, (int, long)): | 267 if not isinstance(value, (int, long)): |
261 raise errors.MonitoringInvalidValueTypeError(self._name, value) | 268 raise errors.MonitoringInvalidValueTypeError(self._name, value) |
262 self._set(fields, target_fields, value, enforce_ge=True) | 269 self._set(fields, target_fields, value, enforce_ge=True) |
(...skipping 18 matching lines...) Expand all Loading... | |
281 raise errors.MonitoringInvalidValueTypeError(self._name, value) | 288 raise errors.MonitoringInvalidValueTypeError(self._name, value) |
282 self._set(fields, target_fields, value) | 289 self._set(fields, target_fields, value) |
283 | 290 |
284 def is_cumulative(self): | 291 def is_cumulative(self): |
285 return False | 292 return False |
286 | 293 |
287 | 294 |
288 class CumulativeMetric(NumericMetric): | 295 class CumulativeMetric(NumericMetric): |
289 """A metric whose value type is a monotonically increasing float.""" | 296 """A metric whose value type is a monotonically increasing float.""" |
290 | 297 |
291 def __init__(self, name, fields=None, start_time=None, description=None): | 298 def __init__(self, name, fields=None, start_time=None, description=None, |
299 units=None): | |
292 super(CumulativeMetric, self).__init__( | 300 super(CumulativeMetric, self).__init__( |
293 name, fields=fields, description=description) | 301 name, fields=fields, description=description, units=units) |
294 self._start_time = start_time | 302 self._start_time = start_time |
295 | 303 |
296 def _populate_value(self, metric, value, start_time): | 304 def _populate_value(self, metric, value, start_time): |
297 metric.cumulative_double_value = value | 305 metric.cumulative_double_value = value |
298 metric.start_timestamp_us = int(start_time * MICROSECONDS_PER_SECOND) | 306 metric.start_timestamp_us = int(start_time * MICROSECONDS_PER_SECOND) |
299 | 307 |
300 def set(self, value, fields=None, target_fields=None): | 308 def set(self, value, fields=None, target_fields=None): |
301 if not isinstance(value, (float, int)): | 309 if not isinstance(value, (float, int)): |
302 raise errors.MonitoringInvalidValueTypeError(self._name, value) | 310 raise errors.MonitoringInvalidValueTypeError(self._name, value) |
303 self._set(fields, target_fields, float(value), enforce_ge=True) | 311 self._set(fields, target_fields, float(value), enforce_ge=True) |
(...skipping 25 matching lines...) Expand all Loading... | |
329 for many kinds of data, but you may want to provide a FixedWidthBucketer or | 337 for many kinds of data, but you may want to provide a FixedWidthBucketer or |
330 GeometricBucketer with different parameters.""" | 338 GeometricBucketer with different parameters.""" |
331 | 339 |
332 CANONICAL_SPEC_TYPES = { | 340 CANONICAL_SPEC_TYPES = { |
333 2: metrics_pb2.PrecomputedDistribution.CANONICAL_POWERS_OF_2, | 341 2: metrics_pb2.PrecomputedDistribution.CANONICAL_POWERS_OF_2, |
334 10**0.2: metrics_pb2.PrecomputedDistribution.CANONICAL_POWERS_OF_10_P_0_2, | 342 10**0.2: metrics_pb2.PrecomputedDistribution.CANONICAL_POWERS_OF_10_P_0_2, |
335 10: metrics_pb2.PrecomputedDistribution.CANONICAL_POWERS_OF_10, | 343 10: metrics_pb2.PrecomputedDistribution.CANONICAL_POWERS_OF_10, |
336 } | 344 } |
337 | 345 |
338 def __init__(self, name, is_cumulative=True, bucketer=None, fields=None, | 346 def __init__(self, name, is_cumulative=True, bucketer=None, fields=None, |
339 start_time=None, description=None): | 347 start_time=None, description=None, units=None): |
340 super(DistributionMetric, self).__init__( | 348 super(DistributionMetric, self).__init__( |
341 name, fields=fields, description=description) | 349 name, fields=fields, description=description, units=units) |
342 self._start_time = start_time | 350 self._start_time = start_time |
343 | 351 |
344 if bucketer is None: | 352 if bucketer is None: |
345 bucketer = distribution.GeometricBucketer() | 353 bucketer = distribution.GeometricBucketer() |
346 | 354 |
347 self._is_cumulative = is_cumulative | 355 self._is_cumulative = is_cumulative |
348 self.bucketer = bucketer | 356 self.bucketer = bucketer |
349 | 357 |
350 def _populate_value(self, metric, value, start_time): | 358 def _populate_value(self, metric, value, start_time): |
351 pb = metric.distribution | 359 pb = metric.distribution |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
425 self._set(fields, target_fields, value) | 433 self._set(fields, target_fields, value) |
426 | 434 |
427 def is_cumulative(self): | 435 def is_cumulative(self): |
428 raise NotImplementedError() # Keep this class abstract. | 436 raise NotImplementedError() # Keep this class abstract. |
429 | 437 |
430 | 438 |
431 class CumulativeDistributionMetric(DistributionMetric): | 439 class CumulativeDistributionMetric(DistributionMetric): |
432 """A DistributionMetric with is_cumulative set to True.""" | 440 """A DistributionMetric with is_cumulative set to True.""" |
433 | 441 |
434 def __init__(self, name, bucketer=None, fields=None, | 442 def __init__(self, name, bucketer=None, fields=None, |
435 description=None): | 443 description=None, units=None): |
436 super(CumulativeDistributionMetric, self).__init__( | 444 super(CumulativeDistributionMetric, self).__init__( |
437 name, | 445 name, |
438 is_cumulative=True, | 446 is_cumulative=True, |
439 bucketer=bucketer, | 447 bucketer=bucketer, |
440 fields=fields, | 448 fields=fields, |
441 description=description) | 449 description=description, |
450 units=units) | |
442 | 451 |
443 def is_cumulative(self): | 452 def is_cumulative(self): |
444 return True | 453 return True |
445 | 454 |
446 | 455 |
447 class NonCumulativeDistributionMetric(DistributionMetric): | 456 class NonCumulativeDistributionMetric(DistributionMetric): |
448 """A DistributionMetric with is_cumulative set to False.""" | 457 """A DistributionMetric with is_cumulative set to False.""" |
449 | 458 |
450 def __init__(self, name, bucketer=None, fields=None, | 459 def __init__(self, name, bucketer=None, fields=None, |
451 description=None): | 460 description=None, units=None): |
452 super(NonCumulativeDistributionMetric, self).__init__( | 461 super(NonCumulativeDistributionMetric, self).__init__( |
453 name, | 462 name, |
454 is_cumulative=False, | 463 is_cumulative=False, |
455 bucketer=bucketer, | 464 bucketer=bucketer, |
456 fields=fields, | 465 fields=fields, |
457 description=description) | 466 description=description, |
467 units=units) | |
458 | 468 |
459 def is_cumulative(self): | 469 def is_cumulative(self): |
460 return False | 470 return False |
471 | |
472 | |
473 class MetaMetricsDataUnits(type): | |
474 """Metaclass to populate the enum values of metrics_pb2.MetricsData.Units | |
agable
2016/06/29 18:25:23
nit: all our docstrings start with a single senten
ddoman
2016/07/06 03:35:37
Done.
| |
475 as class-level attributes. | |
476 """ | |
477 def __new__(mcs, name, bases, attrs): | |
478 attrs.update(metrics_pb2.MetricsData.Units.items()) | |
479 return super(MetaMetricsDataUnits, mcs).__new__(mcs, name, bases, attrs) | |
480 | |
481 | |
482 class MetricsDataUnits(object): | |
483 """Wrapper class for MetricsData.Units. Providing this wrapper class, | |
484 applications that use ts_mon.metrics don't need to import | |
485 metrics_pb2.MetricsData. | |
486 | |
487 See infra_libs/ts_mon/protos/metrics.proto for a list of supported units. | |
488 """ | |
489 __metaclass__ = MetaMetricsDataUnits | |
OLD | NEW |