-
Notifications
You must be signed in to change notification settings - Fork 667
/
Copy path__init__.py
322 lines (235 loc) · 10.1 KB
/
__init__.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
# 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.
"""
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
"""
import abc
from typing import Callable, Dict, Optional, Sequence, Tuple, Type, TypeVar
from opentelemetry.util import loader
ValueT = TypeVar("ValueT", int, float)
class DefaultMetricHandle:
"""The default MetricHandle.
Used when no MetricHandle implementation is available.
"""
class CounterHandle:
def add(self, value: ValueT) -> None:
"""Increases the value of the handle by ``value``.
Args:
value: The value to record to the handle.
"""
class GaugeHandle:
def set(self, value: ValueT) -> None:
"""Sets the current value of the handle to ``value``.
Args:
value: The value to record to the handle.
"""
class MeasureHandle:
def record(self, value: ValueT) -> None:
"""Records the given ``value`` to this handle.
Args:
value: The value to record to the handle.
"""
class LabelSet(abc.ABC):
"""A canonicalized set of labels useful for preaggregation
Re-usable LabelSet objects provide a potential optimization for scenarios
where handles might not be effective. For example, if the LabelSet will be
re-used but only used once per metrics, handles do not offer any
optimization. It may best to pre-compute a canonicalized LabelSet once and
re-use it with the direct calling convention. LabelSets are immutable and
should be opaque in implementation.
"""
class DefaultLabelSet(LabelSet):
"""The default LabelSet.
Used when no LabelSet implementation is available.
"""
class Metric(abc.ABC):
"""Base class for various types of metrics.
Metric class that inherit from this class are specialized with the type of
handle that the metric holds.
"""
@abc.abstractmethod
def get_handle(self, label_set: LabelSet) -> "object":
"""Gets a handle, used for repeated-use of metrics instruments.
Handles are useful to reduce the cost of repeatedly recording a metric
with a pre-defined set of label values. All metric kinds (counter,
gauge, measure) support declaring a set of required label keys. The
values corresponding to these keys should be specified in every handle.
"Unspecified" label values, in cases where a handle is requested but
a value was not provided are permitted.
Args:
label_set: `LabelSet` to associate with the returned handle.
"""
class DefaultMetric(Metric):
"""The default Metric used when no Metric implementation is available."""
def get_handle(self, label_set: LabelSet) -> "DefaultMetricHandle":
"""Gets a `DefaultMetricHandle`.
Args:
label_set: `LabelSet` to associate with the returned handle.
"""
return DefaultMetricHandle()
class Counter(Metric):
"""A counter type metric that expresses the computation of a sum."""
def get_handle(self, label_set: LabelSet) -> "CounterHandle":
"""Gets a `CounterHandle`."""
return CounterHandle()
def add(self, label_set: LabelSet, value: ValueT) -> None:
"""Increases the value of the counter by ``value``.
Args:
label_set: `LabelSet` to associate with the returned handle.
value: The value to add to the counter metric.
"""
class Gauge(Metric):
"""A gauge type metric that expresses a pre-calculated value.
Gauge metrics have a value that is either ``Set`` by explicit
instrumentation or observed through a callback. This kind of metric
should be used when the metric cannot be expressed as a sum or because
the measurement interval is arbitrary.
"""
def get_handle(self, label_set: LabelSet) -> "GaugeHandle":
"""Gets a `GaugeHandle`."""
return GaugeHandle()
def set(self, label_set: LabelSet, value: ValueT) -> None:
"""Sets the value of the gauge to ``value``.
Args:
label_set: `LabelSet` to associate with the returned handle.
value: The value to set the gauge metric to.
"""
class Measure(Metric):
"""A measure type metric that represent raw stats that are recorded.
Measure metrics represent raw statistics that are recorded. By
default, measure metrics can accept both positive and negatives.
Negative inputs will be discarded when monotonic is True.
"""
def get_handle(self, label_set: LabelSet) -> "MeasureHandle":
"""Gets a `MeasureHandle` with a float value."""
return MeasureHandle()
def record(self, label_set: LabelSet, value: ValueT) -> None:
"""Records the ``value`` to the measure.
Args:
label_set: `LabelSet` to associate with the returned handle.
value: The value to record to this measure metric.
"""
MetricT = TypeVar("MetricT", Counter, Gauge, Measure)
# pylint: disable=unused-argument
class Meter(abc.ABC):
"""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.
"""
@abc.abstractmethod
def record_batch(
self,
label_set: LabelSet,
record_tuples: Sequence[Tuple["Metric", ValueT]],
) -> None:
"""Atomically records a batch of `Metric` and value pairs.
Allows the functionality of acting upon multiple metrics with
a single API call. Implementations should find metric and handles that
match the key-value pairs in the label tuples.
Args:
label_set: The `LabelSet` associated with all measurements in
the batch. A measurement is a tuple, representing the `Metric`
being recorded and the corresponding value to record.
record_tuples: A sequence of pairs of `Metric` s and the
corresponding value to record for that metric.
"""
@abc.abstractmethod
def create_metric(
self,
name: str,
description: str,
unit: str,
value_type: Type[ValueT],
metric_type: Type[MetricT],
label_keys: Sequence[str] = (),
enabled: bool = True,
monotonic: bool = False,
) -> "Metric":
"""Creates a ``metric_kind`` metric with type ``value_type``.
Args:
name: The name of the metric.
description: Human-readable description of the metric.
unit: Unit of the metric values.
value_type: The type of values being recorded by the metric.
metric_type: The type of metric being created.
label_keys: The keys for the labels with dynamic values.
enabled: Whether to report the metric by default.
monotonic: Whether to only allow non-negative values.
Returns: A new ``metric_type`` metric with values of ``value_type``.
"""
@abc.abstractmethod
def get_label_set(self, labels: Dict[str, str]) -> "LabelSet":
"""Gets a `LabelSet` with the given labels.
Args:
labels: A dictionary representing label key to label value pairs.
Returns: A `LabelSet` object canonicalized using the given input.
"""
class DefaultMeter(Meter):
"""The default Meter used when no Meter implementation is available."""
def record_batch(
self,
label_set: LabelSet,
record_tuples: Sequence[Tuple["Metric", ValueT]],
) -> None:
pass
def create_metric(
self,
name: str,
description: str,
unit: str,
value_type: Type[ValueT],
metric_type: Type[MetricT],
label_keys: Sequence[str] = (),
enabled: bool = True,
monotonic: bool = False,
) -> "Metric":
# pylint: disable=no-self-use
return DefaultMetric()
def get_label_set(self, labels: Dict[str, str]) -> "LabelSet":
# pylint: disable=no-self-use
return DefaultLabelSet()
# Once https://github.com/python/mypy/issues/7092 is resolved,
# the following type definition should be replaced with
# from opentelemetry.util.loader import ImplementationFactory
ImplementationFactory = Callable[[Type[Meter]], Optional[Meter]]
_METER = None
_METER_FACTORY = None
def meter() -> Meter:
"""Gets the current global :class:`~.Meter` object.
If there isn't one set yet, a default will be loaded.
"""
global _METER, _METER_FACTORY # pylint:disable=global-statement
if _METER is None:
# pylint:disable=protected-access
_METER = loader._load_impl(DefaultMeter, _METER_FACTORY)
del _METER_FACTORY
return _METER
def set_preferred_meter_implementation(factory: ImplementationFactory) -> None:
"""Set the factory to be used to create the meter.
See :mod:`opentelemetry.util.loader` for details.
This function may not be called after a meter is already loaded.
Args:
factory: Callback that should create a new :class:`Meter` instance.
"""
global _METER, _METER_FACTORY # pylint:disable=global-statement
if _METER:
raise RuntimeError("Meter already loaded.")
_METER_FACTORY = factory