trace.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. # Copyright 2024 The Chromium Authors
  2. # Use of this source code is governed by a BSD-style license that can be
  3. # found in the LICENSE file.
  4. """Tracer, Provider and span context."""
  5. import contextlib
  6. from typing import Any, Iterator, Optional, Sequence
  7. import logging
  8. import pathlib
  9. import sys
  10. from opentelemetry import context as otel_context_api
  11. from opentelemetry import trace as otel_trace_api
  12. from opentelemetry.sdk import trace as otel_trace_sdk
  13. from opentelemetry.util import types as otel_types
  14. from . import config
  15. from . import clearcut_span_exporter
  16. from . import detector
  17. @contextlib.contextmanager
  18. def use_span(
  19. span: otel_trace_api.Span,
  20. end_on_exit: bool = False,
  21. record_exception: bool = True,
  22. set_status_on_exception: bool = True,
  23. ) -> Iterator[otel_trace_api.Span]:
  24. """Takes a non-active span and activates it in the current context."""
  25. try:
  26. token = otel_context_api.attach(
  27. # This is needed since the key needs to be the same as
  28. # used in the rest of opentelemetry code.
  29. otel_context_api.set_value(otel_trace_api._SPAN_KEY, span))
  30. try:
  31. yield span
  32. finally:
  33. otel_context_api.detach(token)
  34. except KeyboardInterrupt as exc:
  35. if span.is_recording():
  36. if record_exception:
  37. span.record_exception(exc)
  38. if set_status_on_exception:
  39. span.set_status(otel_trace_api.StatusCode.OK)
  40. raise
  41. except BaseException as exc:
  42. if span.is_recording():
  43. # Record the exception as an event
  44. if record_exception:
  45. span.record_exception(exc)
  46. # Set status in case exception was raised
  47. if set_status_on_exception:
  48. span.set_status(
  49. otel_trace_api.Status(
  50. status_code=otel_trace_api.StatusCode.ERROR,
  51. description=f"{type(exc).__name__}: {exc}",
  52. ))
  53. raise
  54. finally:
  55. if end_on_exit:
  56. span.end()
  57. class Tracer(otel_trace_api.Tracer):
  58. """Specific otel tracer."""
  59. def __init__(self, inner: otel_trace_sdk.Tracer) -> None:
  60. self._inner = inner
  61. def start_span(
  62. self,
  63. name: str,
  64. context: Optional[otel_context_api.Context] = None,
  65. kind: otel_trace_api.SpanKind = otel_trace_api.SpanKind.INTERNAL,
  66. attributes: otel_types.Attributes = None,
  67. links: Optional[Sequence[otel_trace_api.Link]] = None,
  68. start_time: Optional[int] = None,
  69. record_exception: bool = True,
  70. set_status_on_exception: bool = True,
  71. ) -> otel_trace_api.Span:
  72. return self._inner.start_span(
  73. name,
  74. context=context,
  75. kind=kind,
  76. attributes=attributes,
  77. links=links,
  78. start_time=start_time,
  79. record_exception=record_exception,
  80. set_status_on_exception=set_status_on_exception,
  81. )
  82. @contextlib.contextmanager
  83. def start_as_current_span(
  84. self,
  85. name: str,
  86. context: Optional[otel_context_api.Context] = None,
  87. kind: otel_trace_api.SpanKind = otel_trace_api.SpanKind.INTERNAL,
  88. attributes: otel_types.Attributes = None,
  89. links: Optional[Sequence[otel_trace_api.Link]] = None,
  90. start_time: Optional[int] = None,
  91. record_exception: bool = True,
  92. set_status_on_exception: bool = True,
  93. end_on_exit: bool = True,
  94. ) -> Iterator[otel_trace_api.Span]:
  95. span = self.start_span(
  96. name=name,
  97. context=context,
  98. kind=kind,
  99. attributes=attributes,
  100. links=links,
  101. start_time=start_time,
  102. record_exception=record_exception,
  103. set_status_on_exception=set_status_on_exception,
  104. )
  105. with use_span(
  106. span,
  107. end_on_exit=end_on_exit,
  108. record_exception=record_exception,
  109. set_status_on_exception=set_status_on_exception,
  110. ) as span_context:
  111. yield span_context
  112. class TracerProvider(otel_trace_api.TracerProvider):
  113. """Specific otel tracer provider."""
  114. def __init__(self, inner: otel_trace_sdk.TracerProvider) -> None:
  115. self._inner = inner
  116. def get_tracer(
  117. self,
  118. instrumenting_module_name: str,
  119. instrumenting_library_version: Optional[str] = None,
  120. schema_url: Optional[str] = None,
  121. ) -> otel_trace_api.Tracer:
  122. tracer = self._inner.get_tracer(
  123. instrumenting_module_name=instrumenting_module_name,
  124. instrumenting_library_version=instrumenting_library_version,
  125. schema_url=schema_url,
  126. )
  127. return Tracer(tracer)
  128. def __getattr__(self, name: str) -> Any:
  129. """Method allows to delegate method calls."""
  130. return getattr(self._inner, name)