]> git.proxmox.com Git - ceph.git/blame - ceph/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/trace/propagation/b3_propagator.h
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / jaegertracing / opentelemetry-cpp / api / include / opentelemetry / trace / propagation / b3_propagator.h
CommitLineData
1e59de90
TL
1// Copyright The OpenTelemetry Authors
2// SPDX-License-Identifier: Apache-2.0
3
4#pragma once
5
6#include "detail/hex.h"
7#include "detail/string.h"
8#include "opentelemetry/context/propagation/text_map_propagator.h"
9#include "opentelemetry/trace/context.h"
10#include "opentelemetry/trace/default_span.h"
11
12#include <array>
13
14OPENTELEMETRY_BEGIN_NAMESPACE
15namespace trace
16{
17namespace propagation
18{
19
20static const nostd::string_view kB3CombinedHeader = "b3";
21
22static const nostd::string_view kB3TraceIdHeader = "X-B3-TraceId";
23static const nostd::string_view kB3SpanIdHeader = "X-B3-SpanId";
24static const nostd::string_view kB3SampledHeader = "X-B3-Sampled";
25
26/*
27 B3, single header:
28 b3: 80f198ee56343ba864fe8b2a57d3eff7-e457b5a2e4d86bd1-1-05e3ac9a4f6e3b90
29 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^
30 0 TraceId 31 33 SpanId 48 | 52 ParentSpanId 68
31 50 Debug flag
32 Multiheader version: X-B3-Sampled
33 X-B3-TraceId X-B3-SpanId X-B3-ParentSpanId (ignored)
34*/
35
36static const int kTraceIdHexStrLength = 32;
37static const int kSpanIdHexStrLength = 16;
38
39// The B3PropagatorExtractor class provides an interface that enables extracting context from
40// headers of HTTP requests. HTTP frameworks and clients can integrate with B3Propagator by
41// providing the object containing the headers, and a getter function for the extraction. Based on:
42// https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/context/api-propagators.md#b3-extract
43
44class B3PropagatorExtractor : public opentelemetry::context::propagation::TextMapPropagator
45{
46public:
47 // Returns the context that is stored in the HTTP header carrier.
48 context::Context Extract(const opentelemetry::context::propagation::TextMapCarrier &carrier,
49 context::Context &context) noexcept override
50 {
51 SpanContext span_context = ExtractImpl(carrier);
52 nostd::shared_ptr<Span> sp{new DefaultSpan(span_context)};
53 return trace::SetSpan(context, sp);
54 }
55
56 static TraceId TraceIdFromHex(nostd::string_view trace_id)
57 {
58 uint8_t buf[kTraceIdHexStrLength / 2];
59 detail::HexToBinary(trace_id, buf, sizeof(buf));
60 return TraceId(buf);
61 }
62
63 static SpanId SpanIdFromHex(nostd::string_view span_id)
64 {
65 uint8_t buf[kSpanIdHexStrLength / 2];
66 detail::HexToBinary(span_id, buf, sizeof(buf));
67 return SpanId(buf);
68 }
69
70 static TraceFlags TraceFlagsFromHex(nostd::string_view trace_flags)
71 {
72 if (trace_flags.length() != 1 || (trace_flags[0] != '1' && trace_flags[0] != 'd'))
73 { // check for invalid length of flags and treat 'd' as sampled
74 return TraceFlags(0);
75 }
76 return TraceFlags(TraceFlags::kIsSampled);
77 }
78
79private:
80 static SpanContext ExtractImpl(const opentelemetry::context::propagation::TextMapCarrier &carrier)
81 {
82 nostd::string_view trace_id_hex;
83 nostd::string_view span_id_hex;
84 nostd::string_view trace_flags_hex;
85
86 // first let's try a single-header variant
87 auto singleB3Header = carrier.Get(kB3CombinedHeader);
88 if (!singleB3Header.empty())
89 {
90 std::array<nostd::string_view, 3> fields{};
91 // https://github.com/openzipkin/b3-propagation/blob/master/RATIONALE.md
92 if (detail::SplitString(singleB3Header, '-', fields.data(), 3) < 2)
93 {
94 return SpanContext::GetInvalid();
95 }
96
97 trace_id_hex = fields[0];
98 span_id_hex = fields[1];
99 trace_flags_hex = fields[2];
100 }
101 else
102 {
103 trace_id_hex = carrier.Get(kB3TraceIdHeader);
104 span_id_hex = carrier.Get(kB3SpanIdHeader);
105 trace_flags_hex = carrier.Get(kB3SampledHeader);
106 }
107
108 if (!detail::IsValidHex(trace_id_hex) || !detail::IsValidHex(span_id_hex))
109 {
110 return SpanContext::GetInvalid();
111 }
112
113 TraceId trace_id = TraceIdFromHex(trace_id_hex);
114 SpanId span_id = SpanIdFromHex(span_id_hex);
115
116 if (!trace_id.IsValid() || !span_id.IsValid())
117 {
118 return SpanContext::GetInvalid();
119 }
120
121 return SpanContext(trace_id, span_id, TraceFlagsFromHex(trace_flags_hex), true);
122 }
123};
124
125// The B3Propagator class provides interface that enables extracting and injecting context into
126// single header of HTTP Request.
127class B3Propagator : public B3PropagatorExtractor
128{
129public:
130 // Sets the context for a HTTP header carrier with self defined rules.
131 void Inject(opentelemetry::context::propagation::TextMapCarrier &carrier,
132 const context::Context &context) noexcept override
133 {
134 SpanContext span_context = trace::GetSpan(context)->GetContext();
135 if (!span_context.IsValid())
136 {
137 return;
138 }
139
140 char trace_identity[kTraceIdHexStrLength + kSpanIdHexStrLength + 3];
141 static_assert(sizeof(trace_identity) == 51, "b3 trace identity buffer size mismatch");
142 span_context.trace_id().ToLowerBase16(nostd::span<char, 2 * TraceId::kSize>{
143 &trace_identity[0], static_cast<std::size_t>(kTraceIdHexStrLength)});
144 trace_identity[kTraceIdHexStrLength] = '-';
145 span_context.span_id().ToLowerBase16(nostd::span<char, 2 * SpanId::kSize>{
146 &trace_identity[kTraceIdHexStrLength + 1], static_cast<std::size_t>(kSpanIdHexStrLength)});
147 trace_identity[kTraceIdHexStrLength + kSpanIdHexStrLength + 1] = '-';
148 trace_identity[kTraceIdHexStrLength + kSpanIdHexStrLength + 2] =
149 span_context.trace_flags().IsSampled() ? '1' : '0';
150
151 carrier.Set(kB3CombinedHeader, nostd::string_view(trace_identity, sizeof(trace_identity)));
152 }
153
154 bool Fields(nostd::function_ref<bool(nostd::string_view)> callback) const noexcept override
155 {
156 return callback(kB3CombinedHeader);
157 }
158};
159
160class B3PropagatorMultiHeader : public B3PropagatorExtractor
161{
162public:
163 void Inject(opentelemetry::context::propagation::TextMapCarrier &carrier,
164 const context::Context &context) noexcept override
165 {
166 SpanContext span_context = GetSpan(context)->GetContext();
167 if (!span_context.IsValid())
168 {
169 return;
170 }
171 char trace_id[32];
172 TraceId(span_context.trace_id()).ToLowerBase16(trace_id);
173 char span_id[16];
174 SpanId(span_context.span_id()).ToLowerBase16(span_id);
175 char trace_flags[2];
176 TraceFlags(span_context.trace_flags()).ToLowerBase16(trace_flags);
177 carrier.Set(kB3TraceIdHeader, nostd::string_view(trace_id, sizeof(trace_id)));
178 carrier.Set(kB3SpanIdHeader, nostd::string_view(span_id, sizeof(span_id)));
179 carrier.Set(kB3SampledHeader, nostd::string_view(trace_flags + 1, 1));
180 }
181
182 bool Fields(nostd::function_ref<bool(nostd::string_view)> callback) const noexcept override
183 {
184 return callback(kB3TraceIdHeader) && callback(kB3SpanIdHeader) && callback(kB3SampledHeader);
185 }
186};
187
188} // namespace propagation
189} // namespace trace
190OPENTELEMETRY_END_NAMESPACE