| 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 = '/chrome/infra/' | 107 metric_pb.metric_name_prefix = '/chrome/infra/' |
| 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 |