]>
Commit | Line | Data |
---|---|---|
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 | #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 |