diff --git a/docs/examples/basic_meter/basic_metrics.py b/docs/examples/basic_meter/basic_metrics.py index 6e8a5c040f3..b9ff8d87417 100644 --- a/docs/examples/basic_meter/basic_metrics.py +++ b/docs/examples/basic_meter/basic_metrics.py @@ -30,33 +30,17 @@ stateful = True - -def usage(argv): - print("usage:") - print("{} [mode]".format(argv[0])) - print("mode: stateful (default) or stateless") - - -if len(sys.argv) >= 2: - batcher_mode = sys.argv[1] - if batcher_mode not in ("stateful", "stateless"): - print("bad mode specified.") - usage(sys.argv) - sys.exit(1) - stateful = batcher_mode == "stateful" - print( "Starting example, values will be printed to the console every 5 seconds." ) - +# Stateful determines whether how metrics are collected: if true, metrics +# accumulate over the process lifetime. If false, metrics are reset at the +# beginning of each collection interval. +metrics.set_meter_provider(MeterProvider(stateful)) # The Meter is responsible for creating and recording metrics. Each meter has a -# unique name, which we set as the module's name here. The second argument -# determines whether how metrics are collected: if true, metrics accumulate -# over the process lifetime. If false, metrics are reset at the beginning of -# each collection interval. -metrics.set_meter_provider(MeterProvider()) -meter = metrics.get_meter(__name__, batcher_mode == "stateful") +# unique name, which we set as the module's name here. +meter = metrics.get_meter(__name__) # Exporter to export metrics to the console exporter = ConsoleMetricsExporter() diff --git a/docs/examples/basic_meter/observer.py b/docs/examples/basic_meter/observer.py index 0490fbe8efb..aa70abe2a44 100644 --- a/docs/examples/basic_meter/observer.py +++ b/docs/examples/basic_meter/observer.py @@ -24,8 +24,6 @@ from opentelemetry.sdk.metrics.export.batcher import UngroupedBatcher from opentelemetry.sdk.metrics.export.controller import PushController -# Configure a stateful batcher -batcher = UngroupedBatcher(stateful=True) metrics.set_meter_provider(MeterProvider()) meter = metrics.get_meter(__name__) exporter = ConsoleMetricsExporter() diff --git a/opentelemetry-api/CHANGELOG.md b/opentelemetry-api/CHANGELOG.md index 4b678cd4226..a67c840190c 100644 --- a/opentelemetry-api/CHANGELOG.md +++ b/opentelemetry-api/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +- Move stateful from Meter to MeterProvider + ([#751](https://github.com/open-telemetry/opentelemetry-python/pull/751)) - Rename Measure to ValueRecorder in metrics ([#761](https://github.com/open-telemetry/opentelemetry-python/pull/761)) diff --git a/opentelemetry-api/src/opentelemetry/metrics/__init__.py b/opentelemetry-api/src/opentelemetry/metrics/__init__.py index a91a4ce7b76..16ac4c096f0 100644 --- a/opentelemetry-api/src/opentelemetry/metrics/__init__.py +++ b/opentelemetry-api/src/opentelemetry/metrics/__init__.py @@ -29,7 +29,7 @@ """ import abc from logging import getLogger -from typing import Callable, Dict, Sequence, Tuple, Type, TypeVar +from typing import Callable, Dict, Optional, Sequence, Tuple, Type, TypeVar from opentelemetry.util import _load_provider @@ -195,7 +195,6 @@ class MeterProvider(abc.ABC): def get_meter( self, instrumenting_module_name: str, - stateful: bool = True, instrumenting_library_version: str = "", ) -> "Meter": """Returns a `Meter` for use by the given instrumentation library. @@ -212,12 +211,6 @@ def get_meter( E.g., instead of ``"requests"``, use ``"opentelemetry.ext.requests"``. - stateful: True/False to indicate whether the meter will be - stateful. True indicates the meter computes checkpoints - from over the process lifetime. False indicates the meter - computes checkpoints which describe the updates of a single - collection period (deltas). - instrumenting_library_version: Optional. The version string of the instrumenting library. Usually this should be the same as ``pkg_resources.get_distribution(instrumenting_library_name).version``. @@ -233,7 +226,6 @@ class DefaultMeterProvider(MeterProvider): def get_meter( self, instrumenting_module_name: str, - stateful: bool = True, instrumenting_library_version: str = "", ) -> "Meter": # pylint:disable=no-self-use,unused-argument @@ -376,15 +368,19 @@ def unregister_observer(self, observer: "Observer") -> None: def get_meter( instrumenting_module_name: str, - stateful: bool = True, instrumenting_library_version: str = "", + meter_provider: Optional[MeterProvider] = None, ) -> "Meter": """Returns a `Meter` for use by the given instrumentation library. This function is a convenience wrapper for opentelemetry.metrics.get_meter_provider().get_meter + + If meter_provider is omitted the current configured one is used. """ - return get_meter_provider().get_meter( - instrumenting_module_name, stateful, instrumenting_library_version + if meter_provider is None: + meter_provider = get_meter_provider() + return meter_provider.get_meter( + instrumenting_module_name, instrumenting_library_version ) diff --git a/opentelemetry-sdk/CHANGELOG.md b/opentelemetry-sdk/CHANGELOG.md index 29aaed01dcc..3e54a63b3ba 100644 --- a/opentelemetry-sdk/CHANGELOG.md +++ b/opentelemetry-sdk/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +- Move stateful & resource from Meter to MeterProvider + ([#751](https://github.com/open-telemetry/opentelemetry-python/pull/751)) - Rename Measure to ValueRecorder in metrics ([#761](https://github.com/open-telemetry/opentelemetry-python/pull/761)) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/metrics/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/metrics/__init__.py index b9284bae9fe..f231182cc28 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/metrics/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/metrics/__init__.py @@ -270,22 +270,21 @@ class Meter(metrics_api.Meter): """See `opentelemetry.metrics.Meter`. Args: + source: The `MeterProvider` that created this meter. instrumentation_info: The `InstrumentationInfo` for this meter. - stateful: Indicates whether the meter is stateful. """ def __init__( self, + source: "MeterProvider", instrumentation_info: "InstrumentationInfo", - stateful: bool, - resource: Resource = Resource.create_empty(), ): self.instrumentation_info = instrumentation_info + self.batcher = UngroupedBatcher(source.stateful) + self.resource = source.resource self.metrics = set() self.observers = set() - self.batcher = UngroupedBatcher(stateful) self.observers_lock = threading.Lock() - self.resource = resource def collect(self) -> None: """Collects all the metrics created with this `Meter` for export. @@ -398,21 +397,29 @@ def unregister_observer(self, observer: "Observer") -> None: class MeterProvider(metrics_api.MeterProvider): - def __init__(self, resource: Resource = Resource.create_empty()): + """See `opentelemetry.metrics.MeterProvider`. + + Args: + stateful: Indicates whether meters created are going to be stateful + resource: Resource for this MeterProvider + """ + + def __init__( + self, stateful=True, resource: Resource = Resource.create_empty(), + ): + self.stateful = stateful self.resource = resource def get_meter( self, instrumenting_module_name: str, - stateful=True, instrumenting_library_version: str = "", ) -> "metrics_api.Meter": if not instrumenting_module_name: # Reject empty strings too. raise ValueError("get_meter called with missing module name.") return Meter( + self, InstrumentationInfo( instrumenting_module_name, instrumenting_library_version ), - stateful=stateful, - resource=self.resource, ) diff --git a/opentelemetry-sdk/tests/metrics/test_metrics.py b/opentelemetry-sdk/tests/metrics/test_metrics.py index a3c0f4294d9..9d5d2b15d8e 100644 --- a/opentelemetry-sdk/tests/metrics/test_metrics.py +++ b/opentelemetry-sdk/tests/metrics/test_metrics.py @@ -21,6 +21,11 @@ class TestMeterProvider(unittest.TestCase): + def test_stateful(self): + meter_provider = metrics.MeterProvider(stateful=False) + meter = meter_provider.get_meter(__name__) + self.assertIs(meter.batcher.stateful, False) + def test_resource(self): resource = resources.Resource.create({}) meter_provider = metrics.MeterProvider(resource=resource)