2 * Copyright (c) 2017 Uber Technologies, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
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"
26 #include <opentracing/util.h>
29 namespace jaegertracing
{
32 using SystemClock
= Tracer::SystemClock
;
33 using SteadyClock
= Tracer::SteadyClock
;
34 using TimePoints
= std::tuple
<SystemClock::time_point
, SteadyClock::time_point
>;
36 // An extension of opentracing::SpanReferenceType enum. See jaegertracing::SelfRef().
37 const static int SpanReferenceType_JaegerSpecific_SelfRef
= 99;
39 TimePoints
determineStartTimes(const opentracing::StartSpanOptions
& options
)
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());
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
);
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
));
55 return std::make_tuple(options
.start_system_timestamp
,
56 options
.start_steady_timestamp
);
59 } // anonymous namespace
61 using StrMap
= SpanContext::StrMap
;
63 constexpr int Tracer::kGen128BitOption
;
65 std::unique_ptr
<opentracing::Span
>
66 Tracer::StartSpanWithOptions(string_view operationName
,
67 const opentracing::StartSpanOptions
& options
) const
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()))
77 throw std::invalid_argument("Self and references are exclusive. Only one of them can be specified");
80 std::vector
<Tag
> samplerTags
;
81 auto newTrace
= false;
83 if (!parent
|| !parent
->isValid()) {
85 auto highID
= static_cast<uint64_t>(0);
86 auto lowID
= static_cast<uint64_t>(0);
88 highID
= self
->traceID().high();
89 lowID
= self
->traceID().low();
92 if (_options
& kGen128BitOption
) {
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()) {
103 (static_cast<unsigned char>(SpanContext::Flag::kSampled
) |
104 static_cast<unsigned char>(SpanContext::Flag::kDebug
));
105 samplerTags
.push_back(Tag(kJaegerDebugHeader
, parent
->debugID()));
108 const auto samplingStatus
=
109 _sampler
->isSampled(traceID
, operationName
);
110 if (samplingStatus
.isSampled()) {
112 static_cast<unsigned char>(SpanContext::Flag::kSampled
);
113 samplerTags
= samplingStatus
.tags();
116 ctx
= SpanContext(traceID
, spanID
, parentID
, flags
, StrMap());
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());
126 if (parent
&& !parent
->baggage().empty()) {
127 ctx
= ctx
.withBaggage(parent
->baggage());
130 SystemClock::time_point startTimeSystem
;
131 SteadyClock::time_point startTimeSteady
;
132 std::tie(startTimeSystem
, startTimeSteady
) =
133 determineStartTimes(options
);
134 return startSpanInternal(ctx
,
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());
148 utils::ErrorUtil::logError(
149 *_logger
, "Error occurred in Tracer::StartSpanWithOptions");
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
,
162 const std::vector
<Reference
>& references
) const
164 std::vector
<Tag
> spanTags
;
165 spanTags
.reserve(tags
.size() + internalTags
.size());
169 std::back_inserter(spanTags
),
170 [](const OpenTracingTag
& tag
) { return Tag(tag
.first
, tag
.second
); });
172 std::end(spanTags
), std::begin(internalTags
), std::end(internalTags
));
174 std::unique_ptr
<Span
> span(new Span(shared_from_this(),
182 _metrics
->spansStarted().inc(1);
183 if (span
->context().isSampled()) {
184 _metrics
->spansSampled().inc(1);
186 _metrics
->tracesStartedSampled().inc(1);
190 _metrics
->spansNotSampled().inc(1);
192 _metrics
->tracesStartedNotSampled().inc(1);
199 Tracer::AnalyzedReferences
200 Tracer::analyzeReferences(const std::vector
<OpenTracingRef
>& references
) const
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
);
209 _logger
->error("Reference contains invalid type of SpanReference");
213 if (!ctx
->isValid() && !ctx
->isDebugIDContainerOnly() &&
214 ctx
->baggage().empty()) {
218 if (static_cast<int>(ref
.first
) == SpanReferenceType_JaegerSpecific_SelfRef
)
221 continue; // not a reference
224 result
._references
.emplace_back(Reference(*ctx
, ref
.first
));
229 (ref
.first
== opentracing::SpanReferenceType::ChildOfRef
);
233 if (!hasParent
&& parent
&& parent
->isValid()) {
234 // Use `FollowsFromRef` in place of `ChildOfRef`.
240 result
._parent
= parent
;
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
)
252 if (serviceName
.empty()) {
253 throw std::invalid_argument("no service name provided");
256 if (config
.disabled()) {
257 return opentracing::MakeNoopTracer();
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
,
275 opentracing::SpanReference
SelfRef(const opentracing::SpanContext
* span_context
) noexcept
{
276 return {static_cast<opentracing::SpanReferenceType
>(SpanReferenceType_JaegerSpecific_SelfRef
), span_context
};
279 } // namespace jaegertracing