]> git.proxmox.com Git - ceph.git/blame - ceph/src/jaegertracing/jaeger-client-cpp/src/jaegertracing/propagation/Propagator.h
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / jaegertracing / jaeger-client-cpp / src / jaegertracing / propagation / Propagator.h
CommitLineData
f67539c2
TL
1/*
2 * Copyright (c) 2017 Uber Technologies, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef JAEGERTRACING_PROPAGATION_PROPAGATOR_H
18#define JAEGERTRACING_PROPAGATION_PROPAGATOR_H
19
20#include "jaegertracing/SpanContext.h"
21#include "jaegertracing/metrics/Metrics.h"
22#include "jaegertracing/net/URI.h"
23#include "jaegertracing/platform/Endian.h"
24#include "jaegertracing/propagation/Extractor.h"
25#include "jaegertracing/propagation/HeadersConfig.h"
26#include "jaegertracing/propagation/Injector.h"
27#include <cctype>
28#include <climits>
29#include <opentracing/propagation.h>
30#include <sstream>
31
32namespace jaegertracing {
33
34class Tracer;
35
36namespace propagation {
37
38template <typename ReaderType, typename WriterType>
39class Propagator : public Extractor<ReaderType>, public Injector<WriterType> {
40 public:
41 using Reader = ReaderType;
42 using Writer = WriterType;
43 using StrMap = SpanContext::StrMap;
44
45 Propagator()
46 : _headerKeys()
47 , _metrics(metrics::Metrics::makeNullMetrics())
48 {
49 }
50
51 Propagator(const HeadersConfig& headerKeys,
52 const std::shared_ptr<metrics::Metrics>& metrics)
53 : _headerKeys(headerKeys)
54 , _metrics(metrics)
55 {
56 }
57
58 virtual ~Propagator() = default;
59
60 SpanContext extract(const Reader& reader) const override
61 {
62 SpanContext ctx;
63 StrMap baggage;
64 std::string debugID;
65 const auto result = reader.ForeachKey(
66 [this, &ctx, &debugID, &baggage](const std::string& rawKey,
67 const std::string& value) {
68 const auto key = normalizeKey(rawKey);
69 if (key == _headerKeys.traceContextHeaderName()) {
70 const auto safeValue = decodeValue(value);
71 std::istringstream iss(safeValue);
72 if (!(iss >> ctx) || ctx == SpanContext()) {
73 return opentracing::make_expected_from_error<void>(
74 opentracing::span_context_corrupted_error);
75 }
76 }
77 else if (key == _headerKeys.jaegerDebugHeader()) {
78 debugID = value;
79 }
80 else if (key == _headerKeys.jaegerBaggageHeader()) {
81 for (auto&& pair : parseCommaSeparatedMap(value)) {
82 baggage[pair.first] = pair.second;
83 }
84 }
85 else {
86 const auto prefix = _headerKeys.traceBaggageHeaderPrefix();
87 if (key.size() >= prefix.size() &&
88 key.substr(0, prefix.size()) == prefix) {
89 const auto safeKey = removeBaggageKeyPrefix(key);
90 const auto safeValue = decodeValue(value);
91 baggage[safeKey] = safeValue;
92 }
93 }
94 return opentracing::make_expected();
95 });
96
97 if (!result &&
98 result.error() == opentracing::span_context_corrupted_error) {
99 _metrics->decodingErrors().inc(1);
100 return SpanContext();
101 }
102
103 if (!ctx.traceID().isValid() && debugID.empty() && baggage.empty()) {
104 return SpanContext();
105 }
106
107 int flags = ctx.flags();
108 if (!debugID.empty()) {
109 flags |= static_cast<unsigned char>(SpanContext::Flag::kDebug) |
110 static_cast<unsigned char>(SpanContext::Flag::kSampled);
111 }
112 return SpanContext(ctx.traceID(),
113 ctx.spanID(),
114 ctx.parentID(),
115 flags,
116 baggage,
117 debugID);
118 }
119
120 void inject(const SpanContext& ctx, const Writer& writer) const override
121 {
122 std::ostringstream oss;
123 oss << ctx;
124 writer.Set(_headerKeys.traceContextHeaderName(), oss.str());
125 ctx.forEachBaggageItem(
126 [this, &writer](const std::string& key, const std::string& value) {
127 const auto safeKey = addBaggageKeyPrefix(key);
128 const auto safeValue = encodeValue(value);
129 writer.Set(safeKey, safeValue);
130 return true;
131 });
132 }
133
134 protected:
135 virtual std::string encodeValue(const std::string& str) const
136 {
137 return str;
138 }
139
140 virtual std::string decodeValue(const std::string& str) const
141 {
142 return str;
143 }
144
145 virtual std::string normalizeKey(const std::string& rawKey) const
146 {
147 return rawKey;
148 }
149
150 private:
151 static StrMap parseCommaSeparatedMap(const std::string& escapedValue)
152 {
153 StrMap map;
154 std::istringstream iss(net::URI::queryUnescape(escapedValue));
155 std::string piece;
156 while (std::getline(iss, piece, ',')) {
157 const auto eqPos = piece.find('=');
158 if (eqPos != std::string::npos) {
159 const auto key = piece.substr(0, eqPos);
160 const auto value = piece.substr(eqPos + 1);
161 map[key] = value;
162 }
163 }
164 return map;
165 }
166
167 std::string addBaggageKeyPrefix(const std::string& key) const
168 {
169 return _headerKeys.traceBaggageHeaderPrefix() + key;
170 }
171
172 std::string removeBaggageKeyPrefix(const std::string& key) const
173 {
174 return key.substr(_headerKeys.traceBaggageHeaderPrefix().size());
175 }
176
177 HeadersConfig _headerKeys;
178 std::shared_ptr<metrics::Metrics> _metrics;
179};
180
181using TextMapPropagator = Propagator<const opentracing::TextMapReader&,
182 const opentracing::TextMapWriter&>;
183
184class HTTPHeaderPropagator
185 : public Propagator<const opentracing::HTTPHeadersReader&,
186 const opentracing::HTTPHeadersWriter&> {
187 public:
188 using Propagator<Reader, Writer>::Propagator;
189
190 protected:
191 std::string encodeValue(const std::string& str) const override
192 {
193 return net::URI::queryEscape(str);
194 }
195
196 std::string decodeValue(const std::string& str) const override
197 {
198 return net::URI::queryUnescape(str);
199 }
200
201 std::string normalizeKey(const std::string& rawKey) const override
202 {
203 std::string key;
204 key.reserve(rawKey.size());
205 std::transform(std::begin(rawKey),
206 std::end(rawKey),
207 std::back_inserter(key),
208 [](char ch) { return std::tolower(ch); });
209 return key;
210 }
211};
212
213class BinaryPropagator : public Extractor<std::istream&>,
214 public Injector<std::ostream&> {
215 public:
216 using StrMap = SpanContext::StrMap;
217
218 explicit BinaryPropagator(const std::shared_ptr<metrics::Metrics>& metrics =
219 std::shared_ptr<metrics::Metrics>())
220 : _metrics(metrics == nullptr ? metrics::Metrics::makeNullMetrics()
221 : metrics)
222 {
223 }
224
225 void inject(const SpanContext& ctx, std::ostream& out) const override
226 {
227 writeBinary(out, ctx.traceID().high());
228 writeBinary(out, ctx.traceID().low());
229 writeBinary(out, ctx.spanID());
230 writeBinary(out, ctx.parentID());
231 // `flags` is a single byte, so endianness is not an issue.
232 out.put(ctx.flags());
233
234 writeBinary(out, static_cast<uint32_t>(ctx.baggage().size()));
235 for (auto&& pair : ctx.baggage()) {
236 auto&& key = pair.first;
237 writeBinary(out, static_cast<uint32_t>(key.size()));
238 out.write(key.c_str(), key.size());
239
240 auto&& value = pair.second;
241 writeBinary(out, static_cast<uint32_t>(value.size()));
242 out.write(value.c_str(), value.size());
243 }
244 }
245
246 SpanContext extract(std::istream& in) const override
247 {
248 const auto traceIDHigh = readBinary<uint64_t>(in);
249 const auto traceIDLow = readBinary<uint64_t>(in);
250 TraceID traceID(traceIDHigh, traceIDLow);
251 const auto spanID = readBinary<uint64_t>(in);
252 const auto parentID = readBinary<uint64_t>(in);
253
254 auto ch = '\0';
255 in.get(ch);
256 const auto flags = static_cast<unsigned char>(ch);
257
258 const auto numBaggageItems = readBinary<uint32_t>(in);
259 StrMap baggage;
260 baggage.reserve(numBaggageItems);
261 for (auto i = static_cast<uint32_t>(0); i < numBaggageItems; ++i) {
262 const auto keyLength = readBinary<uint32_t>(in);
263 std::string key(keyLength, '\0');
264 if (!in.read(&key[0], keyLength)) {
265 _metrics->decodingErrors().inc(1);
266 return SpanContext();
267 }
268
269 const auto valueLength = readBinary<uint32_t>(in);
270 std::string value(valueLength, '\0');
271 if (!in.read(&value[0], valueLength)) {
272 _metrics->decodingErrors().inc(1);
273 return SpanContext();
274 }
275
276 baggage[key] = value;
277 }
278
279 SpanContext ctx(traceID, spanID, parentID, flags, baggage);
280 return ctx;
281 }
282
283 private:
284 template <typename ValueType>
285 static
286 typename std::enable_if<std::is_integral<ValueType>::value, void>::type
287 writeBinary(std::ostream& out, ValueType value)
288 {
289 const ValueType outValue = platform::endian::toBigEndian(value);
290 for (auto i = static_cast<size_t>(0); i < sizeof(ValueType); ++i) {
291 const auto numShiftBits = (sizeof(ValueType) - i - 1) * CHAR_BIT;
292 const auto byte = outValue >> numShiftBits;
293 out.put(static_cast<unsigned char>(byte));
294 }
295 }
296
297 template <typename ValueType>
298 static typename std::enable_if<std::is_integral<ValueType>::value,
299 ValueType>::type
300 readBinary(std::istream& in)
301 {
302 auto value = static_cast<ValueType>(0);
303 auto ch = '\0';
304 for (auto i = static_cast<size_t>(0);
305 i < sizeof(ValueType) && in.get(ch);
306 ++i) {
307 const auto byte = static_cast<uint8_t>(ch);
308 value <<= CHAR_BIT;
309 value |= byte;
310 }
311 return platform::endian::fromBigEndian(value);
312 }
313
314 private:
315 std::shared_ptr<metrics::Metrics> _metrics;
316};
317
318} // namespace propagation
319} // namespace jaegertracing
320
321#endif // JAEGERTRACING_PROPAGATION_PROPAGATOR_H