http_trace_context.h 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. // Copyright The OpenTelemetry Authors
  2. // SPDX-License-Identifier: Apache-2.0
  3. #pragma once
  4. #include <array>
  5. #include "detail/hex.h"
  6. #include "detail/string.h"
  7. #include "opentelemetry/context/propagation/text_map_propagator.h"
  8. #include "opentelemetry/nostd/function_ref.h"
  9. #include "opentelemetry/nostd/shared_ptr.h"
  10. #include "opentelemetry/nostd/span.h"
  11. #include "opentelemetry/nostd/string_view.h"
  12. #include "opentelemetry/trace/context.h"
  13. #include "opentelemetry/trace/default_span.h"
  14. #include "opentelemetry/version.h"
  15. OPENTELEMETRY_BEGIN_NAMESPACE
  16. namespace trace
  17. {
  18. namespace propagation
  19. {
  20. static const nostd::string_view kTraceParent = "traceparent";
  21. static const nostd::string_view kTraceState = "tracestate";
  22. static const size_t kVersionSize = 2;
  23. static const size_t kTraceIdSize = 32;
  24. static const size_t kSpanIdSize = 16;
  25. static const size_t kTraceFlagsSize = 2;
  26. static const size_t kTraceParentSize = 55;
  27. // The HttpTraceContext provides methods to extract and inject
  28. // context into headers of HTTP requests with traces.
  29. // Example:
  30. // HttpTraceContext().Inject(carrier, context);
  31. // HttpTraceContext().Extract(carrier, context);
  32. class HttpTraceContext : public context::propagation::TextMapPropagator
  33. {
  34. public:
  35. void Inject(context::propagation::TextMapCarrier &carrier,
  36. const context::Context &context) noexcept override
  37. {
  38. SpanContext span_context = trace::GetSpan(context)->GetContext();
  39. if (!span_context.IsValid())
  40. {
  41. return;
  42. }
  43. InjectImpl(carrier, span_context);
  44. }
  45. context::Context Extract(const context::propagation::TextMapCarrier &carrier,
  46. context::Context &context) noexcept override
  47. {
  48. SpanContext span_context = ExtractImpl(carrier);
  49. nostd::shared_ptr<Span> sp{new DefaultSpan(span_context)};
  50. if (span_context.IsValid())
  51. {
  52. return trace::SetSpan(context, sp);
  53. }
  54. else
  55. {
  56. return context;
  57. }
  58. }
  59. static TraceId TraceIdFromHex(nostd::string_view trace_id)
  60. {
  61. uint8_t buf[kTraceIdSize / 2];
  62. detail::HexToBinary(trace_id, buf, sizeof(buf));
  63. return TraceId(buf);
  64. }
  65. static SpanId SpanIdFromHex(nostd::string_view span_id)
  66. {
  67. uint8_t buf[kSpanIdSize / 2];
  68. detail::HexToBinary(span_id, buf, sizeof(buf));
  69. return SpanId(buf);
  70. }
  71. static TraceFlags TraceFlagsFromHex(nostd::string_view trace_flags)
  72. {
  73. uint8_t flags;
  74. detail::HexToBinary(trace_flags, &flags, sizeof(flags));
  75. return TraceFlags(flags);
  76. }
  77. private:
  78. static constexpr uint8_t kInvalidVersion = 0xFF;
  79. static constexpr uint8_t kDefaultAssumedVersion = 0x00;
  80. static void InjectImpl(context::propagation::TextMapCarrier &carrier,
  81. const SpanContext &span_context)
  82. {
  83. char trace_parent[kTraceParentSize];
  84. trace_parent[0] = '0';
  85. trace_parent[1] = '0';
  86. trace_parent[2] = '-';
  87. span_context.trace_id().ToLowerBase16(
  88. nostd::span<char, 2 * TraceId::kSize>{&trace_parent[3], kTraceIdSize});
  89. trace_parent[kTraceIdSize + 3] = '-';
  90. span_context.span_id().ToLowerBase16(
  91. nostd::span<char, 2 * SpanId::kSize>{&trace_parent[kTraceIdSize + 4], kSpanIdSize});
  92. trace_parent[kTraceIdSize + kSpanIdSize + 4] = '-';
  93. span_context.trace_flags().ToLowerBase16(
  94. nostd::span<char, 2>{&trace_parent[kTraceIdSize + kSpanIdSize + 5], 2});
  95. carrier.Set(kTraceParent, nostd::string_view(trace_parent, sizeof(trace_parent)));
  96. const auto trace_state = span_context.trace_state()->ToHeader();
  97. if (!trace_state.empty())
  98. {
  99. carrier.Set(kTraceState, trace_state);
  100. }
  101. }
  102. static SpanContext ExtractContextFromTraceHeaders(nostd::string_view trace_parent,
  103. nostd::string_view trace_state)
  104. {
  105. std::array<nostd::string_view, 4> fields{};
  106. if (detail::SplitString(trace_parent, '-', fields.data(), 4) != 4)
  107. {
  108. return SpanContext::GetInvalid();
  109. }
  110. nostd::string_view version_hex = fields[0];
  111. nostd::string_view trace_id_hex = fields[1];
  112. nostd::string_view span_id_hex = fields[2];
  113. nostd::string_view trace_flags_hex = fields[3];
  114. if (version_hex.size() != kVersionSize || trace_id_hex.size() != kTraceIdSize ||
  115. span_id_hex.size() != kSpanIdSize || trace_flags_hex.size() != kTraceFlagsSize)
  116. {
  117. return SpanContext::GetInvalid();
  118. }
  119. if (!detail::IsValidHex(version_hex) || !detail::IsValidHex(trace_id_hex) ||
  120. !detail::IsValidHex(span_id_hex) || !detail::IsValidHex(trace_flags_hex))
  121. {
  122. return SpanContext::GetInvalid();
  123. }
  124. // hex is valid, convert it to binary
  125. uint8_t version_binary;
  126. detail::HexToBinary(version_hex, &version_binary, sizeof(version_binary));
  127. if (version_binary == kInvalidVersion)
  128. {
  129. // invalid version encountered
  130. return SpanContext::GetInvalid();
  131. }
  132. // See https://www.w3.org/TR/trace-context/#versioning-of-traceparent
  133. if (version_binary > kDefaultAssumedVersion)
  134. {
  135. // higher than default version detected
  136. if (trace_parent.size() < kTraceParentSize)
  137. {
  138. return SpanContext::GetInvalid();
  139. }
  140. }
  141. else
  142. {
  143. // version is either lower or same as the default version
  144. if (trace_parent.size() != kTraceParentSize)
  145. {
  146. return SpanContext::GetInvalid();
  147. }
  148. }
  149. TraceId trace_id = TraceIdFromHex(trace_id_hex);
  150. SpanId span_id = SpanIdFromHex(span_id_hex);
  151. if (!trace_id.IsValid() || !span_id.IsValid())
  152. {
  153. return SpanContext::GetInvalid();
  154. }
  155. return SpanContext(trace_id, span_id, TraceFlagsFromHex(trace_flags_hex), true,
  156. trace::TraceState::FromHeader(trace_state));
  157. }
  158. static SpanContext ExtractImpl(const context::propagation::TextMapCarrier &carrier)
  159. {
  160. // Get trace_parent after trimming the leading and trailing whitespaces
  161. nostd::string_view trace_parent = common::StringUtil::Trim(carrier.Get(kTraceParent));
  162. nostd::string_view trace_state = carrier.Get(kTraceState);
  163. if (trace_parent == "")
  164. {
  165. return SpanContext::GetInvalid();
  166. }
  167. return ExtractContextFromTraceHeaders(trace_parent, trace_state);
  168. }
  169. bool Fields(nostd::function_ref<bool(nostd::string_view)> callback) const noexcept override
  170. {
  171. return (callback(kTraceParent) && callback(kTraceState));
  172. }
  173. };
  174. } // namespace propagation
  175. } // namespace trace
  176. OPENTELEMETRY_END_NAMESPACE