Skip to content

Commit

Permalink
Metrics API with RFC 0003 (#87)
Browse files Browse the repository at this point in the history
* Create functions

Comments for Meter

More comments

Add more comments

Fix typos

* fix lint

* Fix lint

* fix typing

* Remove options, constructors, seperate labels

* Consistent naming for float and int

* Abstract time series

* Use ABC

* Fix typo

* Fix docs

* seperate measure classes

* Add examples

* fix lint

* Update to RFC 0003

* Add spancontext, measurebatch

* Fix docs

* Fix comments

* fix lint

* fix lint

* fix lint

* skip examples

* white space

* fix spacing

* fix imports

* fix imports

* LabelValues to str

* Black formatting

* fix isort

* Remove aggregation

* Fix names

* Remove aggregation from docs

* Fix lint
  • Loading branch information
lzchen authored Sep 12, 2019
1 parent 5ca9e06 commit fb11568
Show file tree
Hide file tree
Showing 7 changed files with 444 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ abstract types for OpenTelemetry implementations.

opentelemetry.context
opentelemetry.loader
opentelemetry.metrics
opentelemetry.trace


Expand Down
14 changes: 14 additions & 0 deletions docs/opentelemetry.metrics.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
opentelemetry.metrics package
=============================

Submodules
----------

.. toctree::

opentelemetry.metrics.time_series

Module contents
---------------

.. automodule:: opentelemetry.metrics
5 changes: 5 additions & 0 deletions docs/opentelemetry.metrics.time_series.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
opentelemetry.metrics.time\_series module
==========================================

.. automodule:: opentelemetry.metrics.time_series

304 changes: 304 additions & 0 deletions opentelemetry-api/src/opentelemetry/metrics/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,307 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
The OpenTelemetry metrics API describes the classes used to report raw
measurements, as well as metrics with known aggregation and labels.
The `Meter` class is used to construct `Metric` s to record raw statistics
as well as metrics with predefined aggregation.
See the `metrics api`_ spec for terminology and context clarification.
.. _metrics api:
https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/api-metrics.md
"""

from abc import ABC, abstractmethod
from typing import List

from opentelemetry.metrics.time_series import (
CounterTimeSeries,
GaugeTimeSeries,
MeasureTimeSeries,
)
from opentelemetry.trace import SpanContext

LabelKeys = List["LabelKey"]
LabelValues = List[str]


class Meter:
"""An interface to allow the recording of metrics.
`Metric` s are used for recording pre-defined aggregation (gauge and
counter), or raw values (measure) in which the aggregation and labels
for the exported metric are deferred.
"""

def create_float_counter(
self,
name: str,
description: str,
unit: str,
label_keys: LabelKeys,
span_context: SpanContext = None,
) -> "FloatCounter":
"""Creates a counter type metric that contains float values.
Args:
name: The name of the counter.
description: Human readable description of the metric.
unit: Unit of the metric values.
label_keys: list of keys for the labels with dynamic values.
Order of the list is important as the same order MUST be used
on recording when suppling values for these labels.
span_context: The `SpanContext` that identifies the `Span`
that the metric is associated with.
Returns: A new `FloatCounter`
"""

def create_int_counter(
self,
name: str,
description: str,
unit: str,
label_keys: LabelKeys,
span_context: SpanContext = None,
) -> "IntCounter":
"""Creates a counter type metric that contains int values.
Args:
name: The name of the counter.
description: Human readable description of the metric.
unit: Unit of the metric values.
label_keys: list of keys for the labels with dynamic values.
Order of the list is important as the same order MUST be used
on recording when suppling values for these labels.
span_context: The `SpanContext` that identifies the `Span`
that the metric is associated with.
Returns:
A new `IntCounter`
"""

def create_float_gauge(
self,
name: str,
description: str,
unit: str,
label_keys: LabelKeys,
span_context: SpanContext = None,
) -> "FloatGauge":
"""Creates a gauge type metric that contains float values.
Args:
name: The name of the counter.
description: Human readable description of the metric.
unit: Unit of the metric values.
label_keys: list of keys for the labels with dynamic values.
Order of the list is important as the same order MUST be used
on recording when suppling values for these labels.
span_context: The `SpanContext` that identifies the `Span`
that the metric is associated with.
Returns:
A new `FloatGauge`
"""

def create_int_gauge(
self,
name: str,
description: str,
unit: str,
label_keys: LabelKeys,
span_context: SpanContext = None,
) -> "IntGauge":
"""Creates a gauge type metric that contains int values.
Args:
name: The name of the counter.
description: Human readable description of the metric.
unit: Unit of the metric values.
label_keys: list of keys for the labels with dynamic values.
Order of the list is important as the same order MUST be used
on recording when suppling values for these labels.
span_context: The `SpanContext` that identifies the `Span`
that the metric is associated with.
Returns:
A new `IntGauge`
"""

def create_int_measure(
self,
name: str,
description: str,
unit: str,
label_keys: LabelKeys,
span_context: SpanContext = None,
) -> "IntMeasure":
"""Creates a measure used to record raw int values.
Args:
name: The name of the measure.
description: Human readable description of this measure.
unit: Unit of the measure values.
label_keys: list of keys for the labels with dynamic values.
Order of the list is important as the same order MUST be used
on recording when suppling values for these labels.
span_context: The `SpanContext` that identifies the `Span`
that the metric is associated with.
Returns:
A new `IntMeasure`
"""

def create_float_measure(
self,
name: str,
description: str,
unit: str,
label_keys: LabelKeys,
span_context: SpanContext = None,
) -> "FloatMeasure":
"""Creates a Measure used to record raw float values.
Args:
name: the name of the measure
description: Human readable description of this measure.
unit: Unit of the measure values.
label_keys: list of keys for the labels with dynamic values.
Order of the list is important as the same order MUST be used
on recording when suppling values for these labels.
span_context: The `SpanContext` that identifies the `Span`
that the metric is associated with.
Returns:
A new `FloatMeasure`
"""


class Metric(ABC):
"""Base class for various types of metrics.
Metric class that inherit from this class are specialized with the type of
time series that the metric holds. Metric is constructed from the meter.
"""

@abstractmethod
def get_or_create_time_series(self, label_values: LabelValues) -> "object":
"""Gets and returns a timeseries, a container for a cumulative value.
If the provided label values are not already associated with this
metric, a new timeseries is returned, otherwise it returns the existing
timeseries with the exact label values. The timeseries returned
contains logic and behaviour specific to the type of metric that
overrides this function.
Args:
label_values: A list of label values that will be associated
with the return timeseries.
"""

def remove_time_series(self, label_values: LabelValues) -> None:
"""Removes the timeseries from the Metric, if present.
The timeseries with matching label values will be removed.
args:
label_values: The list of label values to match against.
"""

def clear(self) -> None:
"""Removes all timeseries from the `Metric`."""


class FloatCounter(Metric):
"""A counter type metric that holds float values.
Cumulative values can go up or stay the same, but can never go down.
Cumulative values cannot be negative.
"""

def get_or_create_time_series(
self, label_values: LabelValues
) -> "CounterTimeSeries":
"""Gets a `CounterTimeSeries` with a cumulative float value."""


class IntCounter(Metric):
"""A counter type metric that holds int values.
Cumulative values can go up or stay the same, but can never go down.
Cumulative values cannot be negative.
"""

def get_or_create_time_series(
self, label_values: LabelValues
) -> "CounterTimeSeries":
"""Gets a `CounterTimeSeries` with a cumulative int value."""


class FloatGauge(Metric):
"""A gauge type metric that holds float values.
Cumulative value can go both up and down. Values can be negative.
"""

def get_or_create_time_series(
self, label_values: LabelValues
) -> "GaugeTimeSeries":
"""Gets a `GaugeTimeSeries` with a cumulative float value."""


class IntGauge(Metric):
"""A gauge type metric that holds int values.
Cumulative value can go both up and down. Values can be negative.
"""

def get_or_create_time_series(
self, label_values: LabelValues
) -> "GaugeTimeSeries":
"""Gets a `GaugeTimeSeries` with a cumulative int value."""


class FloatMeasure(Metric):
"""A measure type metric that holds float values.
Measure metrics represent raw statistics that are recorded.
"""

def get_or_create_time_series(
self, label_values: LabelValues
) -> "MeasureTimeSeries":
"""Gets a `MeasureTimeSeries` with a cumulated float value."""


class IntMeasure(Metric):
"""A measure type metric that holds int values.
Measure metrics represent raw statistics that are recorded.
"""

def get_or_create_time_series(
self, label_values: LabelValues
) -> "MeasureTimeSeries":
"""Gets a `MeasureTimeSeries` with a cumulated int value."""


class LabelKey:
"""The label keys associated with the metric.
:type key: str
:param key: the key for the label
:type description: str
:param description: description of the label
"""

def __init__(self, key: str, description: str) -> None:
self.key = key
self.description = description
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Copyright 2019, OpenTelemetry Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# pylint: skip-file
from opentelemetry.metrics import LabelKey, LabelValue, Meter

METER = Meter()
LABEL_KEYS = [
LabelKey("environment", "the environment the application is running in")
]
COUNTER = METER.create_int_counter(
"sum numbers", # pragma: no cover
"sum numbers over time",
"number",
LABEL_KEYS,
)
LABEL_VALUE_TESTING = [LabelValue("Testing")]
LABEL_VALUE_STAGING = [LabelValue("Staging")]

# Metrics sent to some exporter
METRIC_TESTING = COUNTER.get_or_create_time_series(LABEL_VALUE_TESTING)
METRIC_STAGING = COUNTER.get_or_create_time_series(LABEL_VALUE_STAGING)

for i in range(100):
METRIC_STAGING.add(i)
Loading

0 comments on commit fb11568

Please sign in to comment.