Skip to content
This repository was archived by the owner on Sep 17, 2025. It is now read-only.

Commit 9a07314

Browse files
authored
Cumulative metrics API (#626)
1 parent d685f98 commit 9a07314

File tree

5 files changed

+449
-33
lines changed

5 files changed

+449
-33
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
## Unreleased
44

5+
- Add cumulative API
6+
([#626](https://github.com/census-instrumentation/opencensus-python/pull/626))
7+
58
## 0.4.0
69
Released 2019-04-08
710

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# Copyright 2019, OpenCensus Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import six
16+
17+
from opencensus.metrics.export import metric_descriptor
18+
from opencensus.metrics.export import gauge
19+
20+
21+
class CumulativePointLong(gauge.GaugePointLong):
22+
"""A `GaugePointLong` that cannot decrease."""
23+
24+
def _set(self, val):
25+
if not isinstance(val, six.integer_types):
26+
raise ValueError("CumulativePointLong only supports integer types")
27+
if val > self.get_value():
28+
super(CumulativePointLong, self)._set(val)
29+
30+
def add(self, val):
31+
"""Add `val` to the current value if it's positive.
32+
33+
Return without adding if `val` is not positive.
34+
35+
:type val: int
36+
:param val: Value to add.
37+
"""
38+
if not isinstance(val, six.integer_types):
39+
raise ValueError("CumulativePointLong only supports integer types")
40+
if val > 0:
41+
super(CumulativePointLong, self).add(val)
42+
43+
44+
class CumulativePointDouble(gauge.GaugePointDouble):
45+
"""A `GaugePointDouble` that cannot decrease."""
46+
47+
def _set(self, val):
48+
if val > self.get_value():
49+
super(CumulativePointDouble, self)._set(val)
50+
51+
def add(self, val):
52+
"""Add `val` to the current value if it's positive.
53+
54+
Return without adding if `val` is not positive.
55+
56+
:type val: float
57+
:param val: Value to add.
58+
"""
59+
if val > 0:
60+
super(CumulativePointDouble, self).add(val)
61+
62+
63+
class LongCumulativeMixin(object):
64+
"""Type mixin for long-valued cumulative measures."""
65+
descriptor_type = metric_descriptor.MetricDescriptorType.CUMULATIVE_INT64
66+
point_type = CumulativePointLong
67+
68+
69+
class DoubleCumulativeMixin(object):
70+
"""Type mixin for float-valued cumulative measures."""
71+
descriptor_type = metric_descriptor.MetricDescriptorType.CUMULATIVE_DOUBLE
72+
point_type = CumulativePointDouble
73+
74+
75+
class LongCumulative(LongCumulativeMixin, gauge.Gauge):
76+
"""Records cumulative int-valued measurements."""
77+
78+
79+
class DoubleCumulative(DoubleCumulativeMixin, gauge.Gauge):
80+
"""Records cumulative float-valued measurements."""
81+
82+
83+
class DerivedLongCumulative(LongCumulativeMixin, gauge.DerivedGauge):
84+
"""Records derived cumulative int-valued measurements."""
85+
86+
87+
class DerivedDoubleCumulative(DoubleCumulativeMixin, gauge.DerivedGauge):
88+
"""Records derived cumulative float-valued measurements."""

opencensus/metrics/export/gauge.py

Lines changed: 46 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -88,16 +88,19 @@ def add(self, val):
8888
with self._value_lock:
8989
self.value += val
9090

91+
def _set(self, val):
92+
if not isinstance(val, six.integer_types):
93+
raise ValueError("GaugePointLong only supports integer types")
94+
with self._value_lock:
95+
self.value = val
96+
9197
def set(self, val):
9298
"""Set the current value to `val`.
9399
94100
:type val: int
95101
:param val: Value to set.
96102
"""
97-
if not isinstance(val, six.integer_types):
98-
raise ValueError("GaugePointLong only supports integer types")
99-
with self._value_lock:
100-
self.value = val
103+
self._set(val)
101104

102105
def get_value(self):
103106
"""Get the current value.
@@ -143,14 +146,17 @@ def add(self, val):
143146
with self._value_lock:
144147
self.value += val
145148

149+
def _set(self, val):
150+
with self._value_lock:
151+
self.value = float(val)
152+
146153
def set(self, val):
147154
"""Set the current value to `val`.
148155
149156
:type val: float
150157
:param val: Value to set.
151158
"""
152-
with self._value_lock:
153-
self.value = float(val)
159+
self._set(val)
154160

155161
def get_value(self):
156162
"""Get the current value.
@@ -180,7 +186,9 @@ class DerivedGaugePoint(GaugePoint):
180186
:type func: function
181187
:param func: The function to track.
182188
183-
:type gauge_point: :class:`GaugePointLong` or :class:`GaugePointDouble`
189+
:type gauge_point: :class:`GaugePointLong`, :class:`GaugePointDouble`,
190+
:class:`opencensus.metrics.export.cumulative.CumulativePointLong`, or
191+
:class:`opencensus.metrics.export.cumulative.CumulativePointDouble`
184192
:param gauge_point: The underlying `GaugePoint`.
185193
"""
186194
def __init__(self, func, gauge_point):
@@ -202,13 +210,14 @@ def get_value(self):
202210
203211
:rtype: int, float, or None
204212
:return: The current value of the wrapped function, or `None` if it no
205-
longer exists.
213+
longer exists.
206214
"""
207215
try:
208-
self.gauge_point.set(self.func()())
209-
# The underlying function has been GC'd
210-
except TypeError:
216+
val = self.func()()
217+
except TypeError: # The underlying function has been GC'd
211218
return None
219+
220+
self.gauge_point._set(val)
212221
return self.gauge_point.get_value()
213222

214223
def to_point_value(self):
@@ -218,9 +227,9 @@ def to_point_value(self):
218227
measurement as a side-effect.
219228
220229
:rtype: :class:`opencensus.metrics.export.value.ValueLong`,
221-
:class:`opencensus.metrics.export.value.ValueDouble`, or None
230+
:class:`opencensus.metrics.export.value.ValueDouble`, or None
222231
:return: The point value conversion of the underlying `GaugePoint`, or
223-
None if the tracked function no longer exists.
232+
None if the tracked function no longer exists.
224233
"""
225234
if self.get_value() is None:
226235
return None
@@ -309,7 +318,9 @@ def point_type(self): # pragma: NO COVER
309318
class Gauge(BaseGauge):
310319
"""A set of mutable, instantaneous measurements of the same type.
311320
312-
End users should use :class:`LongGauge` or :class:`DoubleGauge` instead of
321+
End users should use :class:`LongGauge`, :class:`DoubleGauge`,
322+
:class:`opencensus.metrics.export.cumulative.LongCumulative`, or
323+
:class:`opencensus.metrics.export.cumulative.DoubleCumulative` instead of
313324
using this class directly.
314325
315326
The constructor arguments are used to create a
@@ -328,9 +339,12 @@ def get_or_create_time_series(self, label_values):
328339
:type label_values: list(:class:`LabelValue`)
329340
:param label_values: The measurement's label values.
330341
331-
:rtype: :class:`GaugePointLong` or :class:`GaugePointDouble`
342+
:rtype: :class:`GaugePointLong`, :class:`GaugePointDouble`
343+
:class:`opencensus.metrics.export.cumulative.CumulativePointLong`,
344+
or
345+
:class:`opencensus.metrics.export.cumulative.CumulativePointDouble`
332346
:return: A mutable point that represents the last value of the
333-
measurement.
347+
measurement.
334348
"""
335349
if label_values is None:
336350
raise ValueError
@@ -347,9 +361,12 @@ def get_or_create_default_time_series(self):
347361
values. When this gauge is exported as a metric via `get_metric` the
348362
time series associated with this point will have null label values.
349363
350-
:rtype: :class:`GaugePointLong` or :class:`GaugePointDouble`
364+
:rtype: :class:`GaugePointLong`, :class:`GaugePointDouble`
365+
:class:`opencensus.metrics.export.cumulative.CumulativePointLong`,
366+
or
367+
:class:`opencensus.metrics.export.cumulative.CumulativePointDouble`
351368
:return: A mutable point that represents the last value of the
352-
measurement.
369+
measurement.
353370
"""
354371
return self._get_or_create_time_series(self.default_label_values)
355372

@@ -380,8 +397,10 @@ class DerivedGauge(BaseGauge):
380397
Each of a `DerivedGauge`'s measurements are associated with a function
381398
which is called when the gauge is exported.
382399
383-
End users should use :class:`DerivedLongGauge` or
384-
:class:`DerivedDoubleGauge` instead of using this class directly.
400+
End users should use :class:`DerivedLongGauge`, :class:`DerivedDoubleGauge`
401+
:class:`opencensus.metrics.export.cumulative.DerivedLongCumulative`, or
402+
:class:`opencensus.metrics.export.cumulative.DerivedDoubleCumulative`
403+
instead of using this class directly.
385404
"""
386405

387406
def _create_time_series(self, label_values, func):
@@ -452,18 +471,19 @@ def __repr__(self):
452471
))
453472

454473
def add_gauge(self, gauge):
455-
"""Add `gauge` to the registry and return it.
474+
"""Add `gauge` to the registry.
456475
457476
Raises a `ValueError` if another gauge with the same name already
458477
exists in the registry.
459478
460479
:type gauge: class:`LongGauge`, class:`DoubleGauge`,
461-
:class:`DerivedLongGauge`, or :class:`DerivedDoubleGauge`
480+
:class:`opencensus.metrics.export.cumulative.LongCumulative`,
481+
:class:`opencensus.metrics.export.cumulative.DoubleCumulative`,
482+
:class:`DerivedLongGauge`, :class:`DerivedDoubleGauge`
483+
:class:`opencensus.metrics.export.cumulative.DerivedLongCumulative`,
484+
or
485+
:class:`opencensus.metrics.export.cumulative.DerivedDoubleCumulative`
462486
:param gauge: The gauge to add to the registry.
463-
464-
:type gauge: class:`LongGauge`, class:`DoubleGauge`,
465-
:class:`DerivedLongGauge`, or :class:`DerivedDoubleGauge`
466-
:return: The gauge that was added to the registry.
467487
"""
468488
if gauge is None:
469489
raise ValueError

0 commit comments

Comments
 (0)