Skip to content

Commit 242d5a7

Browse files
authored
[WIP] Views API Prototype (#596)
1 parent 1112792 commit 242d5a7

File tree

17 files changed

+910
-501
lines changed

17 files changed

+910
-501
lines changed

docs/examples/basic_meter/basic_metrics.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
- How to configure a meter passing a sateful or stateless.
2020
- How to configure an exporter and how to create a controller.
2121
- How to create some metrics intruments and how to capture data with them.
22+
- How to use views to specify aggregation types for each metric instrument.
2223
"""
2324
import sys
2425
import time
@@ -57,7 +58,6 @@
5758
unit="1",
5859
value_type=int,
5960
metric_type=Counter,
60-
label_keys=("environment",),
6161
)
6262

6363
requests_size = meter.create_metric(
@@ -66,7 +66,6 @@
6666
unit="1",
6767
value_type=int,
6868
metric_type=ValueRecorder,
69-
label_keys=("environment",),
7069
)
7170

7271
# Labels are used to identify key-values that are associated with a specific
@@ -86,4 +85,5 @@
8685

8786
requests_counter.add(35, testing_labels)
8887
requests_size.record(2, testing_labels)
89-
time.sleep(5)
88+
89+
input("...\n")

docs/examples/basic_meter/calling_conventions.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
unit="1",
3434
value_type=int,
3535
metric_type=Counter,
36-
label_keys=("environment",),
3736
)
3837

3938
requests_size = meter.create_metric(
@@ -42,7 +41,6 @@
4241
unit="1",
4342
value_type=int,
4443
metric_type=ValueRecorder,
45-
label_keys=("environment",),
4644
)
4745

4846
clicks_counter = meter.create_metric(
@@ -51,7 +49,6 @@
5149
unit="1",
5250
value_type=int,
5351
metric_type=Counter,
54-
label_keys=("environment",),
5552
)
5653

5754
labels = {"environment": "staging"}
@@ -78,3 +75,5 @@
7875
# specified labels for each.
7976
meter.record_batch(labels, ((requests_counter, 50), (clicks_counter, 70)))
8077
time.sleep(5)
78+
79+
input("...\n")

docs/examples/basic_meter/observer.py

-2
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ def get_cpu_usage_callback(observer):
4141
unit="1",
4242
value_type=float,
4343
observer_type=ValueObserver,
44-
label_keys=("cpu_number",),
4544
)
4645

4746

@@ -58,7 +57,6 @@ def get_ram_usage_callback(observer):
5857
unit="1",
5958
value_type=float,
6059
observer_type=ValueObserver,
61-
label_keys=(),
6260
)
6361

6462
input("Metrics will be printed soon. Press a key to finish...\n")

docs/examples/basic_meter/view.py

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# Copyright The OpenTelemetry 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+
"""
16+
This example shows how to use the different modes to capture metrics.
17+
It shows the usage of the direct, bound and batch calling conventions.
18+
"""
19+
from opentelemetry import metrics
20+
from opentelemetry.sdk.metrics import (
21+
MeterProvider,
22+
UpDownCounter,
23+
ValueRecorder,
24+
)
25+
from opentelemetry.sdk.metrics.export import ConsoleMetricsExporter
26+
from opentelemetry.sdk.metrics.export.aggregate import (
27+
HistogramAggregator,
28+
LastValueAggregator,
29+
MinMaxSumCountAggregator,
30+
SumAggregator,
31+
)
32+
from opentelemetry.sdk.metrics.view import View, ViewConfig
33+
34+
# Use the meter type provided by the SDK package
35+
metrics.set_meter_provider(MeterProvider())
36+
meter = metrics.get_meter(__name__)
37+
metrics.get_meter_provider().start_pipeline(meter, ConsoleMetricsExporter(), 5)
38+
39+
requests_counter = meter.create_metric(
40+
name="requests",
41+
description="number of requests",
42+
unit="1",
43+
value_type=int,
44+
metric_type=UpDownCounter,
45+
)
46+
47+
requests_size = meter.create_metric(
48+
name="requests_size",
49+
description="size of requests",
50+
unit="1",
51+
value_type=int,
52+
metric_type=ValueRecorder,
53+
)
54+
55+
# Views are used to define an aggregation type and label keys to aggregate by
56+
# for a given metric
57+
58+
# Two views with the same metric and aggregation type but different label keys
59+
# With ViewConfig.LABEL_KEYS, all labels but the ones defined in label_keys are
60+
# dropped from the aggregation
61+
counter_view1 = View(
62+
requests_counter,
63+
SumAggregator,
64+
label_keys=["environment"],
65+
view_config=ViewConfig.LABEL_KEYS,
66+
)
67+
counter_view2 = View(
68+
requests_counter,
69+
MinMaxSumCountAggregator,
70+
label_keys=["os_type"],
71+
view_config=ViewConfig.LABEL_KEYS,
72+
)
73+
# This view has ViewConfig set to UNGROUPED, meaning all recorded metrics take
74+
# the labels directly without and consideration for label_keys
75+
counter_view3 = View(
76+
requests_counter,
77+
LastValueAggregator,
78+
label_keys=["environment"], # is not used due to ViewConfig.UNGROUPED
79+
view_config=ViewConfig.UNGROUPED,
80+
)
81+
# This view uses the HistogramAggregator which accepts an option config
82+
# parameter to specify the bucket ranges
83+
size_view = View(
84+
requests_size,
85+
HistogramAggregator,
86+
label_keys=["environment"], # is not used due to ViewConfig.UNGROUPED
87+
aggregator_config={"bounds": [20, 40, 60, 80, 100]},
88+
view_config=ViewConfig.UNGROUPED,
89+
)
90+
91+
# Register the views to the view manager to use the views. Views MUST be
92+
# registered before recording metrics. Metrics that are recorded without
93+
# views defined for them will use a default for that type of metric
94+
meter.register_view(counter_view1)
95+
meter.register_view(counter_view2)
96+
meter.register_view(counter_view3)
97+
meter.register_view(size_view)
98+
99+
# The views will evaluate the labels passed into the record and aggregate upon
100+
# the unique labels that are generated
101+
# view1 labels will evaluate to {"environment": "staging"}
102+
# view2 labels will evaluate to {"os_type": linux}
103+
# view3 labels will evaluate to {"environment": "staging", "os_type": "linux"}
104+
requests_counter.add(100, {"environment": "staging", "os_type": "linux"})
105+
106+
# Since this is using the HistogramAggregator, the bucket counts will be reflected
107+
# with each record
108+
requests_size.record(25, {"test": "value"})
109+
requests_size.record(-3, {"test": "value"})
110+
requests_size.record(200, {"test": "value"})
111+
112+
input("...\n")

exporter/opentelemetry-exporter-opencensus/tests/test_otcollector_metrics_exporter.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
Counter,
2626
MeterProvider,
2727
ValueRecorder,
28-
get_labels_as_key,
28+
get_dict_as_key,
2929
)
3030
from opentelemetry.sdk.metrics.export import (
3131
MetricRecord,
@@ -42,7 +42,7 @@ def setUpClass(cls):
4242
metrics.set_meter_provider(MeterProvider())
4343
cls._meter = metrics.get_meter(__name__)
4444
cls._labels = {"environment": "staging"}
45-
cls._key_labels = get_labels_as_key(cls._labels)
45+
cls._key_labels = get_dict_as_key(cls._labels)
4646

4747
def test_constructor(self):
4848
mock_get_node = mock.Mock()
@@ -119,7 +119,7 @@ def test_export(self):
119119
client=mock_client, host_name=host_name
120120
)
121121
test_metric = self._meter.create_metric(
122-
"testname", "testdesc", "unit", int, Counter, ["environment"]
122+
"testname", "testdesc", "unit", int, Counter,
123123
)
124124
record = MetricRecord(
125125
test_metric, self._key_labels, aggregate.SumAggregator(),
@@ -142,7 +142,7 @@ def test_export(self):
142142

143143
def test_translate_to_collector(self):
144144
test_metric = self._meter.create_metric(
145-
"testname", "testdesc", "unit", int, Counter, ["environment"]
145+
"testname", "testdesc", "unit", int, Counter,
146146
)
147147
aggregator = aggregate.SumAggregator()
148148
aggregator.update(123)

exporter/opentelemetry-exporter-prometheus/tests/test_prometheus_exporter.py

+6-23
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,10 @@ def setUp(self):
3232
set_meter_provider(metrics.MeterProvider())
3333
self._meter = get_meter_provider().get_meter(__name__)
3434
self._test_metric = self._meter.create_metric(
35-
"testname",
36-
"testdesc",
37-
"unit",
38-
int,
39-
metrics.Counter,
40-
["environment"],
35+
"testname", "testdesc", "unit", int, metrics.Counter,
4136
)
4237
labels = {"environment": "staging"}
43-
self._labels_key = metrics.get_labels_as_key(labels)
38+
self._labels_key = metrics.get_dict_as_key(labels)
4439

4540
self._mock_registry_register = mock.Mock()
4641
self._registry_register_patch = mock.patch(
@@ -78,15 +73,10 @@ def test_export(self):
7873
def test_counter_to_prometheus(self):
7974
meter = get_meter_provider().get_meter(__name__)
8075
metric = meter.create_metric(
81-
"test@name",
82-
"testdesc",
83-
"unit",
84-
int,
85-
metrics.Counter,
86-
["environment@", "os"],
76+
"test@name", "testdesc", "unit", int, metrics.Counter,
8777
)
8878
labels = {"environment@": "staging", "os": "Windows"}
89-
key_labels = metrics.get_labels_as_key(labels)
79+
key_labels = metrics.get_dict_as_key(labels)
9080
aggregator = SumAggregator()
9181
aggregator.update(123)
9282
aggregator.take_checkpoint()
@@ -117,7 +107,7 @@ def test_invalid_metric(self):
117107
"tesname", "testdesc", "unit", int, StubMetric
118108
)
119109
labels = {"environment": "staging"}
120-
key_labels = metrics.get_labels_as_key(labels)
110+
key_labels = metrics.get_dict_as_key(labels)
121111
record = MetricRecord(metric, key_labels, None)
122112
collector = CustomCollector("testprefix")
123113
collector.add_metrics_data([record])
@@ -143,15 +133,8 @@ def __init__(
143133
unit: str,
144134
value_type,
145135
meter,
146-
label_keys,
147136
enabled: bool = True,
148137
):
149138
super().__init__(
150-
name,
151-
description,
152-
unit,
153-
value_type,
154-
meter,
155-
label_keys=label_keys,
156-
enabled=enabled,
139+
name, description, unit, value_type, meter, enabled=enabled,
157140
)

ext/opentelemetry-ext-grpc/src/opentelemetry/ext/grpc/_utilities.py

-5
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ def __init__(self, meter, span_kind):
4545
self._meter = meter
4646
service_name = "grpcio"
4747
self._span_kind = span_kind
48-
base_attributes = ["method"]
4948

5049
if self._meter:
5150
self._duration = self._meter.create_metric(
@@ -54,31 +53,27 @@ def __init__(self, meter, span_kind):
5453
unit="ms",
5554
value_type=float,
5655
metric_type=ValueRecorder,
57-
label_keys=base_attributes + ["error", "status_code"],
5856
)
5957
self._error_count = self._meter.create_metric(
6058
name="{}/{}/errors".format(service_name, span_kind),
6159
description="Number of errors that were returned from the server",
6260
unit="1",
6361
value_type=int,
6462
metric_type=Counter,
65-
label_keys=base_attributes + ["status_code"],
6663
)
6764
self._bytes_in = self._meter.create_metric(
6865
name="{}/{}/bytes_in".format(service_name, span_kind),
6966
description="Number of bytes received from the server",
7067
unit="by",
7168
value_type=int,
7269
metric_type=Counter,
73-
label_keys=base_attributes,
7470
)
7571
self._bytes_out = self._meter.create_metric(
7672
name="{}/{}/bytes_out".format(service_name, span_kind),
7773
description="Number of bytes sent out through gRPC",
7874
unit="by",
7975
value_type=int,
8076
metric_type=Counter,
81-
label_keys=base_attributes,
8277
)
8378

8479
def record_bytes_in(self, bytes_in, method):

opentelemetry-api/src/opentelemetry/metrics/__init__.py

-3
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,6 @@ def create_metric(
342342
unit: str,
343343
value_type: Type[ValueT],
344344
metric_type: Type[MetricT],
345-
label_keys: Sequence[str] = (),
346345
enabled: bool = True,
347346
) -> "Metric":
348347
"""Creates a ``metric_kind`` metric with type ``value_type``.
@@ -354,7 +353,6 @@ def create_metric(
354353
(https://unitsofmeasure.org/ucum.html).
355354
value_type: The type of values being recorded by the metric.
356355
metric_type: The type of metric being created.
357-
label_keys: The keys for the labels with dynamic values.
358356
enabled: Whether to report the metric by default.
359357
Returns: A new ``metric_type`` metric with values of ``value_type``.
360358
"""
@@ -413,7 +411,6 @@ def create_metric(
413411
unit: str,
414412
value_type: Type[ValueT],
415413
metric_type: Type[MetricT],
416-
label_keys: Sequence[str] = (),
417414
enabled: bool = True,
418415
) -> "Metric":
419416
# pylint: disable=no-self-use

opentelemetry-sdk/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
- Update environment variable names, prefix changed from `OPENTELEMETRY` to `OTEL`
66
([#904](https://github.com/open-telemetry/opentelemetry-python/pull/904))
7+
- Implement Views in metrics SDK
8+
([#596](https://github.com/open-telemetry/opentelemetry-python/pull/596))
79

810
## Version 0.11b0
911

0 commit comments

Comments
 (0)