forked from open-telemetry/opentelemetry-python
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixes open-telemetry#1835
- Loading branch information
Showing
21 changed files
with
1,898 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
Grocery | ||
======= | ||
|
||
This is the implementation of the grocery scenario. | ||
|
||
|
||
Useful links | ||
------------ | ||
|
||
.. _Grocery: https://github.com/open-telemetry/oteps/blob/main/text/metrics/0146-metrics-prototype-scenarios.md#scenario-1-grocery |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
# 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.metrics import get_meter_provider | ||
from opentelemetry.sdk.metrics.export import ConsoleExporter | ||
|
||
exporter = ConsoleExporter() | ||
|
||
get_meter_provider().start_pipeline_equivalent(exporter, 5) | ||
|
||
meter = get_meter_provider().get_meter() | ||
|
||
|
||
order_counter = meter.create_counter( | ||
name="orders", | ||
description="number of orders", | ||
unit="order", | ||
value_type=int, | ||
) | ||
|
||
amount_counter = meter.create_counter( | ||
name="amount", | ||
description="amount paid", | ||
unit="dollar", | ||
value_type=int, | ||
) | ||
|
||
sold_items_counter = meter.create_counter( | ||
name="sold items", | ||
description="number of sold items", | ||
unit="item", | ||
value_type=int, | ||
) | ||
|
||
customers_in_store = meter.create_up_down_counter( | ||
name="customers in store", | ||
description="amount of customers present in store", | ||
unit="customer", | ||
value_type=int, | ||
) | ||
|
||
|
||
class GroceryStore: | ||
def __init__(self, name): | ||
self._name = name | ||
|
||
def process_order(self, customer_name, potatoes=0, tomatoes=0): | ||
order_counter.add(1, {"store": self._name, "customer": customer_name}) | ||
|
||
amount_counter.add( | ||
(potatoes * 1) + (tomatoes * 3), | ||
{"store": self._name, "customer": customer_name}, | ||
) | ||
|
||
sold_items_counter.add( | ||
potatoes, | ||
{ | ||
"store": self._name, | ||
"customer": customer_name, | ||
"item": "potato", | ||
}, | ||
) | ||
|
||
sold_items_counter.add( | ||
tomatoes, | ||
{ | ||
"store": self._name, | ||
"customer": customer_name, | ||
"item": "tomato", | ||
}, | ||
) | ||
|
||
def enter_customer(self, customer_name, account_type): | ||
|
||
customers_in_store.add( | ||
1, {"store": self._name, "account_type": account_type} | ||
) | ||
|
||
def exit_customer(self, customer_name, account_type): | ||
|
||
customers_in_store.add( | ||
-1, {"store": self._name, "account_type": account_type} | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,5 +8,6 @@ OpenTelemetry Python SDK | |
|
||
resources | ||
trace | ||
metrics | ||
error_handler | ||
environment_variables |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,216 @@ | ||
# 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=abstract-class-instantiated | ||
# pylint: disable=too-many-ancestors | ||
# pylint: disable=useless-super-delegation | ||
|
||
|
||
from abc import ABC, abstractmethod | ||
from functools import wraps | ||
from logging import getLogger | ||
from typing import cast | ||
|
||
from opentelemetry.environment_variables import OTEL_PYTHON_METER_PROVIDER | ||
from opentelemetry.metrics.instrument import ( | ||
Counter, | ||
DefaultCounter, | ||
DefaultHistogram, | ||
DefaultObservableCounter, | ||
DefaultObservableGauge, | ||
DefaultObservableUpDownCounter, | ||
DefaultUpDownCounter, | ||
Histogram, | ||
ObservableCounter, | ||
ObservableGauge, | ||
ObservableUpDownCounter, | ||
UpDownCounter, | ||
) | ||
from opentelemetry.util._providers import _load_provider | ||
from opentelemetry.util.types import Attributes | ||
|
||
_logger = getLogger(__name__) | ||
|
||
|
||
class Measurement(ABC): | ||
@abstractmethod | ||
def __init__(self, value, **attributes: Attributes): | ||
pass | ||
|
||
|
||
class DefaultMeasurement(Measurement): | ||
def __init__(self, value, **attributes: Attributes): | ||
super().__init__(value, **attributes) | ||
|
||
|
||
class Meter(ABC): | ||
|
||
# FIXME make unit and description be "" if unit or description are None | ||
@abstractmethod | ||
def create_counter(self, name, unit=None, description=None) -> Counter: | ||
pass | ||
|
||
@abstractmethod | ||
def create_up_down_counter( | ||
self, name, unit=None, description=None | ||
) -> UpDownCounter: | ||
pass | ||
|
||
@abstractmethod | ||
def create_observable_counter( | ||
self, name, callback, unit=None, description=None | ||
) -> ObservableCounter: | ||
pass | ||
|
||
@abstractmethod | ||
def create_histogram(self, name, unit=None, description=None) -> Histogram: | ||
pass | ||
|
||
@abstractmethod | ||
def create_observable_gauge( | ||
self, name, callback, unit=None, description=None | ||
) -> ObservableGauge: | ||
pass | ||
|
||
@abstractmethod | ||
def create_observable_up_down_counter( | ||
self, name, callback, unit=None, description=None | ||
) -> ObservableUpDownCounter: | ||
pass | ||
|
||
@staticmethod | ||
def check_unique_name(checker): | ||
def wrapper_0(method): | ||
@wraps(method) | ||
def wrapper_1(self, name, unit=None, description=None): | ||
checker(self, name) | ||
return method(self, name, unit=unit, description=description) | ||
|
||
return wrapper_1 | ||
|
||
return wrapper_0 | ||
|
||
|
||
class DefaultMeter(Meter): | ||
def __init__(self): | ||
self._instrument_names = set() | ||
|
||
def _instrument_name_checker(self, name): | ||
|
||
if name in self._instrument_names: | ||
raise Exception("Instrument name {} has been used already") | ||
|
||
self._instrument_names.add(name) | ||
|
||
@Meter.check_unique_name(_instrument_name_checker) | ||
def create_counter(self, name, unit=None, description=None) -> Counter: | ||
return DefaultCounter(name, unit=unit, description=description) | ||
|
||
@Meter.check_unique_name(_instrument_name_checker) | ||
def create_up_down_counter( | ||
self, name, unit=None, description=None | ||
) -> UpDownCounter: | ||
return DefaultUpDownCounter(name, unit=unit, description=description) | ||
|
||
@Meter.check_unique_name(_instrument_name_checker) | ||
def create_observable_counter( | ||
self, name, callback, unit=None, description=None | ||
) -> ObservableCounter: | ||
return DefaultObservableCounter( | ||
name, | ||
callback, | ||
unit=unit, | ||
description=description, | ||
) | ||
|
||
@Meter.check_unique_name(_instrument_name_checker) | ||
def create_histogram(self, name, unit=None, description=None) -> Histogram: | ||
return DefaultHistogram(name, unit=unit, description=description) | ||
|
||
@Meter.check_unique_name(_instrument_name_checker) | ||
def create_observable_gauge( | ||
self, name, callback, unit=None, description=None | ||
) -> ObservableGauge: | ||
return DefaultObservableGauge( # pylint: disable=abstract-class-instantiated | ||
name, | ||
callback, | ||
unit=unit, | ||
description=description, | ||
) | ||
|
||
@Meter.check_unique_name(_instrument_name_checker) | ||
def create_observable_up_down_counter( | ||
self, name, callback, unit=None, description=None | ||
) -> ObservableUpDownCounter: | ||
return DefaultObservableUpDownCounter( # pylint: disable=abstract-class-instantiated | ||
name, | ||
callback, | ||
unit=unit, | ||
description=description, | ||
) | ||
|
||
|
||
class MeterProvider(ABC): | ||
""" | ||
var | ||
""" | ||
|
||
@abstractmethod | ||
def get_meter( | ||
self, | ||
name, | ||
version=None, | ||
schema_url=None, | ||
) -> Meter: | ||
""" | ||
vpas | ||
""" | ||
pass | ||
|
||
|
||
class DefaultMeterProvider(MeterProvider): | ||
def get_meter( | ||
self, | ||
name, | ||
version=None, | ||
schema_url=None, | ||
) -> Meter: | ||
return DefaultMeter() | ||
|
||
|
||
_METER_PROVIDER = None | ||
|
||
|
||
def set_meter_provider(meter_provider: MeterProvider) -> None: | ||
"""Sets the current global :class:`~.MeterProvider` object.""" | ||
global _METER_PROVIDER # pylint: disable=global-statement | ||
|
||
if _METER_PROVIDER is not None: | ||
_logger.warning("Overriding of current MeterProvider is not allowed") | ||
return | ||
|
||
_METER_PROVIDER = meter_provider | ||
|
||
|
||
def get_meter_provider() -> MeterProvider: | ||
"""Gets the current global :class:`~.MeterProvider` object.""" | ||
global _METER_PROVIDER # pylint: disable=global-statement | ||
|
||
if _METER_PROVIDER is None: | ||
_METER_PROVIDER = cast( | ||
"MeterProvider", | ||
_load_provider(OTEL_PYTHON_METER_PROVIDER, "meter_provider"), | ||
) | ||
|
||
return _METER_PROVIDER |
Oops, something went wrong.