Chromium Code Reviews| 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 |