Skip to content

Commit fe99dbc

Browse files
authored
Metrics export pipeline + metrics stdout exporter (#341)
Initial implementation of the end-to-end metrics pipeline.
1 parent 7229435 commit fe99dbc

File tree

23 files changed

+1052
-170
lines changed

23 files changed

+1052
-170
lines changed

Diff for: docs/opentelemetry.sdk.metrics.export.aggregate.rst

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
opentelemetry.sdk.metrics.export.aggregate
2+
==========================================
3+
4+
.. automodule:: opentelemetry.sdk.metrics.export.aggregate
5+
:members:
6+
:undoc-members:
7+
:show-inheritance:

Diff for: docs/opentelemetry.sdk.metrics.export.batcher.rst

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
opentelemetry.sdk.metrics.export.batcher
2+
==========================================
3+
4+
.. toctree::
5+
6+
opentelemetry.sdk.metrics.export
7+
8+
.. automodule:: opentelemetry.sdk.metrics.export.batcher
9+
:members:
10+
:undoc-members:
11+
:show-inheritance:

Diff for: docs/opentelemetry.sdk.metrics.export.rst

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
opentelemetry.sdk.metrics.export
2+
==========================================
3+
4+
.. automodule:: opentelemetry.sdk.metrics.export
5+
:members:
6+
:undoc-members:
7+
:show-inheritance:

Diff for: docs/opentelemetry.sdk.metrics.rst

+8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
opentelemetry.sdk.metrics package
22
==========================================
33

4+
Submodules
5+
----------
6+
7+
.. toctree::
8+
9+
opentelemetry.sdk.metrics.export.aggregate
10+
opentelemetry.sdk.metrics.export.batcher
11+
412
.. automodule:: opentelemetry.sdk.metrics
513
:members:
614
:undoc-members:

Diff for: examples/metrics/record.py

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Copyright 2019, 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 module serves as an example for a simple application using metrics.
17+
It demonstrates the different ways you can record metrics via the meter.
18+
"""
19+
import time
20+
21+
from opentelemetry import metrics
22+
from opentelemetry.sdk.metrics import Counter, Meter
23+
from opentelemetry.sdk.metrics.export import ConsoleMetricsExporter
24+
from opentelemetry.sdk.metrics.export.controller import PushController
25+
26+
# Meter is responsible for creating and recording metrics
27+
metrics.set_preferred_meter_implementation(lambda _: Meter())
28+
meter = metrics.meter()
29+
# exporter to export metrics to the console
30+
exporter = ConsoleMetricsExporter()
31+
# controller collects metrics created from meter and exports it via the
32+
# exporter every interval
33+
controller = PushController(meter, exporter, 5)
34+
35+
# Example to show how to record using the meter
36+
counter = meter.create_metric(
37+
"requests", "number of requests", 1, int, Counter, ("environment",)
38+
)
39+
40+
counter2 = meter.create_metric(
41+
"clicks", "number of clicks", 1, int, Counter, ("environment",)
42+
)
43+
44+
# Labelsets are used to identify key-values that are associated with a specific
45+
# metric that you want to record. These are useful for pre-aggregation and can
46+
# be used to store custom dimensions pertaining to a metric
47+
48+
# The meter takes a dictionary of key value pairs
49+
label_set = meter.get_label_set({"environment": "staging"})
50+
51+
# Handle usage
52+
# You can record metrics with metric handles. Handles are created by passing in
53+
# a labelset. A handle is essentially metric data that corresponds to a specific
54+
# set of labels. Therefore, getting a handle using the same set of labels will
55+
# yield the same metric handle.
56+
counter_handle = counter.get_handle(label_set)
57+
counter_handle.add(100)
58+
59+
# Direct metric usage
60+
# You can record metrics directly using the metric instrument. You pass in a
61+
# labelset that you would like to record for.
62+
counter.add(25, label_set)
63+
64+
# Record batch usage
65+
# You can record metrics in a batch by passing in a labelset and a sequence of
66+
# (metric, value) pairs. The value would be recorded for each metric using the
67+
# specified labelset for each.
68+
meter.record_batch(label_set, [(counter, 50), (counter2, 70)])
69+
time.sleep(100)

Diff for: examples/metrics/stateful.py

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Copyright 2019, 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 module serves as an example for a simple application using metrics
17+
Examples show how to recording affects the collection of metrics to be exported
18+
"""
19+
import time
20+
21+
from opentelemetry import metrics
22+
from opentelemetry.sdk.metrics import Counter, Meter
23+
from opentelemetry.sdk.metrics.export import ConsoleMetricsExporter
24+
from opentelemetry.sdk.metrics.export.batcher import UngroupedBatcher
25+
from opentelemetry.sdk.metrics.export.controller import PushController
26+
27+
# Batcher used to collect all created metrics from meter ready for exporting
28+
# Pass in true/false to indicate whether the batcher is stateful. True
29+
# indicates the batcher computes checkpoints from over the process lifetime.
30+
# False indicates the batcher computes checkpoints which describe the updates
31+
# of a single collection period (deltas)
32+
batcher = UngroupedBatcher(True)
33+
# If a batcher is not provded, a default batcher is used
34+
# Meter is responsible for creating and recording metrics
35+
metrics.set_preferred_meter_implementation(lambda _: Meter(batcher))
36+
meter = metrics.meter()
37+
# exporter to export metrics to the console
38+
exporter = ConsoleMetricsExporter()
39+
# controller collects metrics created from meter and exports it via the
40+
# exporter every interval
41+
controller = PushController(meter, exporter, 5)
42+
43+
counter = meter.create_metric(
44+
"requests", "number of requests", 1, int, Counter, ("environment",)
45+
)
46+
47+
counter2 = meter.create_metric(
48+
"clicks", "number of clicks", 1, int, Counter, ("environment",)
49+
)
50+
51+
# Labelsets are used to identify key-values that are associated with a specific
52+
# metric that you want to record. These are useful for pre-aggregation and can
53+
# be used to store custom dimensions pertaining to a metric
54+
label_set = meter.get_label_set({"environment": "staging"})
55+
label_set2 = meter.get_label_set({"environment": "testing"})
56+
57+
counter.add(25, label_set)
58+
# We sleep for 5 seconds, exported value should be 25
59+
time.sleep(5)
60+
61+
counter.add(50, label_set)
62+
# exported value should be 75
63+
time.sleep(5)
64+
65+
counter.add(35, label_set2)
66+
# should be two exported values 75 and 35, one for each labelset
67+
time.sleep(5)
68+
69+
counter2.add(5, label_set)
70+
# should be three exported values, labelsets can be reused for different
71+
# metrics but will be recorded seperately, 75, 35 and 5
72+
time.sleep(5)

Diff for: examples/metrics/stateless.py

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Copyright 2019, 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 module serves as an example for a simple application using metrics
17+
Examples show how to recording affects the collection of metrics to be exported
18+
"""
19+
import time
20+
21+
from opentelemetry import metrics
22+
from opentelemetry.sdk.metrics import Counter, Meter
23+
from opentelemetry.sdk.metrics.export import ConsoleMetricsExporter
24+
from opentelemetry.sdk.metrics.export.batcher import UngroupedBatcher
25+
from opentelemetry.sdk.metrics.export.controller import PushController
26+
27+
# Batcher used to collect all created metrics from meter ready for exporting
28+
# Pass in false for non-stateful batcher. Indicates the batcher computes
29+
# checkpoints which describe the updates of a single collection period (deltas)
30+
batcher = UngroupedBatcher(False)
31+
# Meter is responsible for creating and recording metrics
32+
metrics.set_preferred_meter_implementation(lambda _: Meter(batcher))
33+
meter = metrics.meter()
34+
# exporter to export metrics to the console
35+
exporter = ConsoleMetricsExporter()
36+
# controller collects metrics created from meter and exports it via the
37+
# exporter every interval
38+
controller = PushController(meter, exporter, 5)
39+
40+
counter = meter.create_metric(
41+
"requests", "number of requests", 1, int, Counter, ("environment",)
42+
)
43+
44+
# Labelsets are used to identify key-values that are associated with a specific
45+
# metric that you want to record. These are useful for pre-aggregation and can
46+
# be used to store custom dimensions pertaining to a metric
47+
label_set = meter.get_label_set({"environment": "staging"})
48+
49+
counter.add(25, label_set)
50+
# We sleep for 5 seconds, exported value should be 25
51+
time.sleep(5)
52+
53+
counter.add(50, label_set)
54+
# exported value should be 50 due to non-stateful batcher
55+
time.sleep(20)
56+
57+
# Following exported values would be 0

Diff for: examples/opentelemetry-example-app/src/opentelemetry_example_app/metrics_example.py

+8-4
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,12 @@
1818

1919
from opentelemetry import metrics
2020
from opentelemetry.sdk.metrics import Counter, Meter
21+
from opentelemetry.sdk.metrics.export import ConsoleMetricsExporter
22+
from opentelemetry.sdk.metrics.export.batcher import UngroupedBatcher
23+
from opentelemetry.sdk.metrics.export.controller import PushController
2124

22-
metrics.set_preferred_meter_implementation(lambda _: Meter())
25+
batcher = UngroupedBatcher(True)
26+
metrics.set_preferred_meter_implementation(lambda _: Meter(batcher))
2327
meter = metrics.meter()
2428
counter = meter.create_metric(
2529
"available memory",
@@ -33,14 +37,14 @@
3337
label_set = meter.get_label_set({"environment": "staging"})
3438

3539
# Direct metric usage
36-
counter.add(label_set, 25)
40+
counter.add(25, label_set)
3741

3842
# Handle usage
3943
counter_handle = counter.get_handle(label_set)
4044
counter_handle.add(100)
4145

4246
# Record batch usage
4347
meter.record_batch(label_set, [(counter, 50)])
44-
print(counter_handle.data)
4548

46-
# TODO: exporters
49+
exporter = ConsoleMetricsExporter()
50+
controller = PushController(meter, exporter, 5)

Diff for: ext/opentelemetry-ext-jaeger/tests/test_jaeger_exporter.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ def test_translate_to_jaeger(self):
163163
vLong=StatusCanonicalCode.OK.value,
164164
),
165165
jaeger.Tag(
166-
key="status.message", vType=jaeger.TagType.STRING, vStr=None,
166+
key="status.message", vType=jaeger.TagType.STRING, vStr=None
167167
),
168168
jaeger.Tag(
169169
key="span.kind",
@@ -246,7 +246,7 @@ def test_translate_to_jaeger(self):
246246
vStr=trace_api.SpanKind.CLIENT.name,
247247
),
248248
jaeger.Tag(
249-
key="error", vType=jaeger.TagType.BOOL, vBool=True,
249+
key="error", vType=jaeger.TagType.BOOL, vBool=True
250250
),
251251
],
252252
references=[

Diff for: ext/opentelemetry-ext-zipkin/src/opentelemetry/ext/zipkin/__init__.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,7 @@ def export(self, spans: Sequence[Span]) -> SpanExportResult:
101101

102102
def _translate_to_zipkin(self, spans: Sequence[Span]):
103103

104-
local_endpoint = {
105-
"serviceName": self.service_name,
106-
"port": self.port,
107-
}
104+
local_endpoint = {"serviceName": self.service_name, "port": self.port}
108105

109106
if self.ipv4 is not None:
110107
local_endpoint["ipv4"] = self.ipv4

Diff for: ext/opentelemetry-ext-zipkin/tests/test_zipkin_exporter.py

+2-7
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,7 @@ def test_export(self):
114114
)
115115

116116
span_context = trace_api.SpanContext(
117-
trace_id,
118-
span_id,
119-
trace_options=TraceOptions(TraceOptions.SAMPLED),
117+
trace_id, span_id, trace_options=TraceOptions(TraceOptions.SAMPLED)
120118
)
121119
parent_context = trace_api.SpanContext(trace_id, parent_id)
122120
other_context = trace_api.SpanContext(trace_id, other_id)
@@ -168,10 +166,7 @@ def test_export(self):
168166
otel_spans[2].end(end_time=end_times[2])
169167

170168
service_name = "test-service"
171-
local_endpoint = {
172-
"serviceName": service_name,
173-
"port": 9411,
174-
}
169+
local_endpoint = {"serviceName": service_name, "port": 9411}
175170

176171
exporter = ZipkinSpanExporter(service_name)
177172
expected = [

0 commit comments

Comments
 (0)