]> git.proxmox.com Git - ceph.git/blob - ceph/src/jaegertracing/jaeger-client-cpp/src/jaegertracing/Tracer.cpp
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / jaegertracing / jaeger-client-cpp / src / jaegertracing / Tracer.cpp
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 #include "jaegertracing/Tag.h"
18 #include "jaegertracing/Tracer.h"
19 #include "jaegertracing/Reference.h"
20 #include "jaegertracing/TraceID.h"
21 #include "jaegertracing/samplers/SamplingStatus.h"
22 #include <algorithm>
23 #include <cassert>
24 #include <chrono>
25 #include <iterator>
26 #include <opentracing/util.h>
27 #include <tuple>
28
29 namespace jaegertracing {
30 namespace {
31
32 using SystemClock = Tracer::SystemClock;
33 using SteadyClock = Tracer::SteadyClock;
34 using TimePoints = std::tuple<SystemClock::time_point, SteadyClock::time_point>;
35
36 // An extension of opentracing::SpanReferenceType enum. See jaegertracing::SelfRef().
37 const static int SpanReferenceType_JaegerSpecific_SelfRef = 99;
38
39 TimePoints determineStartTimes(const opentracing::StartSpanOptions& options)
40 {
41 if (options.start_system_timestamp == SystemClock::time_point() &&
42 options.start_steady_timestamp == SteadyClock::time_point()) {
43 return std::make_tuple(SystemClock::now(), SteadyClock::now());
44 }
45 if (options.start_system_timestamp == SystemClock::time_point()) {
46 return std::make_tuple(opentracing::convert_time_point<SystemClock>(
47 options.start_steady_timestamp),
48 options.start_steady_timestamp);
49 }
50 if (options.start_steady_timestamp == SteadyClock::time_point()) {
51 return std::make_tuple(options.start_system_timestamp,
52 opentracing::convert_time_point<SteadyClock>(
53 options.start_system_timestamp));
54 }
55 return std::make_tuple(options.start_system_timestamp,
56 options.start_steady_timestamp);
57 }
58
59 } // anonymous namespace
60
61 using StrMap = SpanContext::StrMap;
62
63 constexpr int Tracer::kGen128BitOption;
64
65 std::unique_ptr<opentracing::Span>
66 Tracer::StartSpanWithOptions(string_view operationName,
67 const opentracing::StartSpanOptions& options) const
68 noexcept
69 {
70 try {
71 const auto result = analyzeReferences(options.references);
72 const auto* parent = result._parent;
73 const auto* self = result._self;
74 const auto& references = result._references;
75 if (self && (parent || !references.empty()))
76 {
77 throw std::invalid_argument("Self and references are exclusive. Only one of them can be specified");
78 }
79
80 std::vector<Tag> samplerTags;
81 auto newTrace = false;
82 SpanContext ctx;
83 if (!parent || !parent->isValid()) {
84 newTrace = true;
85 auto highID = static_cast<uint64_t>(0);
86 auto lowID = static_cast<uint64_t>(0);
87 if (self) {
88 highID = self->traceID().high();
89 lowID = self->traceID().low();
90 }
91 else {
92 if (_options & kGen128BitOption) {
93 highID = randomID();
94 }
95 lowID = randomID();
96 }
97 const TraceID traceID(highID, lowID);
98 const auto spanID = self ? self->spanID() : traceID.low();
99 const auto parentID = 0;
100 auto flags = static_cast<unsigned char>(0);
101 if (parent && parent->isDebugIDContainerOnly()) {
102 flags |=
103 (static_cast<unsigned char>(SpanContext::Flag::kSampled) |
104 static_cast<unsigned char>(SpanContext::Flag::kDebug));
105 samplerTags.push_back(Tag(kJaegerDebugHeader, parent->debugID()));
106 }
107 else {
108 const auto samplingStatus =
109 _sampler->isSampled(traceID, operationName);
110 if (samplingStatus.isSampled()) {
111 flags |=
112 static_cast<unsigned char>(SpanContext::Flag::kSampled);
113 samplerTags = samplingStatus.tags();
114 }
115 }
116 ctx = SpanContext(traceID, spanID, parentID, flags, StrMap());
117 }
118 else {
119 const auto traceID = parent->traceID();
120 const auto spanID = randomID();
121 const auto parentID = parent->spanID();
122 const auto flags = parent->flags();
123 ctx = SpanContext(traceID, spanID, parentID, flags, StrMap());
124 }
125
126 if (parent && !parent->baggage().empty()) {
127 ctx = ctx.withBaggage(parent->baggage());
128 }
129
130 SystemClock::time_point startTimeSystem;
131 SteadyClock::time_point startTimeSteady;
132 std::tie(startTimeSystem, startTimeSteady) =
133 determineStartTimes(options);
134 return startSpanInternal(ctx,
135 operationName,
136 startTimeSystem,
137 startTimeSteady,
138 samplerTags,
139 options.tags,
140 newTrace,
141 references);
142 } catch (const std::exception& ex) {
143 std::ostringstream oss;
144 oss << "Error occurred in Tracer::StartSpanWithOptions: " << ex.what();
145 utils::ErrorUtil::logError(*_logger, oss.str());
146 return nullptr;
147 } catch (...) {
148 utils::ErrorUtil::logError(
149 *_logger, "Error occurred in Tracer::StartSpanWithOptions");
150 return nullptr;
151 }
152 }
153
154 std::unique_ptr<Span>
155 Tracer::startSpanInternal(const SpanContext& context,
156 const std::string& operationName,
157 const SystemClock::time_point& startTimeSystem,
158 const SteadyClock::time_point& startTimeSteady,
159 const std::vector<Tag>& internalTags,
160 const std::vector<OpenTracingTag>& tags,
161 bool newTrace,
162 const std::vector<Reference>& references) const
163 {
164 std::vector<Tag> spanTags;
165 spanTags.reserve(tags.size() + internalTags.size());
166 std::transform(
167 std::begin(tags),
168 std::end(tags),
169 std::back_inserter(spanTags),
170 [](const OpenTracingTag& tag) { return Tag(tag.first, tag.second); });
171 spanTags.insert(
172 std::end(spanTags), std::begin(internalTags), std::end(internalTags));
173
174 std::unique_ptr<Span> span(new Span(shared_from_this(),
175 context,
176 operationName,
177 startTimeSystem,
178 startTimeSteady,
179 spanTags,
180 references));
181
182 _metrics->spansStarted().inc(1);
183 if (span->context().isSampled()) {
184 _metrics->spansSampled().inc(1);
185 if (newTrace) {
186 _metrics->tracesStartedSampled().inc(1);
187 }
188 }
189 else {
190 _metrics->spansNotSampled().inc(1);
191 if (newTrace) {
192 _metrics->tracesStartedNotSampled().inc(1);
193 }
194 }
195
196 return span;
197 }
198
199 Tracer::AnalyzedReferences
200 Tracer::analyzeReferences(const std::vector<OpenTracingRef>& references) const
201 {
202 AnalyzedReferences result;
203 auto hasParent = false;
204 const auto* parent = result._parent;
205 for (auto&& ref : references) {
206 const auto* ctx = dynamic_cast<const SpanContext*>(ref.second);
207
208 if (!ctx) {
209 _logger->error("Reference contains invalid type of SpanReference");
210 continue;
211 }
212
213 if (!ctx->isValid() && !ctx->isDebugIDContainerOnly() &&
214 ctx->baggage().empty()) {
215 continue;
216 }
217
218 if (static_cast<int>(ref.first) == SpanReferenceType_JaegerSpecific_SelfRef)
219 {
220 result._self = ctx;
221 continue; // not a reference
222 }
223
224 result._references.emplace_back(Reference(*ctx, ref.first));
225
226 if (!hasParent) {
227 parent = ctx;
228 hasParent =
229 (ref.first == opentracing::SpanReferenceType::ChildOfRef);
230 }
231 }
232
233 if (!hasParent && parent && parent->isValid()) {
234 // Use `FollowsFromRef` in place of `ChildOfRef`.
235 hasParent = true;
236 }
237
238 if (hasParent) {
239 assert(parent);
240 result._parent = parent;
241 }
242
243 return result;
244 }
245
246 std::shared_ptr<opentracing::Tracer>
247 Tracer::make(const std::string& serviceName,
248 const Config& config,
249 const std::shared_ptr<logging::Logger>& logger,
250 metrics::StatsFactory& statsFactory, int options)
251 {
252 if (serviceName.empty()) {
253 throw std::invalid_argument("no service name provided");
254 }
255
256 if (config.disabled()) {
257 return opentracing::MakeNoopTracer();
258 }
259
260 auto metrics = std::make_shared<metrics::Metrics>(statsFactory);
261 std::shared_ptr<samplers::Sampler> sampler(
262 config.sampler().makeSampler(serviceName, *logger, *metrics));
263 std::shared_ptr<reporters::Reporter> reporter(
264 config.reporter().makeReporter(serviceName, *logger, *metrics));
265 return std::shared_ptr<Tracer>(new Tracer(serviceName,
266 sampler,
267 reporter,
268 logger,
269 metrics,
270 config.headers(),
271 config.tags(),
272 options));
273 }
274
275 opentracing::SpanReference SelfRef(const opentracing::SpanContext* span_context) noexcept {
276 return {static_cast<opentracing::SpanReferenceType>(SpanReferenceType_JaegerSpecific_SelfRef), span_context};
277 }
278
279 } // namespace jaegertracing