-
Notifications
You must be signed in to change notification settings - Fork 703
Implement "named" meters + Remove "Batcher" from Meter constructor #431
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 24 commits
bba1fea
712ccd3
b50c269
fd3d175
08b1117
c92f837
7b8b67d
63824f3
16e728b
7733a87
b436c62
d6c97f0
a2f2e0f
32cf2c1
ec9c673
7ebd438
27d75ba
08095b6
6a743c7
e226eda
c7432ef
60b2f38
bd53f84
6f6a37d
4770ec4
0f36b31
4f4632b
e591a39
0878f5d
584d996
f854923
4df2553
40ee67b
0b93285
3735d88
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
opentelemetry.sdk.util.instrumentation | ||
========================================== | ||
|
||
.. automodule:: opentelemetry.sdk.util.instrumentation |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,10 +27,13 @@ | |
|
||
""" | ||
import abc | ||
import logging | ||
from typing import Callable, Dict, Optional, Sequence, Tuple, Type, TypeVar | ||
|
||
from opentelemetry.util import loader | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
ValueT = TypeVar("ValueT", int, float) | ||
|
||
|
||
|
@@ -224,6 +227,56 @@ def record(self, value: ValueT, label_set: LabelSet) -> None: | |
""" | ||
|
||
|
||
class MeterProvider(abc.ABC): | ||
@abc.abstractmethod | ||
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. | ||
|
||
This function may return different `Meter` types (e.g. a no-op meter | ||
vs. a functional meter). | ||
|
||
Args: | ||
instrumenting_module_name: The name of the instrumenting module | ||
(usually just ``__name__``). | ||
|
||
This should *not* be the name of the module that is | ||
instrumented but the name of the module doing the instrumentation. | ||
E.g., instead of ``"requests"``, use | ||
``"opentelemetry.ext.http_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``. | ||
""" | ||
|
||
|
||
class DefaultMeterProvider(MeterProvider): | ||
"""The default MeterProvider, used when no implementation is available. | ||
|
||
All operations are no-op. | ||
""" | ||
|
||
def get_meter( | ||
self, | ||
instrumenting_module_name: str, | ||
stateful: bool = True, | ||
instrumenting_library_version: str = "", | ||
) -> "Meter": | ||
# pylint:disable=no-self-use,unused-argument | ||
return DefaultMeter() | ||
|
||
|
||
MetricT = TypeVar("MetricT", Counter, Gauge, Measure) | ||
|
||
|
||
|
@@ -322,45 +375,69 @@ def get_label_set(self, labels: Dict[str, str]) -> "LabelSet": | |
# Once https://github.com/python/mypy/issues/7092 is resolved, | ||
# the following type definition should be replaced with | ||
# from opentelemetry.util.loader import ImplementationFactory | ||
ImplementationFactory = Callable[[Type[Meter]], Optional[Meter]] | ||
|
||
_METER = None | ||
_METER_FACTORY = None | ||
ImplementationFactory = Callable[ | ||
[Type[MeterProvider]], Optional[MeterProvider] | ||
] | ||
|
||
_METER_SOURCE = None | ||
_METER_SOURCE_FACTORY = None | ||
|
||
|
||
def get_meter( | ||
instrumenting_module_name: str, | ||
stateful: bool = True, | ||
instrumenting_library_version: str = "", | ||
) -> "Meter": | ||
"""Returns a `Meter` for use by the given instrumentation library. | ||
This function is a convenience wrapper for | ||
opentelemetry.metrics.meter_provider().get_meter | ||
""" | ||
return meter_provider().get_meter( | ||
instrumenting_module_name, stateful, instrumenting_library_version | ||
) | ||
|
||
|
||
def meter() -> Meter: | ||
"""Gets the current global :class:`~.Meter` object. | ||
def meter_provider() -> MeterProvider: | ||
"""Gets the current global :class:`~.MeterProvider` object. | ||
|
||
If there isn't one set yet, a default will be loaded. | ||
""" | ||
global _METER, _METER_FACTORY # pylint:disable=global-statement | ||
global _METER_SOURCE, _METER_SOURCE_FACTORY # pylint:disable=global-statement | ||
|
||
if _METER is None: | ||
if _METER_SOURCE is None: | ||
# pylint:disable=protected-access | ||
try: | ||
_METER = loader._load_impl(Meter, _METER_FACTORY) # type: ignore | ||
_METER_SOURCE = loader._load_impl( | ||
MeterProvider, _METER_SOURCE_FACTORY # type: ignore | ||
) | ||
except TypeError: | ||
lzchen marked this conversation as resolved.
Show resolved
Hide resolved
|
||
# if we raised an exception trying to instantiate an | ||
# abstract class, default to no-op tracer impl | ||
_METER = DefaultMeter() | ||
del _METER_FACTORY | ||
# abstract class, default to no-op meter impl | ||
logger.warning( | ||
"Unable to instantiate MeterProvider from meter provider factory.", | ||
exc_info=True, | ||
) | ||
_METER_SOURCE = DefaultMeterProvider() | ||
del _METER_SOURCE_FACTORY | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this variable be deleted, or just set to None? It's a lot easier to see if a variable is None that go to locals() and check if the _METER_SOURCE_FACTORY key is in there as a guard condition to check on the _METER_SOURCE_FACTORY. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't have a strong opinion on this. I'm taking what is being done in the tracing API to be consistent. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. +1 on setting it to None, stays consistent with the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. my bad, i missed that. |
||
|
||
return _METER | ||
return _METER_SOURCE | ||
|
||
|
||
def set_preferred_meter_implementation(factory: ImplementationFactory) -> None: | ||
"""Set the factory to be used to create the meter. | ||
def set_preferred_meter_provider_implementation( | ||
factory: ImplementationFactory, | ||
) -> None: | ||
"""Set the factory to be used to create the meter provider. | ||
|
||
See :mod:`opentelemetry.util.loader` for details. | ||
|
||
This function may not be called after a meter is already loaded. | ||
|
||
Args: | ||
factory: Callback that should create a new :class:`Meter` instance. | ||
factory: Callback that should create a new :class:`MeterProvider` instance. | ||
""" | ||
global _METER, _METER_FACTORY # pylint:disable=global-statement | ||
global _METER_SOURCE_FACTORY # pylint:disable=global-statement | ||
|
||
if _METER: | ||
raise RuntimeError("Meter already loaded.") | ||
if _METER_SOURCE: | ||
raise RuntimeError("MeterProvider already loaded.") | ||
|
||
_METER_FACTORY = factory | ||
_METER_SOURCE_FACTORY = factory |
Uh oh!
There was an error while loading. Please reload this page.