Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(231)

Side by Side Diff: client/third_party/infra_libs/ts_mon/common/metrics.py

Issue 2465423002: Roll infra_libs to 564aaf7480f24c90687df79d9cef910cc342a54d (Closed)
Patch Set: update readmes Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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.current import metrics_pb2
10 from infra_libs.ts_mon.protos.new import metrics_pb2 as new_metrics_pb2
10 11
11 from infra_libs.ts_mon.common import distribution 12 from infra_libs.ts_mon.common import distribution
12 from infra_libs.ts_mon.common import errors 13 from infra_libs.ts_mon.common import errors
13 from infra_libs.ts_mon.common import interface 14 from infra_libs.ts_mon.common import interface
14 15
15 16
16 MICROSECONDS_PER_SECOND = 1000000 17 MICROSECONDS_PER_SECOND = 1000000
17 18
18 19
19 class Metric(object): 20 class Metric(object):
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
86 raise NotImplementedError() 87 raise NotImplementedError()
87 88
88 def __eq__(self, other): 89 def __eq__(self, other):
89 return (self.name == other.name and 90 return (self.name == other.name and
90 self._fields == other._fields and 91 self._fields == other._fields and
91 type(self) == type(other)) 92 type(self) == type(other))
92 93
93 def unregister(self): 94 def unregister(self):
94 interface.unregister(self) 95 interface.unregister(self)
95 96
97 @staticmethod
98 def _map_units_to_string(units):
99 """Map MetricsDataUnits to the corresponding string according to:
100 http://unitsofmeasure.org/ucum.html because that's what the new proto
101 requires."""
102 if units in _UNITS_TO_STRING:
103 return _UNITS_TO_STRING[units]
104 else:
105 return '{unknown}'
106
107 def _populate_data_set(self, data_set, fields):
108 """Populate MetricsDataSet."""
109 data_set.metric_name = '%s%s' % (interface.state.metric_name_prefix,
110 self._name)
111 data_set.description = self._description or ''
112 data_set.annotations.unit = self._map_units_to_string(self._units)
113
114 if self.is_cumulative():
115 data_set.stream_kind = new_metrics_pb2.CUMULATIVE
116 else:
117 data_set.stream_kind = new_metrics_pb2.GAUGE
118
119 self._populate_value_type(data_set)
120 self._populate_field_descriptors(data_set, fields)
121
122 def _populate_data(self, data_set, start_time, end_time, fields, value):
123 """Add a new metrics_pb2.MetricsData to data_set
124
125 Args:
126 data_set (new_metrics_pb2.MetricsDataSet): protocol buffer into
127 which to add the current metric values.
128 start_time (int): timestamp in microseconds since UNIX epoch.
129 """
130 data = data_set.data.add()
131 data.start_timestamp.seconds = int(start_time)
132 data.end_timestamp.seconds = int(end_time)
133
134 self._populate_fields_new(data, fields)
135 self._populate_value_new(data, value)
136
96 def serialize_to(self, collection_pb, start_time, fields, value, target): 137 def serialize_to(self, collection_pb, start_time, fields, value, target):
97 """Generate metrics_pb2.MetricsData messages for this metric. 138 """Generate metrics_pb2.MetricsData messages for this metric.
98 139
99 Args: 140 Args:
100 collection_pb (metrics_pb2.MetricsCollection): protocol buffer into which 141 collection_pb (metrics_pb2.MetricsCollection): protocol buffer into which
101 to add the current metric values. 142 to add the current metric values.
102 start_time (int): timestamp in microseconds since UNIX epoch. 143 start_time (int): timestamp in microseconds since UNIX epoch.
103 target (Target): a Target to use. 144 target (Target): a Target to use.
104 """ 145 """
105 146
106 metric_pb = collection_pb.data.add() 147 metric_pb = collection_pb.data.add()
107 metric_pb.metric_name_prefix = interface.state.metric_name_prefix 148 metric_pb.metric_name_prefix = interface.state.metric_name_prefix
108 metric_pb.name = self._name 149 metric_pb.name = self._name
109 if self._description is not None: 150 if self._description is not None:
110 metric_pb.description = self._description 151 metric_pb.description = self._description
111 if self._units is not None: 152 if self._units is not None:
112 metric_pb.units = self._units 153 metric_pb.units = self._units
113 154
114 self._populate_value(metric_pb, value, start_time) 155 self._populate_value(metric_pb, value, start_time)
115 self._populate_fields(metric_pb, fields) 156 self._populate_fields(metric_pb, fields)
116 157
117 target._populate_target_pb(metric_pb) 158 target._populate_target_pb(metric_pb)
118 159
160 def _populate_field_descriptors(self, data_set, fields):
161 """Populate `field_descriptor` in MetricsDataSet.
162
163 Args:
164 data_set (new_metrics_pb2.MetricsDataSet): a data set protobuf to
165 populate
166 fields (list of (key, value) tuples): normalized metric fields
167
168 Raises:
169 MonitoringInvalidFieldTypeError: if a field has a value of unknown type
170 """
171 field_type = new_metrics_pb2.MetricsDataSet.MetricFieldDescriptor
172 for key, value in fields:
173 descriptor = data_set.field_descriptor.add()
174 descriptor.name = key
175 if isinstance(value, basestring):
176 descriptor.field_type = field_type.STRING
177 elif isinstance(value, bool):
178 descriptor.field_type = field_type.BOOL
179 elif isinstance(value, int):
180 descriptor.field_type = field_type.INT64
181 else:
182 raise errors.MonitoringInvalidFieldTypeError(self._name, key, value)
183
184 def _populate_fields_new(self, data, fields):
185 """Fill in the fields attribute of a metric protocol buffer.
186
187 Args:
188 metric (metrics_pb2.MetricsData): a metrics protobuf to populate
189 fields (list of (key, value) tuples): normalized metric fields
190
191 Raises:
192 MonitoringInvalidFieldTypeError: if a field has a value of unknown type
193 """
194 for key, value in fields:
195 field = data.field.add()
196 field.name = key
197 if isinstance(value, basestring):
198 field.string_value = value
199 elif isinstance(value, bool):
200 field.bool_value = value
201 elif isinstance(value, int):
202 field.int64_value = value
203 else:
204 raise errors.MonitoringInvalidFieldTypeError(self._name, key, value)
205
119 def _populate_fields(self, metric, fields): 206 def _populate_fields(self, metric, fields):
120 """Fill in the fields attribute of a metric protocol buffer. 207 """Fill in the fields attribute of a metric protocol buffer.
121 208
122 Args: 209 Args:
123 metric (metrics_pb2.MetricsData): a metrics protobuf to populate 210 metric (metrics_pb2.MetricsData): a metrics protobuf to populate
124 fields (list of (key, value) tuples): normalized metric fields 211 fields (list of (key, value) tuples): normalized metric fields
125 212
126 Raises: 213 Raises:
127 MonitoringInvalidFieldTypeError: if a field has a value of unknown type 214 MonitoringInvalidFieldTypeError: if a field has a value of unknown type
128 """ 215 """
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
168 def _populate_value(self, metric, value, start_time): 255 def _populate_value(self, metric, value, start_time):
169 """Fill in the the data values of a metric protocol buffer. 256 """Fill in the the data values of a metric protocol buffer.
170 257
171 Args: 258 Args:
172 metric (metrics_pb2.MetricsData): a metrics protobuf to populate 259 metric (metrics_pb2.MetricsData): a metrics protobuf to populate
173 value (see concrete class): the value of the metric to be set 260 value (see concrete class): the value of the metric to be set
174 start_time (int): timestamp in microseconds since UNIX epoch. 261 start_time (int): timestamp in microseconds since UNIX epoch.
175 """ 262 """
176 raise NotImplementedError() 263 raise NotImplementedError()
177 264
265 def _populate_value_new(self, data, value):
266 """Fill in the the data values of a metric protocol buffer.
267
268 Args:
269 data (metrics_pb2.MetricsData): a metrics protobuf to populate
270 value (see concrete class): the value of the metric to be set
271 """
272 raise NotImplementedError()
273
274 def _populate_value_type(self, data_set):
275 """Fill in the the data values of a metric protocol buffer.
276
277 Args:
278 data_set (metrics_pb2.MetricsDataSet): a MetricsDataSet protobuf to
279 populate
280 """
281 raise NotImplementedError()
282
178 def set(self, value, fields=None, target_fields=None): 283 def set(self, value, fields=None, target_fields=None):
179 """Set a new value for this metric. Results in sending a new value. 284 """Set a new value for this metric. Results in sending a new value.
180 285
181 The subclass should do appropriate type checking on value and then call 286 The subclass should do appropriate type checking on value and then call
182 self._set_and_send_value. 287 self._set_and_send_value.
183 288
184 Args: 289 Args:
185 value (see concrete class): the value of the metric to be set 290 value (see concrete class): the value of the metric to be set
186 fields (dict): additional metric fields to complement those on self 291 fields (dict): additional metric fields to complement those on self
187 target_fields (dict): overwrite some of the default target fields 292 target_fields (dict): overwrite some of the default target fields
(...skipping 29 matching lines...) Expand all
217 interface.state.store.incr(self.name, self._normalize_fields(fields), 322 interface.state.store.incr(self.name, self._normalize_fields(fields),
218 target_fields, delta, modify_fn=modify_fn) 323 target_fields, delta, modify_fn=modify_fn)
219 324
220 325
221 class StringMetric(Metric): 326 class StringMetric(Metric):
222 """A metric whose value type is a string.""" 327 """A metric whose value type is a string."""
223 328
224 def _populate_value(self, metric, value, start_time): 329 def _populate_value(self, metric, value, start_time):
225 metric.string_value = value 330 metric.string_value = value
226 331
332 def _populate_value_new(self, data, value):
333 data.string_value = value
334
335 def _populate_value_type(self, data_set):
336 data_set.value_type = new_metrics_pb2.STRING
337
227 def set(self, value, fields=None, target_fields=None): 338 def set(self, value, fields=None, target_fields=None):
228 if not isinstance(value, basestring): 339 if not isinstance(value, basestring):
229 raise errors.MonitoringInvalidValueTypeError(self._name, value) 340 raise errors.MonitoringInvalidValueTypeError(self._name, value)
230 self._set(fields, target_fields, value) 341 self._set(fields, target_fields, value)
231 342
232 def is_cumulative(self): 343 def is_cumulative(self):
233 return False 344 return False
234 345
235 346
236 class BooleanMetric(Metric): 347 class BooleanMetric(Metric):
237 """A metric whose value type is a boolean.""" 348 """A metric whose value type is a boolean."""
238 349
239 def _populate_value(self, metric, value, start_time): 350 def _populate_value(self, metric, value, start_time):
240 metric.boolean_value = value 351 metric.boolean_value = value
241 352
353 def _populate_value_new(self, data, value):
354 data.bool_value = value
355
356 def _populate_value_type(self, data_set):
357 data_set.value_type = new_metrics_pb2.BOOL
358
242 def set(self, value, fields=None, target_fields=None): 359 def set(self, value, fields=None, target_fields=None):
243 if not isinstance(value, bool): 360 if not isinstance(value, bool):
244 raise errors.MonitoringInvalidValueTypeError(self._name, value) 361 raise errors.MonitoringInvalidValueTypeError(self._name, value)
245 self._set(fields, target_fields, value) 362 self._set(fields, target_fields, value)
246 363
247 def is_cumulative(self): 364 def is_cumulative(self):
248 return False 365 return False
249 366
250 367
251 class NumericMetric(Metric): # pylint: disable=abstract-method 368 class NumericMetric(Metric): # pylint: disable=abstract-method
(...skipping 13 matching lines...) Expand all
265 def __init__(self, name, fields=None, start_time=None, description=None, 382 def __init__(self, name, fields=None, start_time=None, description=None,
266 units=None): 383 units=None):
267 super(CounterMetric, self).__init__( 384 super(CounterMetric, self).__init__(
268 name, fields=fields, description=description, units=units) 385 name, fields=fields, description=description, units=units)
269 self._start_time = start_time 386 self._start_time = start_time
270 387
271 def _populate_value(self, metric, value, start_time): 388 def _populate_value(self, metric, value, start_time):
272 metric.counter = value 389 metric.counter = value
273 metric.start_timestamp_us = int(start_time * MICROSECONDS_PER_SECOND) 390 metric.start_timestamp_us = int(start_time * MICROSECONDS_PER_SECOND)
274 391
392 def _populate_value_new(self, data, value):
393 data.int64_value = value
394
395 def _populate_value_type(self, data_set):
396 data_set.value_type = new_metrics_pb2.INT64
397
275 def set(self, value, fields=None, target_fields=None): 398 def set(self, value, fields=None, target_fields=None):
276 if not isinstance(value, (int, long)): 399 if not isinstance(value, (int, long)):
277 raise errors.MonitoringInvalidValueTypeError(self._name, value) 400 raise errors.MonitoringInvalidValueTypeError(self._name, value)
278 self._set(fields, target_fields, value, enforce_ge=True) 401 self._set(fields, target_fields, value, enforce_ge=True)
279 402
280 def increment_by(self, step, fields=None, target_fields=None): 403 def increment_by(self, step, fields=None, target_fields=None):
281 if not isinstance(step, (int, long)): 404 if not isinstance(step, (int, long)):
282 raise errors.MonitoringInvalidValueTypeError(self._name, step) 405 raise errors.MonitoringInvalidValueTypeError(self._name, step)
283 self._incr(fields, target_fields, step) 406 self._incr(fields, target_fields, step)
284 407
285 def is_cumulative(self): 408 def is_cumulative(self):
286 return True 409 return True
287 410
288 411
289 class GaugeMetric(NumericMetric): 412 class GaugeMetric(NumericMetric):
290 """A metric whose value type is an integer.""" 413 """A metric whose value type is an integer."""
291 414
292 def _populate_value(self, metric, value, start_time): 415 def _populate_value(self, metric, value, start_time):
293 metric.gauge = value 416 metric.gauge = value
294 417
418 def _populate_value_new(self, data, value):
419 data.int64_value = value
420
421 def _populate_value_type(self, data_set):
422 data_set.value_type = new_metrics_pb2.INT64
423
295 def set(self, value, fields=None, target_fields=None): 424 def set(self, value, fields=None, target_fields=None):
296 if not isinstance(value, (int, long)): 425 if not isinstance(value, (int, long)):
297 raise errors.MonitoringInvalidValueTypeError(self._name, value) 426 raise errors.MonitoringInvalidValueTypeError(self._name, value)
298 self._set(fields, target_fields, value) 427 self._set(fields, target_fields, value)
299 428
300 def is_cumulative(self): 429 def is_cumulative(self):
301 return False 430 return False
302 431
303 432
304 class CumulativeMetric(NumericMetric): 433 class CumulativeMetric(NumericMetric):
305 """A metric whose value type is a monotonically increasing float.""" 434 """A metric whose value type is a monotonically increasing float."""
306 435
307 def __init__(self, name, fields=None, start_time=None, description=None, 436 def __init__(self, name, fields=None, start_time=None, description=None,
308 units=None): 437 units=None):
309 super(CumulativeMetric, self).__init__( 438 super(CumulativeMetric, self).__init__(
310 name, fields=fields, description=description, units=units) 439 name, fields=fields, description=description, units=units)
311 self._start_time = start_time 440 self._start_time = start_time
312 441
313 def _populate_value(self, metric, value, start_time): 442 def _populate_value(self, metric, value, start_time):
314 metric.cumulative_double_value = value 443 metric.cumulative_double_value = value
315 metric.start_timestamp_us = int(start_time * MICROSECONDS_PER_SECOND) 444 metric.start_timestamp_us = int(start_time * MICROSECONDS_PER_SECOND)
316 445
446 def _populate_value_new(self, data, value):
447 data.double_value = value
448
449 def _populate_value_type(self, data_set):
450 data_set.value_type = new_metrics_pb2.DOUBLE
451
317 def set(self, value, fields=None, target_fields=None): 452 def set(self, value, fields=None, target_fields=None):
318 if not isinstance(value, (float, int)): 453 if not isinstance(value, (float, int)):
319 raise errors.MonitoringInvalidValueTypeError(self._name, value) 454 raise errors.MonitoringInvalidValueTypeError(self._name, value)
320 self._set(fields, target_fields, float(value), enforce_ge=True) 455 self._set(fields, target_fields, float(value), enforce_ge=True)
321 456
322 def is_cumulative(self): 457 def is_cumulative(self):
323 return True 458 return True
324 459
325 460
326 class FloatMetric(NumericMetric): 461 class FloatMetric(NumericMetric):
327 """A metric whose value type is a float.""" 462 """A metric whose value type is a float."""
328 463
329 def _populate_value(self, metric, value, start_time): 464 def _populate_value(self, metric, value, start_time):
330 metric.noncumulative_double_value = value 465 metric.noncumulative_double_value = value
331 466
467 def _populate_value_new(self, metric, value):
468 metric.double_value = value
469
470 def _populate_value_type(self, data_set_pb):
471 data_set_pb.value_type = new_metrics_pb2.DOUBLE
472
332 def set(self, value, fields=None, target_fields=None): 473 def set(self, value, fields=None, target_fields=None):
333 if not isinstance(value, (float, int)): 474 if not isinstance(value, (float, int)):
334 raise errors.MonitoringInvalidValueTypeError(self._name, value) 475 raise errors.MonitoringInvalidValueTypeError(self._name, value)
335 self._set(fields, target_fields, float(value)) 476 self._set(fields, target_fields, float(value))
336 477
337 def is_cumulative(self): 478 def is_cumulative(self):
338 return False 479 return False
339 480
340 481
341 class DistributionMetric(Metric): 482 class DistributionMetric(Metric):
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
389 530
390 # Add the overflow buckets if present. 531 # Add the overflow buckets if present.
391 if value.bucketer.underflow_bucket in value.buckets: 532 if value.bucketer.underflow_bucket in value.buckets:
392 pb.underflow = value.buckets[value.bucketer.underflow_bucket] 533 pb.underflow = value.buckets[value.bucketer.underflow_bucket]
393 if value.bucketer.overflow_bucket in value.buckets: 534 if value.bucketer.overflow_bucket in value.buckets:
394 pb.overflow = value.buckets[value.bucketer.overflow_bucket] 535 pb.overflow = value.buckets[value.bucketer.overflow_bucket]
395 536
396 if value.count != 0: 537 if value.count != 0:
397 pb.mean = float(value.sum) / value.count 538 pb.mean = float(value.sum) / value.count
398 539
540 def _populate_value_new(self, metric, value):
541 pb = metric.distribution_value
542
543 # Copy the bucketer params.
544 if value.bucketer.width == 0:
545 pb.exponential_buckets.growth_factor = value.bucketer.growth_factor
546 pb.exponential_buckets.scale = 1.0
547 pb.exponential_buckets.num_finite_buckets = (
548 value.bucketer.num_finite_buckets)
549 else:
550 pb.linear_buckets.width = value.bucketer.width
551 pb.linear_buckets.offset = 0.0
552 pb.linear_buckets.num_finite_buckets = value.bucketer.num_finite_buckets
553
554 # Copy the distribution bucket values. Only include the finite buckets, not
555 # the overflow buckets on each end.
556 pb.bucket_count.extend(
557 value.buckets.get(i, 0) for i in
558 xrange(0, value.bucketer.total_buckets))
559
560 pb.count = value.count
561 pb.mean = float(value.sum) / max(value.count, 1)
562
563 def _populate_value_type(self, data_set_pb):
564 data_set_pb.value_type = new_metrics_pb2.DISTRIBUTION
565
399 @staticmethod 566 @staticmethod
400 def _running_zero_generator(iterable): 567 def _running_zero_generator(iterable):
401 """Compresses sequences of zeroes in the iterable into negative zero counts. 568 """Compresses sequences of zeroes in the iterable into negative zero counts.
402 569
403 For example an input of [1, 0, 0, 0, 2] is converted to [1, -3, 2]. 570 For example an input of [1, 0, 0, 0, 2] is converted to [1, -3, 2].
404 """ 571 """
405 572
406 count = 0 573 count = 0
407 574
408 for value in iterable: 575 for value in iterable:
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
484 def __new__(mcs, name, bases, attrs): 651 def __new__(mcs, name, bases, attrs):
485 attrs.update(metrics_pb2.MetricsData.Units.items()) 652 attrs.update(metrics_pb2.MetricsData.Units.items())
486 return super(MetaMetricsDataUnits, mcs).__new__(mcs, name, bases, attrs) 653 return super(MetaMetricsDataUnits, mcs).__new__(mcs, name, bases, attrs)
487 654
488 655
489 class MetricsDataUnits(object): 656 class MetricsDataUnits(object):
490 """An enumeration class for units of measurement for Metrics data. 657 """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. 658 See infra_libs/ts_mon/protos/metrics.proto for a full list of supported units.
492 """ 659 """
493 __metaclass__ = MetaMetricsDataUnits 660 __metaclass__ = MetaMetricsDataUnits
661
662 _UNITS_TO_STRING = {
663 MetricsDataUnits.UNKNOWN_UNITS: '{unknown}',
664 MetricsDataUnits.SECONDS: 's',
665 MetricsDataUnits.MILLISECONDS: 'ms',
666 MetricsDataUnits.MICROSECONDS: 'us',
667 MetricsDataUnits.NANOSECONDS: 'ns',
668 MetricsDataUnits.BITS: 'B',
669 MetricsDataUnits.BYTES: 'By',
670 MetricsDataUnits.KILOBYTES: 'kBy',
671 MetricsDataUnits.MEGABYTES: 'MBy',
672 MetricsDataUnits.GIGABYTES: 'GBy',
673 MetricsDataUnits.KIBIBYTES: 'kiBy',
674 MetricsDataUnits.MEBIBYTES: 'MiBy',
675 MetricsDataUnits.GIBIBYTES: 'GiBy',
676 MetricsDataUnits.AMPS: 'A',
677 MetricsDataUnits.MILLIAMPS : 'mA',
678 MetricsDataUnits.DEGREES_CELSIUS: 'Cel'
679 }
OLDNEW
« no previous file with comments | « client/third_party/infra_libs/ts_mon/common/metric_store.py ('k') | client/third_party/infra_libs/ts_mon/common/monitors.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698