propagator.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. from sentry_sdk.integrations import DidNotEnable
  2. from sentry_sdk.integrations.opentelemetry.consts import (
  3. SENTRY_BAGGAGE_KEY,
  4. SENTRY_TRACE_KEY,
  5. )
  6. from sentry_sdk.integrations.opentelemetry.span_processor import (
  7. SentrySpanProcessor,
  8. )
  9. from sentry_sdk.tracing import (
  10. BAGGAGE_HEADER_NAME,
  11. SENTRY_TRACE_HEADER_NAME,
  12. )
  13. from sentry_sdk.tracing_utils import Baggage, extract_sentrytrace_data
  14. try:
  15. from opentelemetry import trace
  16. from opentelemetry.context import (
  17. Context,
  18. get_current,
  19. set_value,
  20. )
  21. from opentelemetry.propagators.textmap import (
  22. CarrierT,
  23. Getter,
  24. Setter,
  25. TextMapPropagator,
  26. default_getter,
  27. default_setter,
  28. )
  29. from opentelemetry.trace import (
  30. NonRecordingSpan,
  31. SpanContext,
  32. TraceFlags,
  33. )
  34. except ImportError:
  35. raise DidNotEnable("opentelemetry not installed")
  36. from typing import TYPE_CHECKING
  37. if TYPE_CHECKING:
  38. from typing import Optional, Set
  39. class SentryPropagator(TextMapPropagator):
  40. """
  41. Propagates tracing headers for Sentry's tracing system in a way OTel understands.
  42. """
  43. def extract(
  44. self,
  45. carrier: "CarrierT",
  46. context: "Optional[Context]" = None,
  47. getter: "Getter[CarrierT]" = default_getter,
  48. ) -> "Context":
  49. if context is None:
  50. context = get_current()
  51. sentry_trace = getter.get(carrier, SENTRY_TRACE_HEADER_NAME)
  52. if not sentry_trace:
  53. return context
  54. sentrytrace = extract_sentrytrace_data(sentry_trace[0])
  55. if not sentrytrace:
  56. return context
  57. context = set_value(SENTRY_TRACE_KEY, sentrytrace, context)
  58. trace_id, span_id = sentrytrace["trace_id"], sentrytrace["parent_span_id"]
  59. span_context = SpanContext(
  60. trace_id=int(trace_id, 16), # type: ignore
  61. span_id=int(span_id, 16), # type: ignore
  62. # we simulate a sampled trace on the otel side and leave the sampling to sentry
  63. trace_flags=TraceFlags(TraceFlags.SAMPLED),
  64. is_remote=True,
  65. )
  66. baggage_header = getter.get(carrier, BAGGAGE_HEADER_NAME)
  67. if baggage_header:
  68. baggage = Baggage.from_incoming_header(baggage_header[0])
  69. else:
  70. # If there's an incoming sentry-trace but no incoming baggage header,
  71. # for instance in traces coming from older SDKs,
  72. # baggage will be empty and frozen and won't be populated as head SDK.
  73. baggage = Baggage(sentry_items={})
  74. baggage.freeze()
  75. context = set_value(SENTRY_BAGGAGE_KEY, baggage, context)
  76. span = NonRecordingSpan(span_context)
  77. modified_context = trace.set_span_in_context(span, context)
  78. return modified_context
  79. def inject(
  80. self,
  81. carrier: "CarrierT",
  82. context: "Optional[Context]" = None,
  83. setter: "Setter[CarrierT]" = default_setter,
  84. ) -> None:
  85. if context is None:
  86. context = get_current()
  87. current_span = trace.get_current_span(context)
  88. current_span_context = current_span.get_span_context()
  89. if not current_span_context.is_valid:
  90. return
  91. span_id = trace.format_span_id(current_span_context.span_id)
  92. span_map = SentrySpanProcessor().otel_span_map
  93. sentry_span = span_map.get(span_id, None)
  94. if not sentry_span:
  95. return
  96. setter.set(carrier, SENTRY_TRACE_HEADER_NAME, sentry_span.to_traceparent())
  97. if sentry_span.containing_transaction:
  98. baggage = sentry_span.containing_transaction.get_baggage()
  99. if baggage:
  100. baggage_data = baggage.serialize()
  101. if baggage_data:
  102. setter.set(carrier, BAGGAGE_HEADER_NAME, baggage_data)
  103. @property
  104. def fields(self) -> "Set[str]":
  105. return {SENTRY_TRACE_HEADER_NAME, BAGGAGE_HEADER_NAME}