Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cumulative gauges #626

Merged
merged 13 commits into from
Apr 23, 2019
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

- Add cumulative API
([#626](https://github.com/census-instrumentation/opencensus-python/pull/626))

## 0.4.0
Released 2019-04-08

Expand Down
125 changes: 107 additions & 18 deletions opencensus/metrics/export/gauge.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,64 @@ def to_point_value(self):
return value_module.ValueDouble(self.value)


class CumulativePointLong(GaugePointLong):
"""A `GaugePointLong` that cannot decrease."""
c24t marked this conversation as resolved.
Show resolved Hide resolved

def set(self, val):
"""Set the current value to `val`

Return without changing the value if `val` is not greater than the
c24t marked this conversation as resolved.
Show resolved Hide resolved
current value.

:type val: int
:param val: Value to set.
"""
if not isinstance(val, six.integer_types):
raise ValueError("CumulativePointLong only supports integer types")
if val > self.get_value():
super(CumulativePointLong, self).set(val)

def add(self, val):
"""Add `val` to the current value if it's positive.

Return without adding if `val` is not positive.

:type val: int
:param val: Value to add.
"""
if not isinstance(val, six.integer_types):
raise ValueError("CumulativePointLong only supports integer types")
if val > 0:
super(CumulativePointLong, self).add(val)


class CumulativePointDouble(GaugePointDouble):
"""A `GaugePointDouble` that cannot decrease."""

def set(self, val):
"""Set the current value to `val`

Return without changing the value if `val` is not greater than the
current value.

:type val: float
:param val: Value to set.
"""
if val > self.get_value():
super(CumulativePointDouble, self).set(val)

def add(self, val):
"""Add `val` to the current value if it's positive.

Return without adding if `val` is not positive.

:type val: float
:param val: Value to add.
"""
if val > 0:
super(CumulativePointDouble, self).add(val)


class DerivedGaugePoint(GaugePoint):
"""Wraps a `GaugePoint` to automatically track the value of a function.

Expand All @@ -180,7 +238,8 @@ class DerivedGaugePoint(GaugePoint):
:type func: function
:param func: The function to track.

:type gauge_point: :class:`GaugePointLong` or :class:`GaugePointDouble`
:type gauge_point: :class:`GaugePointLong`, :class:`GaugePointDouble`,
:class:`CumulativePointLong`, or :class:`CumulativePointDouble`
:param gauge_point: The underlying `GaugePoint`.
"""
def __init__(self, func, gauge_point):
Expand All @@ -202,7 +261,7 @@ def get_value(self):

:rtype: int, float, or None
:return: The current value of the wrapped function, or `None` if it no
longer exists.
longer exists.
"""
try:
self.gauge_point.set(self.func()())
Expand All @@ -218,9 +277,9 @@ def to_point_value(self):
measurement as a side-effect.

:rtype: :class:`opencensus.metrics.export.value.ValueLong`,
:class:`opencensus.metrics.export.value.ValueDouble`, or None
:class:`opencensus.metrics.export.value.ValueDouble`, or None
:return: The point value conversion of the underlying `GaugePoint`, or
None if the tracked function no longer exists.
None if the tracked function no longer exists.
"""
if self.get_value() is None:
return None
Expand Down Expand Up @@ -309,8 +368,9 @@ def point_type(self): # pragma: NO COVER
class Gauge(BaseGauge):
"""A set of mutable, instantaneous measurements of the same type.

End users should use :class:`LongGauge` or :class:`DoubleGauge` instead of
using this class directly.
End users should use :class:`LongGauge`, :class:`DoubleGauge`,
:class:`LongCumulative`, or :class:`DoubleCumulative` instead of using
c24t marked this conversation as resolved.
Show resolved Hide resolved
this class directly.

The constructor arguments are used to create a
:class:`opencensus.metrics.export.metric_descriptor.MetricDescriptor` for
Expand All @@ -328,9 +388,10 @@ def get_or_create_time_series(self, label_values):
:type label_values: list(:class:`LabelValue`)
:param label_values: The measurement's label values.

:rtype: :class:`GaugePointLong` or :class:`GaugePointDouble`
:rtype: :class:`GaugePointLong`, :class:`GaugePointDouble`
:class:`CumulativePointLong`, or :class:`CumulativePointDouble`
:return: A mutable point that represents the last value of the
measurement.
measurement.
"""
if label_values is None:
raise ValueError
Expand All @@ -347,9 +408,10 @@ def get_or_create_default_time_series(self):
values. When this gauge is exported as a metric via `get_metric` the
time series associated with this point will have null label values.

:rtype: :class:`GaugePointLong` or :class:`GaugePointDouble`
:rtype: :class:`GaugePointLong`, :class:`GaugePointDouble`
:class:`CumulativePointLong`, or :class:`CumulativePointDouble`
:return: A mutable point that represents the last value of the
measurement.
measurement.
"""
return self._get_or_create_time_series(self.default_label_values)

Expand All @@ -374,14 +436,35 @@ class DoubleGauge(DoubleGaugeMixin, Gauge):
"""Gauge for recording float-valued measurements."""


class LongCumulativeMixin(object):
"""Type mixin for long-valued cumulative measures."""
descriptor_type = metric_descriptor.MetricDescriptorType.CUMULATIVE_INT64
point_type = CumulativePointLong


class DoubleCumulativeMixin(object):
"""Type mixin for float-valued cumulative measures."""
descriptor_type = metric_descriptor.MetricDescriptorType.CUMULATIVE_DOUBLE
point_type = CumulativePointDouble


class LongCumulative(LongCumulativeMixin, Gauge):
"""Records cumulative int-valued measurements."""


class DoubleCumulative(DoubleCumulativeMixin, Gauge):
"""Records cumulative float-valued measurements."""


class DerivedGauge(BaseGauge):
"""Gauge that tracks values of other functions.

Each of a `DerivedGauge`'s measurements are associated with a function
which is called when the gauge is exported.

End users should use :class:`DerivedLongGauge` or
:class:`DerivedDoubleGauge` instead of using this class directly.
End users should use :class:`DerivedLongGauge`, :class:`DerivedDoubleGauge`
:class:`DerivedLongCumulative`, or :class:`DerivedDoubleCumulative` instead
of using this class directly.
"""

def _create_time_series(self, label_values, func):
Expand Down Expand Up @@ -434,6 +517,14 @@ class DerivedDoubleGauge(DoubleGaugeMixin, DerivedGauge):
"""Gauge for derived float-valued measurements."""


class DerivedLongCumulative(LongCumulativeMixin, DerivedGauge):
"""Records derived cumulative int-valued measurements."""


class DerivedDoubleCumulative(DoubleCumulativeMixin, DerivedGauge):
"""Records derived cumulative float-valued measurements."""


class Registry(metric_producer.MetricProducer):
"""A collection of gauges to be exported together.

Expand All @@ -452,18 +543,16 @@ def __repr__(self):
))

def add_gauge(self, gauge):
"""Add `gauge` to the registry and return it.
"""Add `gauge` to the registry.

Raises a `ValueError` if another gauge with the same name already
exists in the registry.

:type gauge: class:`LongGauge`, class:`DoubleGauge`,
:class:`DerivedLongGauge`, or :class:`DerivedDoubleGauge`
:class:`LongCumulative`, :class:`DoubleCumulative`,
:class:`DerivedLongGauge`, :class:`DerivedDoubleGauge`
:class:`DerivedLongCumulative`, or :class:`DerivedDoubleCumulative`
:param gauge: The gauge to add to the registry.

:type gauge: class:`LongGauge`, class:`DoubleGauge`,
:class:`DerivedLongGauge`, or :class:`DerivedDoubleGauge`
:return: The gauge that was added to the registry.
"""
if gauge is None:
raise ValueError
Expand Down