Initial Commit
This commit is contained in:
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,75 @@
|
||||
# Copyright The OpenTelemetry Authors
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import contextlib
|
||||
import functools
|
||||
import inspect
|
||||
from collections.abc import Callable, Iterator
|
||||
from typing import TYPE_CHECKING, Generic, TypeVar
|
||||
|
||||
V = TypeVar("V")
|
||||
R = TypeVar("R") # Return type
|
||||
Pargs = TypeVar("Pargs") # Generic type for arguments
|
||||
Pkwargs = TypeVar("Pkwargs") # Generic type for arguments
|
||||
|
||||
# We don't actually depend on typing_extensions but we can use it in CI with this conditional
|
||||
# import. ParamSpec can be imported directly from typing after python 3.9 is dropped
|
||||
# https://peps.python.org/pep-0612/.
|
||||
if TYPE_CHECKING:
|
||||
from typing_extensions import ParamSpec
|
||||
|
||||
P = ParamSpec("P") # Generic type for all arguments
|
||||
|
||||
|
||||
class _AgnosticContextManager(
|
||||
contextlib._GeneratorContextManager[R],
|
||||
Generic[R],
|
||||
): # pylint: disable=protected-access
|
||||
"""Context manager that can decorate both async and sync functions.
|
||||
|
||||
This is an overridden version of the contextlib._GeneratorContextManager
|
||||
class that will decorate async functions with an async context manager
|
||||
to end the span AFTER the entire async function coroutine finishes.
|
||||
|
||||
Else it will report near zero spans durations for async functions.
|
||||
|
||||
We are overriding the contextlib._GeneratorContextManager class as
|
||||
reimplementing it is a lot of code to maintain and this class (even if it's
|
||||
marked as protected) doesn't seems like to be evolving a lot.
|
||||
|
||||
For more information, see:
|
||||
https://github.com/open-telemetry/opentelemetry-python/pull/3633
|
||||
"""
|
||||
|
||||
def __enter__(self) -> R:
|
||||
"""Reimplementing __enter__ to avoid the type error.
|
||||
|
||||
The original __enter__ method returns Any type, but we want to return R.
|
||||
"""
|
||||
del self.args, self.kwds, self.func # type: ignore
|
||||
try:
|
||||
return next(self.gen) # type: ignore
|
||||
except StopIteration:
|
||||
raise RuntimeError("generator didn't yield") from None
|
||||
|
||||
def __call__(self, func: V) -> V: # pyright: ignore [reportIncompatibleMethodOverride]
|
||||
if inspect.iscoroutinefunction(func):
|
||||
|
||||
@functools.wraps(func) # type: ignore
|
||||
async def async_wrapper(*args: Pargs, **kwargs: Pkwargs) -> R: # pyright: ignore [reportInvalidTypeVarUse]
|
||||
with self._recreate_cm(): # type: ignore
|
||||
return await func(*args, **kwargs) # type: ignore
|
||||
|
||||
return async_wrapper # type: ignore
|
||||
return super().__call__(func) # type: ignore
|
||||
|
||||
|
||||
def _agnosticcontextmanager(
|
||||
func: "Callable[P, Iterator[R]]",
|
||||
) -> "Callable[P, _AgnosticContextManager[R]]":
|
||||
@functools.wraps(func)
|
||||
def helper(*args: Pargs, **kwargs: Pkwargs) -> _AgnosticContextManager[R]: # pyright: ignore [reportInvalidTypeVarUse]
|
||||
return _AgnosticContextManager(func, args, kwargs) # pyright: ignore [reportArgumentType]
|
||||
|
||||
# Ignoring the type to keep the original signature of the function
|
||||
return helper # type: ignore[return-value]
|
||||
@@ -0,0 +1,61 @@
|
||||
# Copyright The OpenTelemetry Authors
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
"""
|
||||
Caching and compatibility wrapper for standard library ``importlib.metadata``.
|
||||
|
||||
This module caches ``entry_points()`` to avoid reloading entry points from disk on every call.
|
||||
It also normalizes minor differences across python versions 3.10+. References to issues:
|
||||
|
||||
- https://github.com/open-telemetry/opentelemetry-python/pull/4735
|
||||
- https://github.com/open-telemetry/opentelemetry-python/pull/5203
|
||||
"""
|
||||
|
||||
import itertools
|
||||
from functools import cache
|
||||
from importlib.metadata import (
|
||||
Distribution,
|
||||
EntryPoint,
|
||||
EntryPoints,
|
||||
PackageNotFoundError,
|
||||
distributions,
|
||||
requires,
|
||||
version,
|
||||
)
|
||||
from importlib.metadata import entry_points as original_entry_points
|
||||
from typing import Any
|
||||
|
||||
|
||||
def _as_entry_points(eps: Any) -> EntryPoints:
|
||||
# Python versions greater than 3.11 return EntryPoints.
|
||||
if isinstance(eps, EntryPoints):
|
||||
return eps
|
||||
# In Python 3.10 and 3.11 entry_points() returns
|
||||
# a dict-like SelectableGroups object.
|
||||
# Use dict.values() instead of eps.values() to avoid the DeprecationWarning
|
||||
# that SelectableGroups raises when calling .values().
|
||||
if isinstance(eps, dict):
|
||||
return EntryPoints(itertools.chain.from_iterable(dict.values(eps)))
|
||||
# This case should be unreachable, but is included as a fallback.
|
||||
return EntryPoints(ep for group in eps.groups for ep in eps.select(group=group))
|
||||
|
||||
|
||||
@cache
|
||||
def _original_entry_points_cached() -> EntryPoints:
|
||||
return _as_entry_points(original_entry_points())
|
||||
|
||||
|
||||
def entry_points(**params) -> EntryPoints:
|
||||
return _original_entry_points_cached().select(**params)
|
||||
|
||||
|
||||
__all__ = [
|
||||
"Distribution",
|
||||
"EntryPoint",
|
||||
"EntryPoints",
|
||||
"PackageNotFoundError",
|
||||
"distributions",
|
||||
"entry_points",
|
||||
"requires",
|
||||
"version",
|
||||
]
|
||||
@@ -0,0 +1,36 @@
|
||||
# Copyright The OpenTelemetry Authors
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from collections.abc import Callable
|
||||
from threading import Lock
|
||||
|
||||
|
||||
class Once:
|
||||
"""Execute a function exactly once and block all callers until the function returns
|
||||
|
||||
Same as golang's `sync.Once <https://pkg.go.dev/sync#Once>`_
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._lock = Lock()
|
||||
self._done = False
|
||||
|
||||
def do_once(self, func: Callable[[], None]) -> bool:
|
||||
"""Execute ``func`` if it hasn't been executed or return.
|
||||
|
||||
Will block until ``func`` has been called by one thread.
|
||||
|
||||
Returns:
|
||||
Whether or not ``func`` was executed in this call
|
||||
"""
|
||||
|
||||
# fast path, try to avoid locking
|
||||
if self._done:
|
||||
return False
|
||||
|
||||
with self._lock:
|
||||
if not self._done:
|
||||
func()
|
||||
self._done = True
|
||||
return True
|
||||
return False
|
||||
@@ -0,0 +1,42 @@
|
||||
# Copyright The OpenTelemetry Authors
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from logging import getLogger
|
||||
from os import environ
|
||||
from typing import TYPE_CHECKING, TypeVar, cast
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from opentelemetry.metrics import MeterProvider
|
||||
from opentelemetry.trace import TracerProvider
|
||||
|
||||
Provider = TypeVar("Provider", "TracerProvider", "MeterProvider")
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
|
||||
def _load_provider(provider_environment_variable: str, provider: str) -> Provider: # type: ignore[type-var]
|
||||
# pylint: disable=import-outside-toplevel,no-name-in-module
|
||||
from opentelemetry.util._importlib_metadata import ( # noqa: PLC0415
|
||||
entry_points,
|
||||
)
|
||||
|
||||
try:
|
||||
provider_name = cast(
|
||||
str,
|
||||
environ.get(provider_environment_variable, f"default_{provider}"),
|
||||
)
|
||||
|
||||
return cast(
|
||||
Provider,
|
||||
next( # type: ignore
|
||||
iter( # type: ignore
|
||||
entry_points( # type: ignore
|
||||
group=f"opentelemetry_{provider}",
|
||||
name=provider_name,
|
||||
)
|
||||
)
|
||||
).load()(),
|
||||
)
|
||||
except Exception: # pylint: disable=broad-exception-caught
|
||||
logger.exception("Failed to load configured provider %s", provider)
|
||||
raise
|
||||
@@ -0,0 +1,93 @@
|
||||
# Copyright The OpenTelemetry Authors
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from collections.abc import Mapping
|
||||
from logging import getLogger
|
||||
from re import compile, split
|
||||
from urllib.parse import unquote
|
||||
|
||||
from typing_extensions import deprecated
|
||||
|
||||
_logger = getLogger(__name__)
|
||||
|
||||
# The following regexes reference this spec: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#specifying-headers-via-environment-variables
|
||||
|
||||
# Optional whitespace
|
||||
_OWS = r"[ \t]*"
|
||||
# A key contains printable US-ASCII characters except: SP and "(),/:;<=>?@[\]{}
|
||||
_KEY_FORMAT = r"[\x21\x23-\x27\x2a\x2b\x2d\x2e\x30-\x39\x41-\x5a\x5e-\x7a\x7c\x7e]+"
|
||||
# A value contains a URL-encoded UTF-8 string. The encoded form can contain any
|
||||
# printable US-ASCII characters (0x20-0x7f) other than SP, DEL, and ",;/
|
||||
_VALUE_FORMAT = r"[\x21\x23-\x2b\x2d-\x3a\x3c-\x5b\x5d-\x7e]*"
|
||||
# Like above with SP included
|
||||
_LIBERAL_VALUE_FORMAT = r"[\x20\x21\x23-\x2b\x2d-\x3a\x3c-\x5b\x5d-\x7e]*"
|
||||
# A key-value is key=value, with optional whitespace surrounding key and value
|
||||
_KEY_VALUE_FORMAT = rf"{_OWS}{_KEY_FORMAT}{_OWS}={_OWS}{_VALUE_FORMAT}{_OWS}"
|
||||
|
||||
_HEADER_PATTERN = compile(_KEY_VALUE_FORMAT)
|
||||
_LIBERAL_HEADER_PATTERN = compile(rf"{_OWS}{_KEY_FORMAT}{_OWS}={_OWS}{_LIBERAL_VALUE_FORMAT}{_OWS}")
|
||||
_DELIMITER_PATTERN = compile(r"[ \t]*,[ \t]*")
|
||||
|
||||
_BAGGAGE_PROPERTY_FORMAT = rf"{_KEY_VALUE_FORMAT}|{_OWS}{_KEY_FORMAT}{_OWS}"
|
||||
|
||||
_INVALID_HEADER_ERROR_MESSAGE_STRICT_TEMPLATE = (
|
||||
"Header format invalid! Header values in environment variables must be "
|
||||
"URL encoded per the OpenTelemetry Protocol Exporter specification: %s"
|
||||
)
|
||||
|
||||
_INVALID_HEADER_ERROR_MESSAGE_LIBERAL_TEMPLATE = (
|
||||
"Header format invalid! Header values in environment variables must be "
|
||||
"URL encoded per the OpenTelemetry Protocol Exporter specification or "
|
||||
"a comma separated list of name=value occurrences: %s"
|
||||
)
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
|
||||
|
||||
@deprecated("You should use parse_env_headers. Deprecated since version 1.15.0.")
|
||||
def parse_headers(s: str) -> Mapping[str, str]:
|
||||
return parse_env_headers(s)
|
||||
|
||||
|
||||
def parse_env_headers(s: str, liberal: bool = False) -> Mapping[str, str]:
|
||||
"""
|
||||
Parse ``s``, which is a ``str`` instance containing HTTP headers encoded
|
||||
for use in ENV variables per the W3C Baggage HTTP header format at
|
||||
https://www.w3.org/TR/baggage/#baggage-http-header-format, except that
|
||||
additional semi-colon delimited metadata is not supported.
|
||||
If ``liberal`` is True we try to parse ``s`` anyway to be more compatible
|
||||
with other languages SDKs that accept non URL-encoded headers by default.
|
||||
"""
|
||||
headers: dict[str, str] = {}
|
||||
headers_list: list[str] = split(_DELIMITER_PATTERN, s)
|
||||
for header in headers_list:
|
||||
if not header: # empty string
|
||||
continue
|
||||
header_match = _HEADER_PATTERN.fullmatch(header.strip())
|
||||
if not header_match and not liberal:
|
||||
_logger.warning(_INVALID_HEADER_ERROR_MESSAGE_STRICT_TEMPLATE, header)
|
||||
continue
|
||||
|
||||
if header_match:
|
||||
match_string: str = header_match.string
|
||||
# value may contain any number of `=`
|
||||
name, value = match_string.split("=", 1)
|
||||
name = unquote(name).strip().lower()
|
||||
value = unquote(value).strip()
|
||||
headers[name] = value
|
||||
else:
|
||||
# this is not url-encoded and does not match the spec but we decided to be
|
||||
# liberal in what we accept to match other languages SDKs behaviour
|
||||
liberal_header_match = _LIBERAL_HEADER_PATTERN.fullmatch(header.strip())
|
||||
if not liberal_header_match:
|
||||
_logger.warning(_INVALID_HEADER_ERROR_MESSAGE_LIBERAL_TEMPLATE, header)
|
||||
continue
|
||||
|
||||
liberal_match_string: str = liberal_header_match.string
|
||||
# value may contain any number of `=`
|
||||
name, value = liberal_match_string.split("=", 1)
|
||||
name = name.strip().lower()
|
||||
value = value.strip()
|
||||
headers[name] = value
|
||||
|
||||
return headers
|
||||
@@ -0,0 +1,28 @@
|
||||
# Copyright The OpenTelemetry Authors
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from collections.abc import Mapping, Sequence
|
||||
from typing import TypeAlias
|
||||
|
||||
# This is the implementation of the "Any" type as specified by the specifications of OpenTelemetry data model for logs.
|
||||
# For more details, refer to the OTel specification:
|
||||
# https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/data-model.md#type-any
|
||||
AnyValue: TypeAlias = str | bool | int | float | bytes | Sequence["AnyValue"] | Mapping[str, "AnyValue"] | None
|
||||
AttributeValue: TypeAlias = AnyValue
|
||||
Attributes = Mapping[str, AnyValue] | None
|
||||
|
||||
# Deprecated type, do not use.
|
||||
AttributesAsKey = tuple[
|
||||
tuple[
|
||||
str,
|
||||
str
|
||||
| bool
|
||||
| int
|
||||
| float
|
||||
| tuple[str | None, ...]
|
||||
| tuple[bool | None, ...]
|
||||
| tuple[int | None, ...]
|
||||
| tuple[float | None, ...],
|
||||
],
|
||||
...,
|
||||
]
|
||||
Reference in New Issue
Block a user