aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/azure/core/tracing
diff options
context:
space:
mode:
Diffstat (limited to '.venv/lib/python3.12/site-packages/azure/core/tracing')
-rw-r--r--.venv/lib/python3.12/site-packages/azure/core/tracing/__init__.py12
-rw-r--r--.venv/lib/python3.12/site-packages/azure/core/tracing/_abstract_span.py321
-rw-r--r--.venv/lib/python3.12/site-packages/azure/core/tracing/common.py108
-rw-r--r--.venv/lib/python3.12/site-packages/azure/core/tracing/decorator.py120
-rw-r--r--.venv/lib/python3.12/site-packages/azure/core/tracing/decorator_async.py129
-rw-r--r--.venv/lib/python3.12/site-packages/azure/core/tracing/ext/__init__.py0
-rw-r--r--.venv/lib/python3.12/site-packages/azure/core/tracing/ext/opentelemetry_span/__init__.py416
-rw-r--r--.venv/lib/python3.12/site-packages/azure/core/tracing/ext/opentelemetry_span/_schema.py60
-rw-r--r--.venv/lib/python3.12/site-packages/azure/core/tracing/ext/opentelemetry_span/_version.py6
-rw-r--r--.venv/lib/python3.12/site-packages/azure/core/tracing/ext/opentelemetry_span/py.typed0
10 files changed, 1172 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/azure/core/tracing/__init__.py b/.venv/lib/python3.12/site-packages/azure/core/tracing/__init__.py
new file mode 100644
index 00000000..ecf6fe6d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/azure/core/tracing/__init__.py
@@ -0,0 +1,12 @@
+# ------------------------------------
+# Copyright (c) Microsoft Corporation.
+# Licensed under the MIT License.
+# ------------------------------------
+from azure.core.tracing._abstract_span import (
+ AbstractSpan,
+ SpanKind,
+ HttpSpanMixin,
+ Link,
+)
+
+__all__ = ["AbstractSpan", "SpanKind", "HttpSpanMixin", "Link"]
diff --git a/.venv/lib/python3.12/site-packages/azure/core/tracing/_abstract_span.py b/.venv/lib/python3.12/site-packages/azure/core/tracing/_abstract_span.py
new file mode 100644
index 00000000..f97507da
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/azure/core/tracing/_abstract_span.py
@@ -0,0 +1,321 @@
+# ------------------------------------
+# Copyright (c) Microsoft Corporation.
+# Licensed under the MIT License.
+# ------------------------------------
+"""Protocol that defines what functions wrappers of tracing libraries should implement."""
+from __future__ import annotations
+from enum import Enum
+from urllib.parse import urlparse
+
+from typing import (
+ Any,
+ Sequence,
+ Optional,
+ Union,
+ Callable,
+ Dict,
+ Type,
+ Generic,
+ TypeVar,
+)
+from types import TracebackType
+from typing_extensions import Protocol, ContextManager, runtime_checkable
+from azure.core.pipeline.transport import HttpRequest, HttpResponse, AsyncHttpResponse
+from azure.core.rest import (
+ HttpResponse as RestHttpResponse,
+ AsyncHttpResponse as AsyncRestHttpResponse,
+ HttpRequest as RestHttpRequest,
+)
+
+HttpResponseType = Union[HttpResponse, AsyncHttpResponse, RestHttpResponse, AsyncRestHttpResponse]
+HttpRequestType = Union[HttpRequest, RestHttpRequest]
+
+AttributeValue = Union[
+ str,
+ bool,
+ int,
+ float,
+ Sequence[str],
+ Sequence[bool],
+ Sequence[int],
+ Sequence[float],
+]
+Attributes = Dict[str, AttributeValue]
+SpanType = TypeVar("SpanType")
+
+
+class SpanKind(Enum):
+ UNSPECIFIED = 1
+ SERVER = 2
+ CLIENT = 3
+ PRODUCER = 4
+ CONSUMER = 5
+ INTERNAL = 6
+
+
+@runtime_checkable
+class AbstractSpan(Protocol, Generic[SpanType]):
+ """Wraps a span from a distributed tracing implementation.
+
+ If a span is given wraps the span. Else a new span is created.
+ The optional argument name is given to the new span.
+
+ :param span: The span to wrap
+ :type span: Any
+ :param name: The name of the span
+ :type name: str
+ """
+
+ def __init__(self, span: Optional[SpanType] = None, name: Optional[str] = None, **kwargs: Any) -> None:
+ pass
+
+ def span(self, name: str = "child_span", **kwargs: Any) -> AbstractSpan[SpanType]:
+ """
+ Create a child span for the current span and append it to the child spans list.
+ The child span must be wrapped by an implementation of AbstractSpan
+
+ :param name: The name of the child span
+ :type name: str
+ :return: The child span
+ :rtype: AbstractSpan
+ """
+ ...
+
+ @property
+ def kind(self) -> Optional[SpanKind]:
+ """Get the span kind of this span.
+
+ :rtype: SpanKind
+ :return: The span kind of this span
+ """
+ ...
+
+ @kind.setter
+ def kind(self, value: SpanKind) -> None:
+ """Set the span kind of this span.
+
+ :param value: The span kind of this span
+ :type value: SpanKind
+ """
+ ...
+
+ def __enter__(self) -> AbstractSpan[SpanType]:
+ """Start a span."""
+ ...
+
+ def __exit__(
+ self,
+ exception_type: Optional[Type[BaseException]],
+ exception_value: Optional[BaseException],
+ traceback: TracebackType,
+ ) -> None:
+ """Finish a span.
+
+ :param exception_type: The type of the exception
+ :type exception_type: type
+ :param exception_value: The value of the exception
+ :type exception_value: Exception
+ :param traceback: The traceback of the exception
+ :type traceback: Traceback
+ """
+ ...
+
+ def start(self) -> None:
+ """Set the start time for a span."""
+ ...
+
+ def finish(self) -> None:
+ """Set the end time for a span."""
+ ...
+
+ def to_header(self) -> Dict[str, str]:
+ """Returns a dictionary with the header labels and values.
+
+ :return: A dictionary with the header labels and values
+ :rtype: dict
+ """
+ ...
+
+ def add_attribute(self, key: str, value: Union[str, int]) -> None:
+ """
+ Add attribute (key value pair) to the current span.
+
+ :param key: The key of the key value pair
+ :type key: str
+ :param value: The value of the key value pair
+ :type value: Union[str, int]
+ """
+ ...
+
+ def set_http_attributes(self, request: HttpRequestType, response: Optional[HttpResponseType] = None) -> None:
+ """
+ Add correct attributes for a http client span.
+
+ :param request: The request made
+ :type request: azure.core.rest.HttpRequest
+ :param response: The response received by the server. Is None if no response received.
+ :type response: ~azure.core.pipeline.transport.HttpResponse or ~azure.core.pipeline.transport.AsyncHttpResponse
+ """
+ ...
+
+ def get_trace_parent(self) -> str:
+ """Return traceparent string.
+
+ :return: a traceparent string
+ :rtype: str
+ """
+ ...
+
+ @property
+ def span_instance(self) -> SpanType:
+ """
+ Returns the span the class is wrapping.
+ """
+ ...
+
+ @classmethod
+ def link(cls, traceparent: str, attributes: Optional[Attributes] = None) -> None:
+ """
+ Given a traceparent, extracts the context and links the context to the current tracer.
+
+ :param traceparent: A string representing a traceparent
+ :type traceparent: str
+ :param attributes: Any additional attributes that should be added to link
+ :type attributes: dict
+ """
+ ...
+
+ @classmethod
+ def link_from_headers(cls, headers: Dict[str, str], attributes: Optional[Attributes] = None) -> None:
+ """
+ Given a dictionary, extracts the context and links the context to the current tracer.
+
+ :param headers: A dictionary of the request header as key value pairs.
+ :type headers: dict
+ :param attributes: Any additional attributes that should be added to link
+ :type attributes: dict
+ """
+ ...
+
+ @classmethod
+ def get_current_span(cls) -> SpanType:
+ """
+ Get the current span from the execution context. Return None otherwise.
+
+ :return: The current span
+ :rtype: AbstractSpan
+ """
+ ...
+
+ @classmethod
+ def get_current_tracer(cls) -> Any:
+ """
+ Get the current tracer from the execution context. Return None otherwise.
+
+ :return: The current tracer
+ :rtype: Any
+ """
+ ...
+
+ @classmethod
+ def set_current_span(cls, span: SpanType) -> None:
+ """Set the given span as the current span in the execution context.
+
+ :param span: The span to set as the current span
+ :type span: Any
+ """
+ ...
+
+ @classmethod
+ def set_current_tracer(cls, tracer: Any) -> None:
+ """Set the given tracer as the current tracer in the execution context.
+
+ :param tracer: The tracer to set as the current tracer
+ :type tracer: Any
+ """
+ ...
+
+ @classmethod
+ def change_context(cls, span: SpanType) -> ContextManager[SpanType]:
+ """Change the context for the life of this context manager.
+
+ :param span: The span to run in the new context
+ :type span: Any
+ :rtype: contextmanager
+ :return: A context manager that will run the given span in the new context
+ """
+ ...
+
+ @classmethod
+ def with_current_context(cls, func: Callable) -> Callable:
+ """Passes the current spans to the new context the function will be run in.
+
+ :param func: The function that will be run in the new context
+ :type func: callable
+ :return: The target the pass in instead of the function
+ :rtype: callable
+ """
+ ...
+
+
+class HttpSpanMixin:
+ """Can be used to get HTTP span attributes settings for free."""
+
+ _SPAN_COMPONENT = "component"
+ _HTTP_USER_AGENT = "http.user_agent"
+ _HTTP_METHOD = "http.method"
+ _HTTP_URL = "http.url"
+ _HTTP_STATUS_CODE = "http.status_code"
+ _NET_PEER_NAME = "net.peer.name"
+ _NET_PEER_PORT = "net.peer.port"
+ _ERROR_TYPE = "error.type"
+
+ def set_http_attributes(
+ self: AbstractSpan,
+ request: HttpRequestType,
+ response: Optional[HttpResponseType] = None,
+ ) -> None:
+ """
+ Add correct attributes for a http client span.
+
+ :param request: The request made
+ :type request: azure.core.rest.HttpRequest
+ :param response: The response received from the server. Is None if no response received.
+ :type response: ~azure.core.pipeline.transport.HttpResponse or ~azure.core.pipeline.transport.AsyncHttpResponse
+ """
+ # Also see https://github.com/python/mypy/issues/5837
+ self.kind = SpanKind.CLIENT
+ self.add_attribute(HttpSpanMixin._SPAN_COMPONENT, "http")
+ self.add_attribute(HttpSpanMixin._HTTP_METHOD, request.method)
+ self.add_attribute(HttpSpanMixin._HTTP_URL, request.url)
+
+ parsed_url = urlparse(request.url)
+ if parsed_url.hostname:
+ self.add_attribute(HttpSpanMixin._NET_PEER_NAME, parsed_url.hostname)
+ if parsed_url.port and parsed_url.port not in [80, 443]:
+ self.add_attribute(HttpSpanMixin._NET_PEER_PORT, parsed_url.port)
+
+ user_agent = request.headers.get("User-Agent")
+ if user_agent:
+ self.add_attribute(HttpSpanMixin._HTTP_USER_AGENT, user_agent)
+ if response and response.status_code:
+ self.add_attribute(HttpSpanMixin._HTTP_STATUS_CODE, response.status_code)
+ if response.status_code >= 400:
+ self.add_attribute(HttpSpanMixin._ERROR_TYPE, str(response.status_code))
+ else:
+ self.add_attribute(HttpSpanMixin._HTTP_STATUS_CODE, 504)
+ self.add_attribute(HttpSpanMixin._ERROR_TYPE, "504")
+
+
+class Link:
+ """
+ This is a wrapper class to link the context to the current tracer.
+ :param headers: A dictionary of the request header as key value pairs.
+ :type headers: dict
+ :param attributes: Any additional attributes that should be added to link
+ :type attributes: dict
+ """
+
+ def __init__(self, headers: Dict[str, str], attributes: Optional[Attributes] = None) -> None:
+ self.headers = headers
+ self.attributes = attributes
diff --git a/.venv/lib/python3.12/site-packages/azure/core/tracing/common.py b/.venv/lib/python3.12/site-packages/azure/core/tracing/common.py
new file mode 100644
index 00000000..a74d67df
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/azure/core/tracing/common.py
@@ -0,0 +1,108 @@
+# --------------------------------------------------------------------------
+#
+# Copyright (c) Microsoft Corporation. All rights reserved.
+#
+# The MIT License (MIT)
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the ""Software""), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# --------------------------------------------------------------------------
+"""Common functions shared by both the sync and the async decorators."""
+from contextlib import contextmanager
+from typing import Any, Optional, Callable, Type, Generator
+import warnings
+
+from ._abstract_span import AbstractSpan
+from ..settings import settings
+
+
+__all__ = [
+ "change_context",
+ "with_current_context",
+]
+
+
+def get_function_and_class_name(func: Callable, *args: object) -> str:
+ """
+ Given a function and its unamed arguments, returns class_name.function_name. It assumes the first argument
+ is `self`. If there are no arguments then it only returns the function name.
+
+ :param func: the function passed in
+ :type func: callable
+ :param args: List of arguments passed into the function
+ :type args: list
+ :return: The function name with the class name
+ :rtype: str
+ """
+ try:
+ return func.__qualname__
+ except AttributeError:
+ if args:
+ return "{}.{}".format(args[0].__class__.__name__, func.__name__)
+ return func.__name__
+
+
+@contextmanager
+def change_context(span: Optional[AbstractSpan]) -> Generator:
+ """Execute this block inside the given context and restore it afterwards.
+
+ This does not start and ends the span, but just make sure all code is executed within
+ that span.
+
+ If span is None, no-op.
+
+ :param span: A span
+ :type span: AbstractSpan
+ :rtype: contextmanager
+ :return: A context manager that will run the given span in the new context
+ """
+ span_impl_type: Optional[Type[AbstractSpan]] = settings.tracing_implementation()
+ if span_impl_type is None or span is None:
+ yield
+ else:
+ try:
+ with span_impl_type.change_context(span):
+ yield
+ except AttributeError:
+ # This plugin does not support "change_context"
+ warnings.warn(
+ 'Your tracing plugin should be updated to support "change_context"',
+ DeprecationWarning,
+ )
+ original_span = span_impl_type.get_current_span()
+ try:
+ span_impl_type.set_current_span(span)
+ yield
+ finally:
+ span_impl_type.set_current_span(original_span)
+
+
+def with_current_context(func: Callable) -> Any:
+ """Passes the current spans to the new context the function will be run in.
+
+ :param func: The function that will be run in the new context
+ :type func: callable
+ :return: The func wrapped with correct context
+ :rtype: callable
+ """
+ span_impl_type: Optional[Type[AbstractSpan]] = settings.tracing_implementation()
+ if span_impl_type is None:
+ return func
+
+ return span_impl_type.with_current_context(func)
diff --git a/.venv/lib/python3.12/site-packages/azure/core/tracing/decorator.py b/.venv/lib/python3.12/site-packages/azure/core/tracing/decorator.py
new file mode 100644
index 00000000..adca3aff
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/azure/core/tracing/decorator.py
@@ -0,0 +1,120 @@
+# --------------------------------------------------------------------------
+#
+# Copyright (c) Microsoft Corporation. All rights reserved.
+#
+# The MIT License (MIT)
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the ""Software""), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# --------------------------------------------------------------------------
+"""The decorator to apply if you want the given function traced."""
+
+import functools
+
+from typing import Callable, Any, TypeVar, overload, Optional, Mapping, TYPE_CHECKING
+from typing_extensions import ParamSpec
+from .common import change_context, get_function_and_class_name
+from . import SpanKind as _SpanKind
+from ..settings import settings
+
+if TYPE_CHECKING:
+ from azure.core.tracing import SpanKind
+
+P = ParamSpec("P")
+T = TypeVar("T")
+
+
+@overload
+def distributed_trace(__func: Callable[P, T]) -> Callable[P, T]:
+ pass
+
+
+@overload
+def distributed_trace(
+ *,
+ name_of_span: Optional[str] = None,
+ kind: Optional["SpanKind"] = None,
+ tracing_attributes: Optional[Mapping[str, Any]] = None,
+ **kwargs: Any,
+) -> Callable[[Callable[P, T]], Callable[P, T]]:
+ pass
+
+
+def distributed_trace(
+ __func: Optional[Callable[P, T]] = None, # pylint: disable=unused-argument
+ *,
+ name_of_span: Optional[str] = None,
+ kind: Optional["SpanKind"] = None,
+ tracing_attributes: Optional[Mapping[str, Any]] = None,
+ **kwargs: Any,
+) -> Any:
+ """Decorator to apply to function to get traced automatically.
+
+ Span will use the func name or "name_of_span".
+
+ Note:
+
+ This decorator SHOULD NOT be used by application developers. It's
+ intended to be called by Azure client libraries only.
+
+ Application developers should use OpenTelemetry or other tracing libraries to
+ instrument their applications.
+
+ :param callable __func: A function to decorate
+ :keyword name_of_span: The span name to replace func name if necessary
+ :paramtype name_of_span: str
+ :keyword kind: The kind of the span. INTERNAL by default.
+ :paramtype kind: ~azure.core.tracing.SpanKind
+ :keyword tracing_attributes: Attributes to add to the span.
+ :paramtype tracing_attributes: Mapping[str, Any] or None
+ :return: The decorated function
+ :rtype: Any
+ """
+ if tracing_attributes is None:
+ tracing_attributes = {}
+ if kind is None:
+ kind = _SpanKind.INTERNAL
+
+ def decorator(func: Callable[P, T]) -> Callable[P, T]:
+ @functools.wraps(func)
+ def wrapper_use_tracer(*args: Any, **kwargs: Any) -> T:
+ merge_span = kwargs.pop("merge_span", False)
+ passed_in_parent = kwargs.pop("parent_span", None)
+
+ # Assume this will be popped in DistributedTracingPolicy.
+ func_tracing_attributes = kwargs.pop("tracing_attributes", tracing_attributes)
+
+ span_impl_type = settings.tracing_implementation()
+ if span_impl_type is None:
+ return func(*args, **kwargs)
+
+ # Merge span is parameter is set, but only if no explicit parent are passed
+ if merge_span and not passed_in_parent:
+ return func(*args, **kwargs)
+
+ with change_context(passed_in_parent):
+ name = name_of_span or get_function_and_class_name(func, *args)
+ with span_impl_type(name=name, kind=kind) as span:
+ for key, value in func_tracing_attributes.items():
+ span.add_attribute(key, value)
+ return func(*args, **kwargs)
+
+ return wrapper_use_tracer
+
+ return decorator if __func is None else decorator(__func)
diff --git a/.venv/lib/python3.12/site-packages/azure/core/tracing/decorator_async.py b/.venv/lib/python3.12/site-packages/azure/core/tracing/decorator_async.py
new file mode 100644
index 00000000..f17081d1
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/azure/core/tracing/decorator_async.py
@@ -0,0 +1,129 @@
+# --------------------------------------------------------------------------
+#
+# Copyright (c) Microsoft Corporation. All rights reserved.
+#
+# The MIT License (MIT)
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the ""Software""), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# --------------------------------------------------------------------------
+"""The decorator to apply if you want the given function traced."""
+
+import functools
+
+from typing import (
+ Awaitable,
+ Callable,
+ Any,
+ TypeVar,
+ overload,
+ Optional,
+ Mapping,
+ TYPE_CHECKING,
+)
+from typing_extensions import ParamSpec
+from .common import change_context, get_function_and_class_name
+from . import SpanKind as _SpanKind
+from ..settings import settings
+
+if TYPE_CHECKING:
+ from azure.core.tracing import SpanKind
+
+P = ParamSpec("P")
+T = TypeVar("T")
+
+
+@overload
+def distributed_trace_async(__func: Callable[P, Awaitable[T]]) -> Callable[P, Awaitable[T]]:
+ pass
+
+
+@overload
+def distributed_trace_async(
+ *,
+ name_of_span: Optional[str] = None,
+ kind: Optional["SpanKind"] = None,
+ tracing_attributes: Optional[Mapping[str, Any]] = None,
+ **kwargs: Any,
+) -> Callable[[Callable[P, Awaitable[T]]], Callable[P, Awaitable[T]]]:
+ pass
+
+
+def distributed_trace_async( # pylint: disable=unused-argument
+ __func: Optional[Callable[P, Awaitable[T]]] = None,
+ *,
+ name_of_span: Optional[str] = None,
+ kind: Optional["SpanKind"] = None,
+ tracing_attributes: Optional[Mapping[str, Any]] = None,
+ **kwargs: Any,
+) -> Any:
+ """Decorator to apply to function to get traced automatically.
+
+ Span will use the func name or "name_of_span".
+
+ Note:
+
+ This decorator SHOULD NOT be used by application developers. It's
+ intended to be called by Azure client libraries only.
+
+ Application developers should use OpenTelemetry or other tracing libraries to
+ instrument their applications.
+
+ :param callable __func: A function to decorate
+ :keyword name_of_span: The span name to replace func name if necessary
+ :paramtype name_of_span: str
+ :keyword kind: The kind of the span. INTERNAL by default.
+ :paramtype kind: ~azure.core.tracing.SpanKind
+ :keyword tracing_attributes: Attributes to add to the span.
+ :paramtype tracing_attributes: Mapping[str, Any] or None
+ :return: The decorated function
+ :rtype: Any
+ """
+ if tracing_attributes is None:
+ tracing_attributes = {}
+ if kind is None:
+ kind = _SpanKind.INTERNAL
+
+ def decorator(func: Callable[P, Awaitable[T]]) -> Callable[P, Awaitable[T]]:
+ @functools.wraps(func)
+ async def wrapper_use_tracer(*args: Any, **kwargs: Any) -> T:
+ merge_span = kwargs.pop("merge_span", False)
+ passed_in_parent = kwargs.pop("parent_span", None)
+
+ # Assume this will be popped in DistributedTracingPolicy.
+ func_tracing_attributes = kwargs.get("tracing_attributes", tracing_attributes)
+
+ span_impl_type = settings.tracing_implementation()
+ if span_impl_type is None:
+ return await func(*args, **kwargs)
+
+ # Merge span is parameter is set, but only if no explicit parent are passed
+ if merge_span and not passed_in_parent:
+ return await func(*args, **kwargs)
+
+ with change_context(passed_in_parent):
+ name = name_of_span or get_function_and_class_name(func, *args)
+ with span_impl_type(name=name, kind=kind) as span:
+ for key, value in func_tracing_attributes.items():
+ span.add_attribute(key, value)
+ return await func(*args, **kwargs)
+
+ return wrapper_use_tracer
+
+ return decorator if __func is None else decorator(__func)
diff --git a/.venv/lib/python3.12/site-packages/azure/core/tracing/ext/__init__.py b/.venv/lib/python3.12/site-packages/azure/core/tracing/ext/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/azure/core/tracing/ext/__init__.py
diff --git a/.venv/lib/python3.12/site-packages/azure/core/tracing/ext/opentelemetry_span/__init__.py b/.venv/lib/python3.12/site-packages/azure/core/tracing/ext/opentelemetry_span/__init__.py
new file mode 100644
index 00000000..c142d2d2
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/azure/core/tracing/ext/opentelemetry_span/__init__.py
@@ -0,0 +1,416 @@
+# ------------------------------------
+# Copyright (c) Microsoft Corporation.
+# Licensed under the MIT License.
+# ------------------------------------
+"""Implements azure.core.tracing.AbstractSpan to wrap OpenTelemetry spans."""
+from typing import Any, ContextManager, Dict, Optional, Union, Callable, Sequence, cast, List
+import warnings
+
+from opentelemetry import context, trace
+from opentelemetry.trace import (
+ Span,
+ Status,
+ StatusCode,
+ Tracer,
+ NonRecordingSpan,
+ SpanKind as OpenTelemetrySpanKind,
+ Link as OpenTelemetryLink,
+) # type: ignore[attr-defined]
+from opentelemetry.propagate import extract, inject # type: ignore[attr-defined]
+from opentelemetry.trace.propagation import get_current_span as get_span_from_context # type: ignore[attr-defined]
+
+# TODO: Fix import of this private attribute once the location of the suppress instrumentation key is defined.
+try:
+ from opentelemetry.context import _SUPPRESS_HTTP_INSTRUMENTATION_KEY # type: ignore[attr-defined]
+except ImportError:
+ _SUPPRESS_HTTP_INSTRUMENTATION_KEY = "suppress_http_instrumentation"
+
+from azure.core.tracing import SpanKind, HttpSpanMixin, Link as CoreLink # type: ignore[attr-defined] # pylint: disable=no-name-in-module
+
+from ._schema import OpenTelemetrySchema, OpenTelemetrySchemaVersion as _OpenTelemetrySchemaVersion
+from ._version import VERSION
+
+AttributeValue = Union[
+ str,
+ bool,
+ int,
+ float,
+ Sequence[str],
+ Sequence[bool],
+ Sequence[int],
+ Sequence[float],
+]
+Attributes = Dict[str, AttributeValue]
+
+__version__ = VERSION
+
+_SUPPRESSED_SPAN_FLAG = "SUPPRESSED_SPAN_FLAG"
+_LAST_UNSUPPRESSED_SPAN = "LAST_UNSUPPRESSED_SPAN"
+_ERROR_SPAN_ATTRIBUTE = "error.type"
+
+_OTEL_KIND_MAPPINGS = {
+ OpenTelemetrySpanKind.CLIENT: SpanKind.CLIENT,
+ OpenTelemetrySpanKind.CONSUMER: SpanKind.CONSUMER,
+ OpenTelemetrySpanKind.PRODUCER: SpanKind.PRODUCER,
+ OpenTelemetrySpanKind.SERVER: SpanKind.SERVER,
+ OpenTelemetrySpanKind.INTERNAL: SpanKind.INTERNAL,
+}
+
+_SPAN_KIND_MAPPINGS = {
+ SpanKind.CLIENT: OpenTelemetrySpanKind.CLIENT,
+ SpanKind.CONSUMER: OpenTelemetrySpanKind.CONSUMER,
+ SpanKind.PRODUCER: OpenTelemetrySpanKind.PRODUCER,
+ SpanKind.SERVER: OpenTelemetrySpanKind.SERVER,
+ SpanKind.INTERNAL: OpenTelemetrySpanKind.INTERNAL,
+ SpanKind.UNSPECIFIED: OpenTelemetrySpanKind.INTERNAL,
+}
+
+
+class _SuppressionContextManager(ContextManager):
+ def __init__(self, span: "OpenTelemetrySpan"):
+ self._span = span
+ self._context_token: Optional[object] = None
+ self._current_ctxt_manager: Optional[ContextManager[Span]] = None
+
+ def __enter__(self) -> Any:
+ ctx = context.get_current()
+ if not isinstance(self._span.span_instance, NonRecordingSpan):
+ if self._span.kind in (SpanKind.INTERNAL, SpanKind.CLIENT, SpanKind.PRODUCER):
+ # This is a client call that's reported for SDK service method.
+ # We're going to suppress all nested spans reported in the context of this call.
+ # We're not suppressing anything in the scope of SERVER or CONSUMER spans because
+ # those wrap user code which may do HTTP requests and call other SDKs.
+ ctx = context.set_value(_SUPPRESSED_SPAN_FLAG, True, ctx)
+ # Since core already instruments HTTP calls, we need to suppress any automatic HTTP instrumentation
+ # provided by other libraries to prevent duplicate spans. This has no effect if no automatic HTTP
+ # instrumentation libraries are being used.
+ ctx = context.set_value(_SUPPRESS_HTTP_INSTRUMENTATION_KEY, True, ctx)
+
+ # Since the span is not suppressed, let's keep a reference to it in the context so that children spans
+ # always have access to the last non-suppressed parent span.
+ ctx = context.set_value(_LAST_UNSUPPRESSED_SPAN, self._span, ctx)
+ ctx = trace.set_span_in_context(self._span._span_instance, ctx)
+ self._context_token = context.attach(ctx)
+
+ return self
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ if self._context_token:
+ context.detach(self._context_token)
+ self._context_token = None
+
+
+class OpenTelemetrySpan(HttpSpanMixin, object):
+ """OpenTelemetry plugin for Azure client libraries.
+
+ :param span: The OpenTelemetry span to wrap, or nothing to create a new one.
+ :type span: ~OpenTelemetry.trace.Span
+ :param name: The name of the OpenTelemetry span to create if a new span is needed
+ :type name: str
+ :keyword kind: The span kind of this span.
+ :paramtype kind: ~azure.core.tracing.SpanKind
+ :keyword links: The list of links to be added to the span.
+ :paramtype links: list[~azure.core.tracing.Link]
+ :keyword context: Context headers of parent span that should be used when creating a new span.
+ :paramtype context: Dict[str, str]
+ :keyword schema_version: The OpenTelemetry schema version to use for the span.
+ :paramtype schema_version: str
+ """
+
+ def __init__(
+ self,
+ span: Optional[Span] = None,
+ name: Optional[str] = "span",
+ *,
+ kind: Optional["SpanKind"] = None,
+ links: Optional[List["CoreLink"]] = None,
+ **kwargs: Any,
+ ) -> None:
+ self._current_ctxt_manager: Optional[_SuppressionContextManager] = None
+ self._schema_version = kwargs.pop("schema_version", _OpenTelemetrySchemaVersion.V1_19_0)
+ self._attribute_mappings = OpenTelemetrySchema.get_attribute_mappings(self._schema_version)
+
+ if span:
+ self._span_instance = span
+ return
+
+ ## kind
+ span_kind = kind
+ otel_kind = _SPAN_KIND_MAPPINGS.get(span_kind)
+
+ if span_kind and otel_kind is None:
+ raise ValueError("Kind {} is not supported in OpenTelemetry".format(span_kind))
+
+ if otel_kind == OpenTelemetrySpanKind.INTERNAL and context.get_value(_SUPPRESSED_SPAN_FLAG):
+ # Nested internal calls should be suppressed per the Azure SDK guidelines.
+ self._span_instance = NonRecordingSpan(context=self.get_current_span().get_span_context())
+ return
+
+ current_tracer = trace.get_tracer(
+ __name__,
+ __version__,
+ schema_url=OpenTelemetrySchema.get_schema_url(self._schema_version),
+ )
+
+ if links:
+ try:
+ ot_links = []
+ for link in links:
+ ctx = extract(link.headers)
+ span_ctx = get_span_from_context(ctx).get_span_context()
+ ot_links.append(OpenTelemetryLink(span_ctx, link.attributes))
+ kwargs.setdefault("links", ot_links)
+ except AttributeError:
+ # We will just send the links as is if it's not ~azure.core.tracing.Link without any validation
+ # assuming user knows what they are doing.
+ kwargs.setdefault("links", links)
+
+ parent_context = kwargs.pop("context", None)
+ if parent_context:
+ # Create OpenTelemetry Context object from dict.
+ kwargs["context"] = extract(parent_context)
+
+ self._span_instance = current_tracer.start_span(name=name, kind=otel_kind, **kwargs) # type: ignore
+
+ @property
+ def span_instance(self) -> Span:
+ """The OpenTelemetry span that is being wrapped.
+
+ :rtype: ~openTelemetry.trace.Span
+ """
+ return self._span_instance
+
+ def span(
+ self,
+ name: str = "span",
+ *,
+ kind: Optional["SpanKind"] = None,
+ links: Optional[List["CoreLink"]] = None,
+ **kwargs: Any,
+ ) -> "OpenTelemetrySpan":
+ """Create a child span for the current span and return it.
+
+ :param name: Name of the child span
+ :type name: str
+ :keyword kind: The span kind of this span.
+ :paramtype kind: ~azure.core.tracing.SpanKind
+ :keyword links: The list of links to be added to the span.
+ :paramtype links: list[Link]
+ :return: The OpenTelemetrySpan that is wrapping the child span instance.
+ :rtype: ~azure.core.tracing.ext.opentelemetry_span.OpenTelemetrySpan
+ """
+ return self.__class__(name=name, kind=kind, links=links, **kwargs)
+
+ @property
+ def kind(self) -> Optional[SpanKind]:
+ """Get the span kind of this span."""
+ try:
+ value = self.span_instance.kind # type: ignore[attr-defined]
+ except AttributeError:
+ return None
+ return _OTEL_KIND_MAPPINGS.get(value)
+
+ @kind.setter
+ def kind(self, value: SpanKind) -> None:
+ """Set the span kind of this span.
+
+ :param value: The span kind to set.
+ :type value: ~azure.core.tracing.SpanKind
+ """
+ kind = _SPAN_KIND_MAPPINGS.get(value)
+ if kind is None:
+ raise ValueError("Kind {} is not supported in OpenTelemetry".format(value))
+ try:
+ self._span_instance._kind = kind # type: ignore[attr-defined] # pylint: disable=protected-access
+ except AttributeError:
+ warnings.warn(
+ """Kind must be set while creating the span for OpenTelemetry. It might be possible
+ that one of the packages you are using doesn't follow the latest Opentelemetry Spec.
+ Try updating the azure packages to the latest versions."""
+ )
+
+ def __enter__(self) -> "OpenTelemetrySpan":
+ self._current_ctxt_manager = _SuppressionContextManager(self)
+ self._current_ctxt_manager.__enter__()
+ return self
+
+ def __exit__(self, exception_type, exception_value, traceback) -> None:
+ # Finish the span.
+ if exception_type:
+ module = exception_type.__module__ if exception_type.__module__ != "builtins" else ""
+ error_type = f"{module}.{exception_type.__qualname__}" if module else exception_type.__qualname__
+ self.add_attribute(_ERROR_SPAN_ATTRIBUTE, error_type)
+
+ self.span_instance.set_status(
+ Status(
+ status_code=StatusCode.ERROR,
+ description=f"{error_type}: {exception_value}",
+ )
+ )
+
+ self.finish()
+
+ # end the context manager.
+ if self._current_ctxt_manager:
+ self._current_ctxt_manager.__exit__(exception_type, exception_value, traceback)
+ self._current_ctxt_manager = None
+
+ def start(self) -> None:
+ # Spans are automatically started at their creation with OpenTelemetry.
+ pass
+
+ def finish(self) -> None:
+ """Set the end time for a span."""
+ self.span_instance.end()
+
+ def to_header(self) -> Dict[str, str]:
+ """Returns a dictionary with the context header labels and values.
+
+ These are generally the W3C Trace Context headers (i.e. "traceparent" and "tracestate").
+
+ :return: A key value pair dictionary
+ :rtype: dict[str, str]
+ """
+ temp_headers: Dict[str, str] = {}
+ inject(temp_headers)
+ return temp_headers
+
+ def add_attribute(self, key: str, value: Union[str, int]) -> None:
+ """Add attribute (key value pair) to the current span.
+
+ :param key: The key of the key value pair
+ :type key: str
+ :param value: The value of the key value pair
+ :type value: Union[str, int]
+ """
+ key = self._attribute_mappings.get(key, key)
+ self.span_instance.set_attribute(key, value)
+
+ def get_trace_parent(self) -> str:
+ """Return traceparent string as defined in W3C trace context specification.
+
+ Example:
+ Value = 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
+ base16(version) = 00
+ base16(trace-id) = 4bf92f3577b34da6a3ce929d0e0e4736
+ base16(parent-id) = 00f067aa0ba902b7
+ base16(trace-flags) = 01 // sampled
+
+ :return: a traceparent string
+ :rtype: str
+ """
+ return self.to_header()["traceparent"]
+
+ @classmethod
+ def link(cls, traceparent: str, attributes: Optional[Attributes] = None) -> None:
+ """Links the context to the current tracer.
+
+ :param traceparent: A complete traceparent
+ :type traceparent: str
+ :param attributes: Attributes to be added to the link
+ :type attributes: dict or None
+ """
+ cls.link_from_headers({"traceparent": traceparent}, attributes)
+
+ @classmethod
+ def link_from_headers(cls, headers: Dict[str, str], attributes: Optional[Attributes] = None) -> None:
+ """Given a dictionary, extracts the context and links the context to the current tracer.
+
+ :param headers: A key value pair dictionary
+ :type headers: dict
+ :param attributes: Attributes to be added to the link
+ :type attributes: dict or None
+ """
+ ctx = extract(headers)
+ span_ctx = get_span_from_context(ctx).get_span_context()
+ current_span = cls.get_current_span()
+ try:
+ current_span._links.append(OpenTelemetryLink(span_ctx, attributes)) # type: ignore # pylint: disable=protected-access
+ except AttributeError:
+ warnings.warn(
+ """Link must be added while creating the span for OpenTelemetry. It might be possible
+ that one of the packages you are using doesn't follow the latest Opentelemetry Spec.
+ Try updating the azure packages to the latest versions."""
+ )
+
+ @classmethod
+ def get_current_span(cls) -> Span:
+ """Get the current span from the execution context.
+
+ :return: The current span
+ :rtype: ~opentelemetry.trace.Span
+ """
+ span = get_span_from_context()
+ last_unsuppressed_parent = context.get_value(_LAST_UNSUPPRESSED_SPAN)
+ if isinstance(span, NonRecordingSpan) and last_unsuppressed_parent:
+ return cast(OpenTelemetrySpan, last_unsuppressed_parent).span_instance
+ return span
+
+ @classmethod
+ def get_current_tracer(cls) -> Tracer:
+ """Get the current tracer from the execution context.
+
+ :return: The current tracer
+ :rtype: ~opentelemetry.trace.Tracer
+ """
+ return trace.get_tracer(__name__, __version__)
+
+ @classmethod
+ def change_context(cls, span: Union[Span, "OpenTelemetrySpan"]) -> ContextManager:
+ """Change the context for the life of this context manager.
+
+ :param span: The span to use as the current span
+ :type span: ~opentelemetry.trace.Span
+ :return: A context manager to use for the duration of the span
+ :rtype: contextmanager
+ """
+
+ if isinstance(span, Span):
+ return trace.use_span(span, end_on_exit=False)
+
+ return _SuppressionContextManager(span)
+
+ @classmethod
+ def set_current_span(cls, span: Span) -> None: # pylint: disable=docstring-missing-return,docstring-missing-rtype
+ """Not supported by OpenTelemetry.
+
+ :param span: The span to set as the current span
+ :type span: ~opentelemetry.trace.Span
+ :raises: NotImplementedError
+ """
+ raise NotImplementedError(
+ "set_current_span is not supported by OpenTelemetry plugin. Use change_context instead."
+ )
+
+ @classmethod
+ def set_current_tracer(cls, tracer: Tracer) -> None: # pylint: disable=unused-argument
+ """Not supported by OpenTelemetry.
+
+ :param tracer: The tracer to set the current tracer as
+ :type tracer: ~opentelemetry.trace.Tracer
+ """
+ # Do nothing, if you're able to get two tracer with OpenTelemetry that's a surprise!
+ return
+
+ @classmethod
+ def with_current_context(cls, func: Callable) -> Callable:
+ """Passes the current spans to the new context the function will be run in.
+
+ :param func: The function that will be run in the new context
+ :type func: callable
+ :return: The target the pass in instead of the function
+ :rtype: callable
+ """
+ # returns the current Context object
+ current_context = context.get_current()
+
+ def call_with_current_context(*args, **kwargs):
+ token = None
+ try:
+ token = context.attach(current_context)
+ return func(*args, **kwargs)
+ finally:
+ if token is not None:
+ context.detach(token)
+
+ return call_with_current_context
diff --git a/.venv/lib/python3.12/site-packages/azure/core/tracing/ext/opentelemetry_span/_schema.py b/.venv/lib/python3.12/site-packages/azure/core/tracing/ext/opentelemetry_span/_schema.py
new file mode 100644
index 00000000..c5ffcc44
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/azure/core/tracing/ext/opentelemetry_span/_schema.py
@@ -0,0 +1,60 @@
+# ------------------------------------
+# Copyright (c) Microsoft Corporation.
+# Licensed under the MIT License.
+# ------------------------------------
+from enum import Enum
+from typing import Dict
+
+from azure.core import CaseInsensitiveEnumMeta # type: ignore[attr-defined] # pylint: disable=no-name-in-module
+
+
+class OpenTelemetrySchemaVersion(
+ str, Enum, metaclass=CaseInsensitiveEnumMeta
+): # pylint: disable=enum-must-inherit-case-insensitive-enum-meta
+
+ V1_19_0 = "1.19.0"
+ V1_23_1 = "1.23.1"
+
+
+class OpenTelemetrySchema:
+
+ SUPPORTED_VERSIONS = (
+ OpenTelemetrySchemaVersion.V1_19_0,
+ OpenTelemetrySchemaVersion.V1_23_1,
+ )
+
+ # Mappings of attributes potentially reported by Azure SDKs to corresponding ones that follow
+ # OpenTelemetry semantic conventions.
+ _ATTRIBUTE_MAPPINGS = {
+ OpenTelemetrySchemaVersion.V1_19_0: {
+ "x-ms-client-request-id": "az.client_request_id",
+ "x-ms-request-id": "az.service_request_id",
+ "http.user_agent": "user_agent.original",
+ "message_bus.destination": "messaging.destination.name",
+ "peer.address": "net.peer.name",
+ },
+ OpenTelemetrySchemaVersion.V1_23_1: {
+ "x-ms-client-request-id": "az.client_request_id",
+ "x-ms-request-id": "az.service_request_id",
+ "http.user_agent": "user_agent.original",
+ "message_bus.destination": "messaging.destination.name",
+ "peer.address": "server.address",
+ "http.method": "http.request.method",
+ "http.status_code": "http.response.status_code",
+ "net.peer.name": "server.address",
+ "net.peer.port": "server.port",
+ "http.url": "url.full",
+ },
+ }
+
+ @classmethod
+ def get_latest_version(cls) -> OpenTelemetrySchemaVersion:
+ return OpenTelemetrySchemaVersion(cls.SUPPORTED_VERSIONS[-1])
+
+ @classmethod
+ def get_attribute_mappings(cls, version: OpenTelemetrySchemaVersion) -> Dict[str, str]:
+ return cls._ATTRIBUTE_MAPPINGS.get(version, {})
+
+ @classmethod
+ def get_schema_url(cls, version: OpenTelemetrySchemaVersion) -> str:
+ return f"https://opentelemetry.io/schemas/{version}"
diff --git a/.venv/lib/python3.12/site-packages/azure/core/tracing/ext/opentelemetry_span/_version.py b/.venv/lib/python3.12/site-packages/azure/core/tracing/ext/opentelemetry_span/_version.py
new file mode 100644
index 00000000..3dc0587c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/azure/core/tracing/ext/opentelemetry_span/_version.py
@@ -0,0 +1,6 @@
+# ------------------------------------
+# Copyright (c) Microsoft Corporation.
+# Licensed under the MIT License.
+# ------------------------------------
+
+VERSION = "1.0.0b12"
diff --git a/.venv/lib/python3.12/site-packages/azure/core/tracing/ext/opentelemetry_span/py.typed b/.venv/lib/python3.12/site-packages/azure/core/tracing/ext/opentelemetry_span/py.typed
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/azure/core/tracing/ext/opentelemetry_span/py.typed