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 14 matching lines...) Expand all Loading... |
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 |
| 35 The unit of measurement for Metric data can be specified with MetricsDataUnits |
| 36 when a Metric object is created: |
| 37 e.g., MetricsDataUnits.SECONDS, MetricsDataUnits.BYTES, and etc.., |
| 38 A full list of supported units can be found in the following protobuf file |
| 39 : infra_libs/ts_mon/protos/metrics.proto |
| 40 |
35 Do not directly instantiate an object of this class. | 41 Do not directly instantiate an object of this class. |
36 Use the concrete child classes instead: | 42 Use the concrete child classes instead: |
37 * StringMetric for metrics with string value | 43 * StringMetric for metrics with string value |
38 * BooleanMetric for metrics with boolean values | 44 * BooleanMetric for metrics with boolean values |
39 * CounterMetric for metrics with monotonically increasing integer values | 45 * CounterMetric for metrics with monotonically increasing integer values |
40 * GaugeMetric for metrics with arbitrarily varying integer values | 46 * GaugeMetric for metrics with arbitrarily varying integer values |
41 * CumulativeMetric for metrics with monotonically increasing float values | 47 * CumulativeMetric for metrics with monotonically increasing float values |
42 * FloatMetric for metrics with arbitrarily varying float values | 48 * FloatMetric for metrics with arbitrarily varying float values |
43 | 49 |
44 See http://go/inframon-doc for help designing and using your metrics. | 50 See http://go/inframon-doc for help designing and using your metrics. |
45 """ | 51 """ |
46 | 52 |
47 def __init__(self, name, fields=None, description=None): | 53 def __init__(self, name, fields=None, description=None, units=None): |
48 """Create an instance of a Metric. | 54 """Create an instance of a Metric. |
49 | 55 |
50 Args: | 56 Args: |
51 name (str): the file-like name of this metric | 57 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 | 58 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 | 59 description (string): help string for the metric. Should be enough to |
54 know what the metric is about. | 60 know what the metric is about. |
| 61 units (int): the unit used to measure data for given |
| 62 metric. Please use the attributes of MetricDataUnit to find |
| 63 valid integer values for this argument. |
55 """ | 64 """ |
56 self._name = name.lstrip('/') | 65 self._name = name.lstrip('/') |
57 self._start_time = None | 66 self._start_time = None |
58 fields = fields or {} | 67 fields = fields or {} |
59 if len(fields) > 7: | 68 if len(fields) > 7: |
60 raise errors.MonitoringTooManyFieldsError(self._name, fields) | 69 raise errors.MonitoringTooManyFieldsError(self._name, fields) |
61 self._fields = fields | 70 self._fields = fields |
62 self._normalized_fields = self._normalize_fields(self._fields) | 71 self._normalized_fields = self._normalize_fields(self._fields) |
63 self._description = description | 72 self._description = description |
| 73 self._units = units |
64 | 74 |
65 interface.register(self) | 75 interface.register(self) |
66 | 76 |
67 @property | 77 @property |
68 def name(self): | 78 def name(self): |
69 return self._name | 79 return self._name |
70 | 80 |
71 @property | 81 @property |
72 def start_time(self): | 82 def start_time(self): |
73 return self._start_time | 83 return self._start_time |
(...skipping 17 matching lines...) Expand all Loading... |
91 to add the current metric values. | 101 to add the current metric values. |
92 start_time (int): timestamp in microseconds since UNIX epoch. | 102 start_time (int): timestamp in microseconds since UNIX epoch. |
93 target (Target): a Target to use. | 103 target (Target): a Target to use. |
94 """ | 104 """ |
95 | 105 |
96 metric_pb = collection_pb.data.add() | 106 metric_pb = collection_pb.data.add() |
97 metric_pb.metric_name_prefix = interface.state.metric_name_prefix | 107 metric_pb.metric_name_prefix = interface.state.metric_name_prefix |
98 metric_pb.name = self._name | 108 metric_pb.name = self._name |
99 if self._description is not None: | 109 if self._description is not None: |
100 metric_pb.description = self._description | 110 metric_pb.description = self._description |
| 111 if self._units is not None: |
| 112 metric_pb.units = self._units |
101 | 113 |
102 self._populate_value(metric_pb, value, start_time) | 114 self._populate_value(metric_pb, value, start_time) |
103 self._populate_fields(metric_pb, fields) | 115 self._populate_fields(metric_pb, fields) |
104 | 116 |
105 target._populate_target_pb(metric_pb) | 117 target._populate_target_pb(metric_pb) |
106 | 118 |
107 def _populate_fields(self, metric, fields): | 119 def _populate_fields(self, metric, fields): |
108 """Fill in the fields attribute of a metric protocol buffer. | 120 """Fill in the fields attribute of a metric protocol buffer. |
109 | 121 |
110 Args: | 122 Args: |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
243 def increment(self, fields=None, target_fields=None): | 255 def increment(self, fields=None, target_fields=None): |
244 self._incr(fields, target_fields, 1) | 256 self._incr(fields, target_fields, 1) |
245 | 257 |
246 def increment_by(self, step, fields=None, target_fields=None): | 258 def increment_by(self, step, fields=None, target_fields=None): |
247 self._incr(fields, target_fields, step) | 259 self._incr(fields, target_fields, step) |
248 | 260 |
249 | 261 |
250 class CounterMetric(NumericMetric): | 262 class CounterMetric(NumericMetric): |
251 """A metric whose value type is a monotonically increasing integer.""" | 263 """A metric whose value type is a monotonically increasing integer.""" |
252 | 264 |
253 def __init__(self, name, fields=None, start_time=None, description=None): | 265 def __init__(self, name, fields=None, start_time=None, description=None, |
| 266 units=None): |
254 super(CounterMetric, self).__init__( | 267 super(CounterMetric, self).__init__( |
255 name, fields=fields, description=description) | 268 name, fields=fields, description=description, units=units) |
256 self._start_time = start_time | 269 self._start_time = start_time |
257 | 270 |
258 def _populate_value(self, metric, value, start_time): | 271 def _populate_value(self, metric, value, start_time): |
259 metric.counter = value | 272 metric.counter = value |
260 metric.start_timestamp_us = int(start_time * MICROSECONDS_PER_SECOND) | 273 metric.start_timestamp_us = int(start_time * MICROSECONDS_PER_SECOND) |
261 | 274 |
262 def set(self, value, fields=None, target_fields=None): | 275 def set(self, value, fields=None, target_fields=None): |
263 if not isinstance(value, (int, long)): | 276 if not isinstance(value, (int, long)): |
264 raise errors.MonitoringInvalidValueTypeError(self._name, value) | 277 raise errors.MonitoringInvalidValueTypeError(self._name, value) |
265 self._set(fields, target_fields, value, enforce_ge=True) | 278 self._set(fields, target_fields, value, enforce_ge=True) |
(...skipping 18 matching lines...) Expand all Loading... |
284 raise errors.MonitoringInvalidValueTypeError(self._name, value) | 297 raise errors.MonitoringInvalidValueTypeError(self._name, value) |
285 self._set(fields, target_fields, value) | 298 self._set(fields, target_fields, value) |
286 | 299 |
287 def is_cumulative(self): | 300 def is_cumulative(self): |
288 return False | 301 return False |
289 | 302 |
290 | 303 |
291 class CumulativeMetric(NumericMetric): | 304 class CumulativeMetric(NumericMetric): |
292 """A metric whose value type is a monotonically increasing float.""" | 305 """A metric whose value type is a monotonically increasing float.""" |
293 | 306 |
294 def __init__(self, name, fields=None, start_time=None, description=None): | 307 def __init__(self, name, fields=None, start_time=None, description=None, |
| 308 units=None): |
295 super(CumulativeMetric, self).__init__( | 309 super(CumulativeMetric, self).__init__( |
296 name, fields=fields, description=description) | 310 name, fields=fields, description=description, units=units) |
297 self._start_time = start_time | 311 self._start_time = start_time |
298 | 312 |
299 def _populate_value(self, metric, value, start_time): | 313 def _populate_value(self, metric, value, start_time): |
300 metric.cumulative_double_value = value | 314 metric.cumulative_double_value = value |
301 metric.start_timestamp_us = int(start_time * MICROSECONDS_PER_SECOND) | 315 metric.start_timestamp_us = int(start_time * MICROSECONDS_PER_SECOND) |
302 | 316 |
303 def set(self, value, fields=None, target_fields=None): | 317 def set(self, value, fields=None, target_fields=None): |
304 if not isinstance(value, (float, int)): | 318 if not isinstance(value, (float, int)): |
305 raise errors.MonitoringInvalidValueTypeError(self._name, value) | 319 raise errors.MonitoringInvalidValueTypeError(self._name, value) |
306 self._set(fields, target_fields, float(value), enforce_ge=True) | 320 self._set(fields, target_fields, float(value), enforce_ge=True) |
(...skipping 25 matching lines...) Expand all Loading... |
332 for many kinds of data, but you may want to provide a FixedWidthBucketer or | 346 for many kinds of data, but you may want to provide a FixedWidthBucketer or |
333 GeometricBucketer with different parameters.""" | 347 GeometricBucketer with different parameters.""" |
334 | 348 |
335 CANONICAL_SPEC_TYPES = { | 349 CANONICAL_SPEC_TYPES = { |
336 2: metrics_pb2.PrecomputedDistribution.CANONICAL_POWERS_OF_2, | 350 2: metrics_pb2.PrecomputedDistribution.CANONICAL_POWERS_OF_2, |
337 10**0.2: metrics_pb2.PrecomputedDistribution.CANONICAL_POWERS_OF_10_P_0_2, | 351 10**0.2: metrics_pb2.PrecomputedDistribution.CANONICAL_POWERS_OF_10_P_0_2, |
338 10: metrics_pb2.PrecomputedDistribution.CANONICAL_POWERS_OF_10, | 352 10: metrics_pb2.PrecomputedDistribution.CANONICAL_POWERS_OF_10, |
339 } | 353 } |
340 | 354 |
341 def __init__(self, name, is_cumulative=True, bucketer=None, fields=None, | 355 def __init__(self, name, is_cumulative=True, bucketer=None, fields=None, |
342 start_time=None, description=None): | 356 start_time=None, description=None, units=None): |
343 super(DistributionMetric, self).__init__( | 357 super(DistributionMetric, self).__init__( |
344 name, fields=fields, description=description) | 358 name, fields=fields, description=description, units=units) |
345 self._start_time = start_time | 359 self._start_time = start_time |
346 | 360 |
347 if bucketer is None: | 361 if bucketer is None: |
348 bucketer = distribution.GeometricBucketer() | 362 bucketer = distribution.GeometricBucketer() |
349 | 363 |
350 self._is_cumulative = is_cumulative | 364 self._is_cumulative = is_cumulative |
351 self.bucketer = bucketer | 365 self.bucketer = bucketer |
352 | 366 |
353 def _populate_value(self, metric, value, start_time): | 367 def _populate_value(self, metric, value, start_time): |
354 pb = metric.distribution | 368 pb = metric.distribution |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
428 self._set(fields, target_fields, value) | 442 self._set(fields, target_fields, value) |
429 | 443 |
430 def is_cumulative(self): | 444 def is_cumulative(self): |
431 raise NotImplementedError() # Keep this class abstract. | 445 raise NotImplementedError() # Keep this class abstract. |
432 | 446 |
433 | 447 |
434 class CumulativeDistributionMetric(DistributionMetric): | 448 class CumulativeDistributionMetric(DistributionMetric): |
435 """A DistributionMetric with is_cumulative set to True.""" | 449 """A DistributionMetric with is_cumulative set to True.""" |
436 | 450 |
437 def __init__(self, name, bucketer=None, fields=None, | 451 def __init__(self, name, bucketer=None, fields=None, |
438 description=None): | 452 description=None, units=None): |
439 super(CumulativeDistributionMetric, self).__init__( | 453 super(CumulativeDistributionMetric, self).__init__( |
440 name, | 454 name, |
441 is_cumulative=True, | 455 is_cumulative=True, |
442 bucketer=bucketer, | 456 bucketer=bucketer, |
443 fields=fields, | 457 fields=fields, |
444 description=description) | 458 description=description, |
| 459 units=units) |
445 | 460 |
446 def is_cumulative(self): | 461 def is_cumulative(self): |
447 return True | 462 return True |
448 | 463 |
449 | 464 |
450 class NonCumulativeDistributionMetric(DistributionMetric): | 465 class NonCumulativeDistributionMetric(DistributionMetric): |
451 """A DistributionMetric with is_cumulative set to False.""" | 466 """A DistributionMetric with is_cumulative set to False.""" |
452 | 467 |
453 def __init__(self, name, bucketer=None, fields=None, | 468 def __init__(self, name, bucketer=None, fields=None, |
454 description=None): | 469 description=None, units=None): |
455 super(NonCumulativeDistributionMetric, self).__init__( | 470 super(NonCumulativeDistributionMetric, self).__init__( |
456 name, | 471 name, |
457 is_cumulative=False, | 472 is_cumulative=False, |
458 bucketer=bucketer, | 473 bucketer=bucketer, |
459 fields=fields, | 474 fields=fields, |
460 description=description) | 475 description=description, |
| 476 units=units) |
461 | 477 |
462 def is_cumulative(self): | 478 def is_cumulative(self): |
463 return False | 479 return False |
| 480 |
| 481 |
| 482 class MetaMetricsDataUnits(type): |
| 483 """Metaclass to populate the enum values of metrics_pb2.MetricsData.Units.""" |
| 484 def __new__(mcs, name, bases, attrs): |
| 485 attrs.update(metrics_pb2.MetricsData.Units.items()) |
| 486 return super(MetaMetricsDataUnits, mcs).__new__(mcs, name, bases, attrs) |
| 487 |
| 488 |
| 489 class MetricsDataUnits(object): |
| 490 """An enumeration class for units of measurement for Metrics data. |
| 491 See infra_libs/ts_mon/protos/metrics.proto for a full list of supported units. |
| 492 """ |
| 493 __metaclass__ = MetaMetricsDataUnits |
OLD | NEW |