From e7b7aa9c1692458fdbfe328b7d17b5f613d44010 Mon Sep 17 00:00:00 2001 From: Aaron Abbott Date: Wed, 12 Jan 2022 00:15:29 +0000 Subject: [PATCH] Complete metric exporter format and update OTLP exporter --- .../proto/grpc/_metric_exporter/__init__.py | 31 +++++++------- .../metrics/test_otlp_metrics_exporter.py | 23 ++++++++--- .../opentelemetry/sdk/_metrics/aggregation.py | 16 ++++---- .../src/opentelemetry/sdk/_metrics/data.py | 35 ---------------- .../sdk/_metrics/export/__init__.py | 11 ++--- .../src/opentelemetry/sdk/_metrics/point.py | 40 +++++++++++++++++-- 6 files changed, 83 insertions(+), 73 deletions(-) delete mode 100644 opentelemetry-sdk/src/opentelemetry/sdk/_metrics/data.py diff --git a/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/_metric_exporter/__init__.py b/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/_metric_exporter/__init__.py index 9db2699da76..ecd03f887c3 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/_metric_exporter/__init__.py +++ b/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/_metric_exporter/__init__.py @@ -33,8 +33,8 @@ from opentelemetry.sdk.environment_variables import ( OTEL_EXPORTER_OTLP_METRICS_INSECURE, ) -from opentelemetry.sdk._metrics.data import ( - MetricData, +from opentelemetry.sdk._metrics.point import ( + Metric, ) from opentelemetry.sdk._metrics.export import ( @@ -45,9 +45,7 @@ class OTLPMetricExporter( MetricExporter, - OTLPExporterMixin[ - MetricData, ExportMetricsServiceRequest, MetricExportResult - ], + OTLPExporterMixin[Metric, ExportMetricsServiceRequest, MetricExportResult], ): _result = MetricExportResult _stub = MetricsServiceStub @@ -79,13 +77,13 @@ def __init__( ) def _translate_data( - self, data: Sequence[MetricData] + self, data: Sequence[Metric] ) -> ExportMetricsServiceRequest: sdk_resource_instrumentation_library_metrics = {} self._collector_metric_kwargs = {} - for metric_data in data: - resource = metric_data.metric.resource + for metric in data: + resource = metric.resource instrumentation_library_map = ( sdk_resource_instrumentation_library_metrics.get(resource, {}) ) @@ -95,26 +93,26 @@ def _translate_data( ] = instrumentation_library_map instrumentation_library_metrics = instrumentation_library_map.get( - metric_data.instrumentation_info + metric.instrumentation_info ) if not instrumentation_library_metrics: - if metric_data.instrumentation_info is not None: + if metric.instrumentation_info is not None: instrumentation_library_map[ - metric_data.instrumentation_info + metric.instrumentation_info ] = InstrumentationLibraryMetrics( instrumentation_library=InstrumentationLibrary( - name=metric_data.instrumentation_info.name, - version=metric_data.instrumentation_info.version, + name=metric.instrumentation_info.name, + version=metric.instrumentation_info.version, ) ) else: instrumentation_library_map[ - metric_data.instrumentation_info + metric.instrumentation_info ] = InstrumentationLibraryMetrics() instrumentation_library_metrics = instrumentation_library_map.get( - metric_data.instrumentation_info + metric.instrumentation_info ) instrumentation_library_metrics.metrics.append( @@ -128,7 +126,8 @@ def _translate_data( ) ) - def export(self, metrics: Sequence[MetricData]) -> MetricExportResult: + def export(self, metrics: Sequence[Metric]) -> MetricExportResult: + print("Got metrics!!!\n", metrics) return self._export(metrics) def shutdown(self): diff --git a/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/metrics/test_otlp_metrics_exporter.py b/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/metrics/test_otlp_metrics_exporter.py index 54253c91415..82da7a0e98c 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/metrics/test_otlp_metrics_exporter.py +++ b/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/metrics/test_otlp_metrics_exporter.py @@ -30,8 +30,12 @@ MetricsServiceServicer, add_MetricsServiceServicer_to_server, ) -from opentelemetry.sdk._metrics.data import Metric, MetricData from opentelemetry.sdk._metrics.export import MetricExportResult +from opentelemetry.sdk._metrics.point import ( + AggregationTemporality, + Metric, + Sum, +) from opentelemetry.sdk.environment_variables import ( OTEL_EXPORTER_OTLP_METRICS_INSECURE, ) @@ -96,13 +100,22 @@ def setUp(self): self.server.start() - self.metric_data_1 = MetricData( - metric=Metric( - resource=SDKResource({"key": "value"}), - ), + self.metric_data_1 = Metric( + resource=SDKResource({"key": "value"}), instrumentation_info=InstrumentationInfo( "first_name", "first_version" ), + attributes={}, + description="foo", + name="foometric", + unit="s", + point=Sum( + aggregation_temporality=AggregationTemporality.CUMULATIVE, + is_monotonic=True, + start_time_unix_nano=1641946015139533244, + time_unix_nano=1641946016139533244, + value=33, + ), ) def tearDown(self): diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/aggregation.py b/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/aggregation.py index 03a2debfe0b..3402f1a4747 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/aggregation.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/aggregation.py @@ -14,23 +14,21 @@ from abc import ABC, abstractmethod from collections import OrderedDict -from enum import IntEnum from logging import getLogger from math import inf from threading import Lock from typing import Generic, Optional, Sequence, TypeVar from opentelemetry.sdk._metrics.measurement import Measurement -from opentelemetry.sdk._metrics.point import Gauge, Histogram, PointT, Sum +from opentelemetry.sdk._metrics.point import ( + AggregationTemporality, + Gauge, + Histogram, + PointT, + Sum, +) from opentelemetry.util._time import _time_ns - -class AggregationTemporality(IntEnum): - UNSPECIFIED = 0 - DELTA = 1 - CUMULATIVE = 2 - - _PointVarT = TypeVar("_PointVarT", bound=PointT) _logger = getLogger(__name__) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/data.py b/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/data.py deleted file mode 100644 index e582d666841..00000000000 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/data.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright The 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. - -from opentelemetry.sdk.resources import Resource -from opentelemetry.sdk.util.instrumentation import InstrumentationInfo - - -class Metric: - """TODO fill this in""" - - def __init__(self, resource: Resource) -> None: - self.resource = resource - - -class MetricData: - """Readable Metric data plus associated InstrumentationLibrary.""" - - def __init__( - self, - metric: Metric, - instrumentation_info: InstrumentationInfo, - ): - self.metric = metric - self.instrumentation_info = instrumentation_info diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/export/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/export/__init__.py index e9a83861fe9..b5e2f086104 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/export/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/export/__init__.py @@ -18,7 +18,7 @@ from sys import stdout from typing import IO, Callable, Sequence -from opentelemetry.sdk._metrics.data import Metric, MetricData +from opentelemetry.sdk._metrics.point import Metric class MetricExportResult(Enum): @@ -33,7 +33,8 @@ class MetricExporter(ABC): in their own format. """ - def export(self, metrics: Sequence[MetricData]) -> "MetricExportResult": + @abstractmethod + def export(self, metrics: Sequence[Metric]) -> "MetricExportResult": """Exports a batch of telemetry data. Args: @@ -68,9 +69,9 @@ def __init__( self.out = out self.formatter = formatter - def export(self, metrics: Sequence[MetricData]) -> MetricExportResult: - for data in metrics: - self.out.write(self.formatter(data.metric)) + def export(self, metrics: Sequence[Metric]) -> MetricExportResult: + for metric in metrics: + self.out.write(self.formatter(metric)) self.out.flush() return MetricExportResult.SUCCESS diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/point.py b/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/point.py index 2503bb43e3b..7405036fd3a 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/point.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/point.py @@ -12,16 +12,27 @@ # See the License for the specific language governing permissions and # limitations under the License. -from dataclasses import dataclass +import json +from dataclasses import asdict, dataclass +from enum import IntEnum from typing import Sequence, Union +from opentelemetry.sdk.resources import Attributes, Resource +from opentelemetry.sdk.util.instrumentation import InstrumentationInfo + + +class AggregationTemporality(IntEnum): + UNSPECIFIED = 0 + DELTA = 1 + CUMULATIVE = 2 + @dataclass(frozen=True) class Sum: start_time_unix_nano: int time_unix_nano: int value: Union[int, float] - aggregation_temporality: int + aggregation_temporality: AggregationTemporality is_monotonic: bool @@ -37,7 +48,30 @@ class Histogram: time_unix_nano: int bucket_counts: Sequence[int] explicit_bounds: Sequence[float] - aggregation_temporality: int + aggregation_temporality: AggregationTemporality PointT = Union[Sum, Gauge, Histogram] + + +@dataclass(frozen=True) +class Metric: + """Represents a metric point in the OpenTelemetry data model to be exported + + Concrete metric types contain all the information as in the OTLP proto definitions + (https://tinyurl.com/7h6yx24v) but are flattened as much as possible. + """ + + # common fields to all metric kinds + attributes: Attributes + description: str + instrumentation_info: InstrumentationInfo + name: str + resource: Resource + unit: str + + point: PointT + """Contains non-common fields for the given metric""" + + def to_json(self) -> str: + return json.dumps(asdict(self))