Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
__init__.py679 linesDownload Raw Back to trace
1# Copyright The OpenTelemetry Authors2#3# Licensed under the Apache License, Version 2.0 (the "License");4# you may not use this file except in compliance with the License.5# You may obtain a copy of the License at6#7#     http://www.apache.org/licenses/LICENSE-2.08#9# Unless required by applicable law or agreed to in writing, software10# distributed under the License is distributed on an "AS IS" BASIS,11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12# See the License for the specific language governing permissions and13# limitations under the License.14 15"""16The OpenTelemetry tracing API describes the classes used to generate17distributed traces.18 19The :class:`.Tracer` class controls access to the execution context, and20manages span creation. Each operation in a trace is represented by a21:class:`.Span`, which records the start, end time, and metadata associated with22the operation.23 24This module provides abstract (i.e. unimplemented) classes required for25tracing, and a concrete no-op :class:`.NonRecordingSpan` that allows applications26to use the API package alone without a supporting implementation.27 28To get a tracer, you need to provide the package name from which you are29calling the tracer APIs to OpenTelemetry by calling `TracerProvider.get_tracer`30with the calling module name and the version of your package.31 32The tracer supports creating spans that are "attached" or "detached" from the33context. New spans are "attached" to the context in that they are34created as children of the currently active span, and the newly-created span35can optionally become the new active span::36 37    from opentelemetry import trace38 39    tracer = trace.get_tracer(__name__)40 41    # Create a new root span, set it as the current span in context42    with tracer.start_as_current_span("parent"):43        # Attach a new child and update the current span44        with tracer.start_as_current_span("child"):45            do_work():46        # Close child span, set parent as current47    # Close parent span, set default span as current48 49When creating a span that's "detached" from the context the active span doesn't50change, and the caller is responsible for managing the span's lifetime::51 52    # Explicit parent span assignment is done via the Context53    from opentelemetry.trace import set_span_in_context54 55    context = set_span_in_context(parent)56    child = tracer.start_span("child", context=context)57 58    try:59        do_work(span=child)60    finally:61        child.end()62 63Applications should generally use a single global TracerProvider, and use64either implicit or explicit context propagation consistently throughout.65 66.. versionadded:: 0.1.067.. versionchanged:: 0.3.068    `TracerProvider` was introduced and the global ``tracer`` getter was69    replaced by ``tracer_provider``.70.. versionchanged:: 0.5.071    ``tracer_provider`` was replaced by `get_tracer_provider`,72    ``set_preferred_tracer_provider_implementation`` was replaced by73    `set_tracer_provider`.74"""75 76import os77import typing78from abc import ABC, abstractmethod79from enum import Enum80from logging import getLogger81from typing import Iterator, Optional, Sequence, cast82 83from typing_extensions import deprecated84 85from opentelemetry import context as context_api86from opentelemetry.attributes import BoundedAttributes87from opentelemetry.context.context import Context88from opentelemetry.environment_variables import OTEL_PYTHON_TRACER_PROVIDER89from opentelemetry.trace.propagation import (90    _SPAN_KEY,91    get_current_span,92    set_span_in_context,93)94from opentelemetry.trace.span import (95    DEFAULT_TRACE_OPTIONS,96    DEFAULT_TRACE_STATE,97    INVALID_SPAN,98    INVALID_SPAN_CONTEXT,99    INVALID_SPAN_ID,100    INVALID_TRACE_ID,101    NonRecordingSpan,102    Span,103    SpanContext,104    TraceFlags,105    TraceState,106    format_span_id,107    format_trace_id,108)109from opentelemetry.trace.status import Status, StatusCode110from opentelemetry.util import types111from opentelemetry.util._decorator import _agnosticcontextmanager112from opentelemetry.util._once import Once113from opentelemetry.util._providers import _load_provider114 115logger = getLogger(__name__)116 117 118class _LinkBase(ABC):119    def __init__(self, context: "SpanContext") -> None:120        self._context = context121 122    @property123    def context(self) -> "SpanContext":124        return self._context125 126    @property127    @abstractmethod128    def attributes(self) -> types.Attributes:129        pass130 131 132class Link(_LinkBase):133    """A link to a `Span`. The attributes of a Link are immutable.134 135    Args:136        context: `SpanContext` of the `Span` to link to.137        attributes: Link's attributes.138    """139 140    def __init__(141        self,142        context: "SpanContext",143        attributes: types.Attributes = None,144    ) -> None:145        super().__init__(context)146        self._attributes = attributes147 148    @property149    def attributes(self) -> types.Attributes:150        return self._attributes151 152    @property153    def dropped_attributes(self) -> int:154        if isinstance(self._attributes, BoundedAttributes):155            return self._attributes.dropped156        return 0157 158 159_Links = Optional[Sequence[Link]]160 161 162class SpanKind(Enum):163    """Specifies additional details on how this span relates to its parent span.164 165    Note that this enumeration is experimental and likely to change. See166    https://github.com/open-telemetry/opentelemetry-specification/pull/226.167    """168 169    #: Default value. Indicates that the span is used internally in the170    # application.171    INTERNAL = 0172 173    #: Indicates that the span describes an operation that handles a remote174    # request.175    SERVER = 1176 177    #: Indicates that the span describes a request to some remote service.178    CLIENT = 2179 180    #: Indicates that the span describes a producer sending a message to a181    #: broker. Unlike client and server, there is usually no direct critical182    #: path latency relationship between producer and consumer spans.183    PRODUCER = 3184 185    #: Indicates that the span describes a consumer receiving a message from a186    #: broker. Unlike client and server, there is usually no direct critical187    #: path latency relationship between producer and consumer spans.188    CONSUMER = 4189 190 191class TracerProvider(ABC):192    @abstractmethod193    def get_tracer(194        self,195        instrumenting_module_name: str,196        instrumenting_library_version: typing.Optional[str] = None,197        schema_url: typing.Optional[str] = None,198        attributes: typing.Optional[types.Attributes] = None,199    ) -> "Tracer":200        """Returns a `Tracer` for use by the given instrumentation library.201 202        For any two calls it is undefined whether the same or different203        `Tracer` instances are returned, even for different library names.204 205        This function may return different `Tracer` types (e.g. a no-op tracer206        vs.  a functional tracer).207 208        Args:209            instrumenting_module_name: The uniquely identifiable name for instrumentation210                scope, such as instrumentation library, package, module or class name.211                ``__name__`` should be avoided as this can result in212                different tracer names if the tracers are in different files.213                It is better to use a fixed string that can be imported where214                needed and used consistently as the name of the tracer.215 216                This should *not* be the name of the module that is217                instrumented but the name of the module doing the instrumentation.218                E.g., instead of ``"requests"``, use219                ``"opentelemetry.instrumentation.requests"``.220 221            instrumenting_library_version: Optional. The version string of the222                instrumenting library.  Usually this should be the same as223                ``importlib.metadata.version(instrumenting_library_name)``.224 225            schema_url: Optional. Specifies the Schema URL of the emitted telemetry.226            attributes: Optional. Specifies the attributes of the emitted telemetry.227        """228 229 230class NoOpTracerProvider(TracerProvider):231    """The default TracerProvider, used when no implementation is available.232 233    All operations are no-op.234    """235 236    def get_tracer(237        self,238        instrumenting_module_name: str,239        instrumenting_library_version: typing.Optional[str] = None,240        schema_url: typing.Optional[str] = None,241        attributes: typing.Optional[types.Attributes] = None,242    ) -> "Tracer":243        # pylint:disable=no-self-use,unused-argument244        return NoOpTracer()245 246 247@deprecated(248    "You should use NoOpTracerProvider. Deprecated since version 1.9.0."249)250class _DefaultTracerProvider(NoOpTracerProvider):251    """The default TracerProvider, used when no implementation is available.252 253    All operations are no-op.254    """255 256 257class ProxyTracerProvider(TracerProvider):258    def get_tracer(259        self,260        instrumenting_module_name: str,261        instrumenting_library_version: typing.Optional[str] = None,262        schema_url: typing.Optional[str] = None,263        attributes: typing.Optional[types.Attributes] = None,264    ) -> "Tracer":265        if _TRACER_PROVIDER:266            return _TRACER_PROVIDER.get_tracer(267                instrumenting_module_name,268                instrumenting_library_version,269                schema_url,270                attributes,271            )272        return ProxyTracer(273            instrumenting_module_name,274            instrumenting_library_version,275            schema_url,276            attributes,277        )278 279 280class Tracer(ABC):281    """Handles span creation and in-process context propagation.282 283    This class provides methods for manipulating the context, creating spans,284    and controlling spans' lifecycles.285    """286 287    @abstractmethod288    def start_span(289        self,290        name: str,291        context: Optional[Context] = None,292        kind: SpanKind = SpanKind.INTERNAL,293        attributes: types.Attributes = None,294        links: _Links = None,295        start_time: Optional[int] = None,296        record_exception: bool = True,297        set_status_on_exception: bool = True,298    ) -> "Span":299        """Starts a span.300 301        Create a new span. Start the span without setting it as the current302        span in the context. To start the span and use the context in a single303        method, see :meth:`start_as_current_span`.304 305        By default the current span in the context will be used as parent, but an306        explicit context can also be specified, by passing in a `Context` containing307        a current `Span`. If there is no current span in the global `Context` or in308        the specified context, the created span will be a root span.309 310        The span can be used as a context manager. On exiting the context manager,311        the span's end() method will be called.312 313        Example::314 315            # trace.get_current_span() will be used as the implicit parent.316            # If none is found, the created span will be a root instance.317            with tracer.start_span("one") as child:318                child.add_event("child's event")319 320        Args:321            name: The name of the span to be created.322            context: An optional Context containing the span's parent. Defaults to the323                global context.324            kind: The span's kind (relationship to parent). Note that is325                meaningful even if there is no parent.326            attributes: The span's attributes.327            links: Links span to other spans328            start_time: Sets the start time of a span329            record_exception: Whether to record any exceptions raised within the330                context as error event on the span.331            set_status_on_exception: Only relevant if the returned span is used332                in a with/context manager. Defines whether the span status will333                be automatically set to ERROR when an uncaught exception is334                raised in the span with block. The span status won't be set by335                this mechanism if it was previously set manually.336 337        Returns:338            The newly-created span.339        """340 341    @_agnosticcontextmanager342    @abstractmethod343    def start_as_current_span(344        self,345        name: str,346        context: Optional[Context] = None,347        kind: SpanKind = SpanKind.INTERNAL,348        attributes: types.Attributes = None,349        links: _Links = None,350        start_time: Optional[int] = None,351        record_exception: bool = True,352        set_status_on_exception: bool = True,353        end_on_exit: bool = True,354    ) -> Iterator["Span"]:355        """Context manager for creating a new span and set it356        as the current span in this tracer's context.357 358        Exiting the context manager will call the span's end method,359        as well as return the current span to its previous value by360        returning to the previous context.361 362        Example::363 364            with tracer.start_as_current_span("one") as parent:365                parent.add_event("parent's event")366                with tracer.start_as_current_span("two") as child:367                    child.add_event("child's event")368                    trace.get_current_span()  # returns child369                trace.get_current_span()      # returns parent370            trace.get_current_span()          # returns previously active span371 372        This is a convenience method for creating spans attached to the373        tracer's context. Applications that need more control over the span374        lifetime should use :meth:`start_span` instead. For example::375 376            with tracer.start_as_current_span(name) as span:377                do_work()378 379        is equivalent to::380 381            span = tracer.start_span(name)382            with opentelemetry.trace.use_span(span, end_on_exit=True):383                do_work()384 385        This can also be used as a decorator::386 387            @tracer.start_as_current_span("name")388            def function():389                ...390 391            function()392 393        Args:394            name: The name of the span to be created.395            context: An optional Context containing the span's parent. Defaults to the396                global context.397            kind: The span's kind (relationship to parent). Note that is398                meaningful even if there is no parent.399            attributes: The span's attributes.400            links: Links span to other spans401            start_time: Sets the start time of a span402            record_exception: Whether to record any exceptions raised within the403                context as error event on the span.404            set_status_on_exception: Only relevant if the returned span is used405                in a with/context manager. Defines whether the span status will406                be automatically set to ERROR when an uncaught exception is407                raised in the span with block. The span status won't be set by408                this mechanism if it was previously set manually.409            end_on_exit: Whether to end the span automatically when leaving the410                context manager.411 412        Yields:413            The newly-created span.414        """415 416 417class ProxyTracer(Tracer):418    # pylint: disable=W0222,signature-differs419    def __init__(420        self,421        instrumenting_module_name: str,422        instrumenting_library_version: typing.Optional[str] = None,423        schema_url: typing.Optional[str] = None,424        attributes: typing.Optional[types.Attributes] = None,425    ):426        self._instrumenting_module_name = instrumenting_module_name427        self._instrumenting_library_version = instrumenting_library_version428        self._schema_url = schema_url429        self._attributes = attributes430        self._real_tracer: Optional[Tracer] = None431        self._noop_tracer = NoOpTracer()432 433    @property434    def _tracer(self) -> Tracer:435        if self._real_tracer:436            return self._real_tracer437 438        if _TRACER_PROVIDER:439            self._real_tracer = _TRACER_PROVIDER.get_tracer(440                self._instrumenting_module_name,441                self._instrumenting_library_version,442                self._schema_url,443                self._attributes,444            )445            return self._real_tracer446        return self._noop_tracer447 448    def start_span(self, *args, **kwargs) -> Span:  # type: ignore449        return self._tracer.start_span(*args, **kwargs)  # type: ignore450 451    @_agnosticcontextmanager  # type: ignore452    def start_as_current_span(self, *args, **kwargs) -> Iterator[Span]:453        with self._tracer.start_as_current_span(*args, **kwargs) as span:  # type: ignore454            yield span455 456 457class NoOpTracer(Tracer):458    """The default Tracer, used when no Tracer implementation is available.459 460    All operations are no-op.461    """462 463    def start_span(464        self,465        name: str,466        context: Optional[Context] = None,467        kind: SpanKind = SpanKind.INTERNAL,468        attributes: types.Attributes = None,469        links: _Links = None,470        start_time: Optional[int] = None,471        record_exception: bool = True,472        set_status_on_exception: bool = True,473    ) -> "Span":474        current_span = get_current_span(context)475        if isinstance(current_span, NonRecordingSpan):476            return current_span477        parent_span_context = current_span.get_span_context()478        if parent_span_context is not None and not isinstance(479            parent_span_context, SpanContext480        ):481            logger.warning(482                "Invalid span context for %s: %s",483                current_span,484                parent_span_context,485            )486            return INVALID_SPAN487 488        return NonRecordingSpan(context=parent_span_context)489 490    @_agnosticcontextmanager491    def start_as_current_span(492        self,493        name: str,494        context: Optional[Context] = None,495        kind: SpanKind = SpanKind.INTERNAL,496        attributes: types.Attributes = None,497        links: _Links = None,498        start_time: Optional[int] = None,499        record_exception: bool = True,500        set_status_on_exception: bool = True,501        end_on_exit: bool = True,502    ) -> Iterator["Span"]:503        span = self.start_span(504            name=name,505            context=context,506            kind=kind,507            attributes=attributes,508            links=links,509            start_time=start_time,510            record_exception=record_exception,511            set_status_on_exception=set_status_on_exception,512        )513        with use_span(514            span,515            end_on_exit=end_on_exit,516            record_exception=record_exception,517            set_status_on_exception=set_status_on_exception,518        ) as span:519            yield span520 521 522@deprecated("You should use NoOpTracer. Deprecated since version 1.9.0.")523class _DefaultTracer(NoOpTracer):524    """The default Tracer, used when no Tracer implementation is available.525 526    All operations are no-op.527    """528 529 530_TRACER_PROVIDER_SET_ONCE = Once()531_TRACER_PROVIDER: Optional[TracerProvider] = None532_PROXY_TRACER_PROVIDER = ProxyTracerProvider()533 534 535def get_tracer(536    instrumenting_module_name: str,537    instrumenting_library_version: typing.Optional[str] = None,538    tracer_provider: Optional[TracerProvider] = None,539    schema_url: typing.Optional[str] = None,540    attributes: typing.Optional[types.Attributes] = None,541) -> "Tracer":542    """Returns a `Tracer` for use by the given instrumentation library.543 544    This function is a convenience wrapper for545    opentelemetry.trace.TracerProvider.get_tracer.546 547    If tracer_provider is omitted the current configured one is used.548    """549    if tracer_provider is None:550        tracer_provider = get_tracer_provider()551    return tracer_provider.get_tracer(552        instrumenting_module_name,553        instrumenting_library_version,554        schema_url,555        attributes,556    )557 558 559def _set_tracer_provider(tracer_provider: TracerProvider, log: bool) -> None:560    def set_tp() -> None:561        global _TRACER_PROVIDER  # pylint: disable=global-statement562        _TRACER_PROVIDER = tracer_provider563 564    did_set = _TRACER_PROVIDER_SET_ONCE.do_once(set_tp)565 566    if log and not did_set:567        logger.warning("Overriding of current TracerProvider is not allowed")568 569 570def set_tracer_provider(tracer_provider: TracerProvider) -> None:571    """Sets the current global :class:`~.TracerProvider` object.572 573    This can only be done once, a warning will be logged if any further attempt574    is made.575    """576    _set_tracer_provider(tracer_provider, log=True)577 578 579def get_tracer_provider() -> TracerProvider:580    """Gets the current global :class:`~.TracerProvider` object."""581    if _TRACER_PROVIDER is None:582        # if a global tracer provider has not been set either via code or env583        # vars, return a proxy tracer provider584        if OTEL_PYTHON_TRACER_PROVIDER not in os.environ:585            return _PROXY_TRACER_PROVIDER586 587        tracer_provider: TracerProvider = _load_provider(588            OTEL_PYTHON_TRACER_PROVIDER, "tracer_provider"589        )590        _set_tracer_provider(tracer_provider, log=False)591    # _TRACER_PROVIDER will have been set by one thread592    return cast("TracerProvider", _TRACER_PROVIDER)593 594 595@_agnosticcontextmanager596def use_span(597    span: Span,598    end_on_exit: bool = False,599    record_exception: bool = True,600    set_status_on_exception: bool = True,601) -> Iterator[Span]:602    """Takes a non-active span and activates it in the current context.603 604    Args:605        span: The span that should be activated in the current context.606        end_on_exit: Whether to end the span automatically when leaving the607            context manager scope.608        record_exception: Whether to record any exceptions raised within the609            context as error event on the span.610        set_status_on_exception: Only relevant if the returned span is used611            in a with/context manager. Defines whether the span status will612            be automatically set to ERROR when an uncaught exception is613            raised in the span with block. The span status won't be set by614            this mechanism if it was previously set manually.615    """616    try:617        token = context_api.attach(context_api.set_value(_SPAN_KEY, span))618        try:619            yield span620        finally:621            context_api.detach(token)622 623    # Record only exceptions that inherit Exception class but not BaseException, because624    # classes that directly inherit BaseException are not technically errors, e.g. GeneratorExit.625    # See https://github.com/open-telemetry/opentelemetry-python/issues/4484626    except Exception as exc:  # pylint: disable=broad-exception-caught627        if isinstance(span, Span) and span.is_recording():628            # Record the exception as an event629            if record_exception:630                span.record_exception(exc)631 632            # Set status in case exception was raised633            if set_status_on_exception:634                span.set_status(635                    Status(636                        status_code=StatusCode.ERROR,637                        description=f"{type(exc).__name__}: {exc}",638                    )639                )640 641        # This causes parent spans to set their status to ERROR and to record642        # an exception as an event if a child span raises an exception even if643        # such child span was started with both record_exception and644        # set_status_on_exception attributes set to False.645        raise646 647    finally:648        if end_on_exit:649            span.end()650 651 652__all__ = [653    "DEFAULT_TRACE_OPTIONS",654    "DEFAULT_TRACE_STATE",655    "INVALID_SPAN",656    "INVALID_SPAN_CONTEXT",657    "INVALID_SPAN_ID",658    "INVALID_TRACE_ID",659    "NonRecordingSpan",660    "Link",661    "Span",662    "SpanContext",663    "SpanKind",664    "TraceFlags",665    "TraceState",666    "TracerProvider",667    "Tracer",668    "format_span_id",669    "format_trace_id",670    "get_current_span",671    "get_tracer",672    "get_tracer_provider",673    "set_tracer_provider",674    "set_span_in_context",675    "use_span",676    "Status",677    "StatusCode",678]679 
codekingpro/portable-devtools · Team Ai