From 0994836adc563359f53f1b9320fcb7edf3c8ed10 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Tue, 19 Oct 2021 11:45:53 +0200 Subject: [PATCH] Add MeterProvider and Meter to the SDK Fixes #2200 --- .../src/opentelemetry/sdk/metrics/__init__.py | 169 ++++++++++++++++++ .../src/opentelemetry/sdk/metrics/api.py | 48 +++++ 2 files changed, 217 insertions(+) create mode 100644 opentelemetry-sdk/src/opentelemetry/sdk/metrics/__init__.py create mode 100644 opentelemetry-sdk/src/opentelemetry/sdk/metrics/api.py diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/metrics/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/metrics/__init__.py new file mode 100644 index 00000000000..cc767c6ab1b --- /dev/null +++ b/opentelemetry-sdk/src/opentelemetry/sdk/metrics/__init__.py @@ -0,0 +1,169 @@ +# 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. + +# pylint: disable=function-redefined,too-many-ancestors + +from atexit import register +from logging import getLogger +from typing import Optional + +from opentelemetry.metrics import Meter, MeterProvider +from opentelemetry.metrics.instrument import ( + Counter, + Histogram, + ObservableCounter, + ObservableGauge, + ObservableUpDownCounter, + UpDownCounter, +) +from opentelemetry.sdk.metrics.api import MetricExporter, MetricReader, View +from opentelemetry.sdk.resources import Resource +from opentelemetry.sdk.util.instrumentation import InstrumentationInfo + +_logger = getLogger(__name__) + + +class Meter(Meter): + def __init__(self, instrumentation_info: InstrumentationInfo): + super().__init__(instrumentation_info) + self._instrumentation_info = instrumentation_info + self._meter_provider = None + + def create_counter(self, name, unit=None, description=None) -> Counter: + pass + + def create_up_down_counter( + self, name, unit=None, description=None + ) -> UpDownCounter: + pass + + def create_observable_counter( + self, name, callback, unit=None, description=None + ) -> ObservableCounter: + pass + + def create_histogram(self, name, unit=None, description=None) -> Histogram: + pass + + def create_observable_gauge( + self, name, callback, unit=None, description=None + ) -> ObservableGauge: + pass + + def create_observable_up_down_counter( + self, name, callback, unit=None, description=None + ) -> ObservableUpDownCounter: + pass + + +class MeterProvider(MeterProvider): + """See `opentelemetry.metrics.Provider`.""" + + def __init__( + self, + resource: Resource = Resource.create({}), + shutdown_on_exit: bool = True, + ): + self._resource = resource + self._atexit_handler = None + + if shutdown_on_exit: + self._atexit_handler = register(self.shutdown) + + self._metric_readers = [] + self._metric_exporters = [] + self._views = [] + self._shutdown = False + + @property + def metric_readers(self): + return self._metric_readers + + @property + def metric_exporters(self): + return self._metric_exporters + + @property + def views(self): + return self._views + + @property + def resource(self) -> Resource: + return self._resource + + def get_meter( + self, + name: str, + version: Optional[str] = None, + schema_url: Optional[str] = None, + ) -> Meter: + meter = Meter(InstrumentationInfo(name, version, schema_url)) + + meter._meter_provider = self # pylint: disable=protected-access + + return meter + + def shutdown(self): + + if self._shutdown: + _logger.warning("shutdown can only be called once") + return False + + result = True + + for metric_reader in self._metric_readers: + result = result and metric_reader.shutdown() + + for metric_exporter in self._metric_exporters: + result = result and metric_exporter.shutdown() + + self._shutdown = True + + return result + + def force_flush(self) -> bool: + result = True + + for metric_reader in self._metric_readers: + result = result and metric_reader.force_flush() + + for metric_exporter in self._metric_exporters: + result = result and metric_exporter.force_flush() + + return result + + def register_metric_reader(self, metric_reader: "MetricReader") -> None: + self._metric_readers.append(metric_reader) + + def register_metric_exporter( + self, metric_exporter: "MetricExporter" + ) -> None: + self._metric_exporters.append(metric_exporter) + + def register_view(self, view: "View") -> None: + self._views.append(view) + + +class MetricReader(MetricReader): + def collect(self): + pass + + +class MetricExporter(MetricExporter): + def export(self): + pass + + +class View(View): + pass diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/metrics/api.py b/opentelemetry-sdk/src/opentelemetry/sdk/metrics/api.py new file mode 100644 index 00000000000..43ad9479b72 --- /dev/null +++ b/opentelemetry-sdk/src/opentelemetry/sdk/metrics/api.py @@ -0,0 +1,48 @@ +# 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. + +# pylint: disable=function-redefined,too-many-ancestors + +from abc import ABC, abstractmethod +from logging import getLogger + +_logger = getLogger(__name__) + + +class MetricReader(ABC): + def __init__(self): + self._shutdown = False + + @abstractmethod + def collect(self): + pass + + def shutdown(self): + self._shutdown = True + + +class MetricExporter(ABC): + def __init__(self): + self._shutdown = False + + @abstractmethod + def export(self): + pass + + def shutdown(self): + self._shutdown = True + + +class View(ABC): + pass