diff --git a/CMakeLists.txt b/CMakeLists.txt index 182dbad6..1d53175c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -157,6 +157,7 @@ set(LIGHTSTEP_SRCS src/utility.cpp src/manual_recorder.cpp src/auto_recorder.cpp src/lightstep_span_context.cpp + src/lightstep_immutable_span_context.cpp src/lightstep_span.cpp src/lightstep_tracer_impl.cpp src/lightstep_tracer_factory.cpp diff --git a/benchmark/span_operations_benchmark.cpp b/benchmark/span_operations_benchmark.cpp index 5f536418..ca539698 100644 --- a/benchmark/span_operations_benchmark.cpp +++ b/benchmark/span_operations_benchmark.cpp @@ -29,6 +29,20 @@ static void BM_SpanCreation(benchmark::State& state) { } BENCHMARK(BM_SpanCreation); +static void BM_SpanCreationWithParent(benchmark::State& state) { + auto tracer = MakeTracer(); + assert(tracer != nullptr); + auto parent_span = tracer->StartSpan("parent"); + parent_span->Finish(); + opentracing::StartSpanOptions options; + options.references.emplace_back(opentracing::SpanReferenceType::ChildOfRef, + &parent_span->context()); + for (auto _ : state) { + auto span = tracer->StartSpanWithOptions("abc123", options); + } +} +BENCHMARK(BM_SpanCreationWithParent); + static void BM_SpanSetTag1(benchmark::State& state) { auto tracer = MakeTracer(); assert(tracer != nullptr); diff --git a/src/auto_recorder.cpp b/src/auto_recorder.cpp index 238b381d..88df8170 100644 --- a/src/auto_recorder.cpp +++ b/src/auto_recorder.cpp @@ -40,7 +40,7 @@ AutoRecorder::~AutoRecorder() { //------------------------------------------------------------------------------ // RecordSpan //------------------------------------------------------------------------------ -void AutoRecorder::RecordSpan(collector::Span&& span) noexcept try { +void AutoRecorder::RecordSpan(const collector::Span& span) noexcept try { std::lock_guard lock_guard{write_mutex_}; if (builder_.num_pending_spans() >= max_buffered_spans_snapshot_ || write_exit_) { @@ -48,7 +48,7 @@ void AutoRecorder::RecordSpan(collector::Span&& span) noexcept try { options_.metrics_observer->OnSpansDropped(1); return; } - builder_.AddSpan(std::move(span)); + builder_.AddSpan(span); if (builder_.num_pending_spans() >= max_buffered_spans_snapshot_) { write_cond_->NotifyAll(); } diff --git a/src/auto_recorder.h b/src/auto_recorder.h index 295012ff..372ed17e 100644 --- a/src/auto_recorder.h +++ b/src/auto_recorder.h @@ -16,7 +16,7 @@ namespace lightstep { // AutoRecorder buffers spans finished by a tracer and sends them over to // the provided SyncTransporter. It uses an internal thread to regularly send // the reports according to the rate specified by LightStepTracerOptions. -class AutoRecorder : public Recorder { +class AutoRecorder final : public Recorder { public: AutoRecorder(Logger& logger, LightStepTracerOptions&& options, std::unique_ptr&& transporter); @@ -32,7 +32,7 @@ class AutoRecorder : public Recorder { ~AutoRecorder() override; - void RecordSpan(collector::Span&& span) noexcept override; + void RecordSpan(const collector::Span& span) noexcept override; bool FlushWithTimeout( std::chrono::system_clock::duration timeout) noexcept override; diff --git a/src/lightstep_immutable_span_context.cpp b/src/lightstep_immutable_span_context.cpp new file mode 100644 index 00000000..c9d54ac2 --- /dev/null +++ b/src/lightstep_immutable_span_context.cpp @@ -0,0 +1,37 @@ +#include "lightstep_immutable_span_context.h" + +namespace lightstep { +//------------------------------------------------------------------------------ +// constructor +//------------------------------------------------------------------------------ +LightStepImmutableSpanContext::LightStepImmutableSpanContext( + uint64_t trace_id, uint64_t span_id, bool sampled, + const std::unordered_map& baggage) + : trace_id_{trace_id}, span_id_{span_id}, sampled_{sampled} { + for (auto& baggage_item : baggage) { + baggage_.insert( + BaggageMap::value_type(baggage_item.first, baggage_item.second)); + } +} + +LightStepImmutableSpanContext::LightStepImmutableSpanContext( + uint64_t trace_id, uint64_t span_id, bool sampled, + BaggageMap&& baggage) noexcept + : trace_id_{trace_id}, + span_id_{span_id}, + sampled_{sampled}, + baggage_{std::move(baggage)} {} + +//------------------------------------------------------------------------------ +// ForeachBaggageItem +//------------------------------------------------------------------------------ +void LightStepImmutableSpanContext::ForeachBaggageItem( + std::function f) + const { + for (const auto& baggage_item : baggage_) { + if (!f(baggage_item.first, baggage_item.second)) { + return; + } + } +} +} // namespace lightstep diff --git a/src/lightstep_immutable_span_context.h b/src/lightstep_immutable_span_context.h new file mode 100644 index 00000000..41768785 --- /dev/null +++ b/src/lightstep_immutable_span_context.h @@ -0,0 +1,56 @@ +#pragma once + +#include "lightstep_span_context.h" + +namespace lightstep { +class LightStepImmutableSpanContext final : public LightStepSpanContext { + public: + LightStepImmutableSpanContext( + uint64_t trace_id, uint64_t span_id, bool sampled, + const std::unordered_map& baggage); + + LightStepImmutableSpanContext(uint64_t trace_id, uint64_t span_id, + bool sampled, BaggageMap&& baggage) noexcept; + + uint64_t trace_id() const noexcept override { return trace_id_; } + + uint64_t span_id() const noexcept override { return span_id_; } + + bool sampled() const noexcept override { return sampled_; } + + void ForeachBaggageItem( + std::function f) + const override; + + opentracing::expected Inject( + const PropagationOptions& propagation_options, + std::ostream& writer) const override { + return this->InjectImpl(propagation_options, writer); + } + + opentracing::expected Inject( + const PropagationOptions& propagation_options, + const opentracing::TextMapWriter& writer) const override { + return this->InjectImpl(propagation_options, writer); + } + + opentracing::expected Inject( + const PropagationOptions& propagation_options, + const opentracing::HTTPHeadersWriter& writer) const override { + return this->InjectImpl(propagation_options, writer); + } + + private: + uint64_t trace_id_; + uint64_t span_id_; + bool sampled_; + BaggageMap baggage_; + + template + opentracing::expected InjectImpl( + const PropagationOptions& propagation_options, Carrier& writer) const { + return InjectSpanContext(propagation_options, writer, trace_id_, span_id_, + sampled_, baggage_); + } +}; +} // namespace lightstep diff --git a/src/lightstep_span.cpp b/src/lightstep_span.cpp index 5e4bd6cc..b6fac63e 100644 --- a/src/lightstep_span.cpp +++ b/src/lightstep_span.cpp @@ -8,6 +8,23 @@ using opentracing::SteadyClock; using opentracing::SteadyTime; namespace lightstep { +//------------------------------------------------------------------------------ +// ToLog +//------------------------------------------------------------------------------ +template +static collector::Log ToLog(std::chrono::system_clock::time_point timestamp, + Iterator field_first, Iterator field_last) { + collector::Log result; + *result.mutable_timestamp() = ToTimestamp(timestamp); + auto& key_values = *result.mutable_fields(); + key_values.Reserve(static_cast(std::distance(field_first, field_last))); + for (Iterator field_iter = field_first; field_iter != field_last; + ++field_iter) { + *key_values.Add() = ToKeyValue(field_iter->first, field_iter->second); + } + return result; +} + //------------------------------------------------------------------------------ // is_sampled //------------------------------------------------------------------------------ @@ -50,8 +67,8 @@ static bool SetSpanReference( Logger& logger, const std::pair& reference, - std::unordered_map& baggage, - collector::Reference& collector_reference, bool& sampled) { + BaggageMap& baggage, collector::Reference& collector_reference, + bool& sampled) { collector_reference.Clear(); switch (reference.first) { case opentracing::SpanReferenceType::ChildOfRef: @@ -93,52 +110,55 @@ LightStepSpan::LightStepSpan( std::shared_ptr&& tracer, Logger& logger, Recorder& recorder, opentracing::string_view operation_name, const opentracing::StartSpanOptions& options) - : tracer_{std::move(tracer)}, - logger_{logger}, - recorder_{recorder}, - operation_name_{operation_name} { + : tracer_{std::move(tracer)}, logger_{logger}, recorder_{recorder} { + span_.set_operation_name(operation_name.data(), operation_name.size()); + auto& span_context = *span_.mutable_span_context(); + auto& baggage = *span_context.mutable_baggage(); + // Set the start timestamps. - std::tie(start_timestamp_, start_steady_) = ComputeStartTimestamps( + std::chrono::system_clock::time_point start_timestamp; + std::tie(start_timestamp, start_steady_) = ComputeStartTimestamps( options.start_system_timestamp, options.start_steady_timestamp); + *span_.mutable_start_timestamp() = ToTimestamp(start_timestamp); // Set any span references. - std::unordered_map baggage; - references_.reserve(options.references.size()); + sampled_ = false; collector::Reference collector_reference; - bool sampled = false; + auto& references = *span_.mutable_references(); + references.Reserve(static_cast(options.references.size())); for (auto& reference : options.references) { if (!SetSpanReference(logger_, reference, baggage, collector_reference, - sampled)) { + sampled_)) { continue; } - references_.push_back(collector_reference); + *references.Add() = collector_reference; } // If there are any span references, sampled should be true if any of the // references are sampled; with no refences, we set sampled to true. - if (references_.empty()) { - sampled = true; + if (references.empty()) { + sampled_ = true; } // Set tags. + auto& tags = *span_.mutable_tags(); + tags.Reserve(static_cast(options.tags.size())); for (auto& tag : options.tags) { - tags_[tag.first] = tag.second; - } + *tags.Add() = ToKeyValue(tag.first, tag.second); - // If sampling_priority is set, it overrides whatever sampling decision was - // derived from the referenced spans. - auto sampling_priority_tag = tags_.find(opentracing::ext::sampling_priority); - if (sampling_priority_tag != tags_.end()) { - sampled = is_sampled(sampling_priority_tag->second); + // If sampling_priority is set, it overrides whatever sampling decision was + // derived from the referenced spans. + if (tag.first == opentracing::ext::sampling_priority) { + sampled_ = is_sampled(tag.second); + } } // Set opentracing::SpanContext. - auto trace_id = references_.empty() - ? GenerateId() - : references_[0].span_context().trace_id(); + auto trace_id = references.empty() ? GenerateId() + : references[0].span_context().trace_id(); auto span_id = GenerateId(); - span_context_ = - LightStepSpanContext{trace_id, span_id, sampled, std::move(baggage)}; + span_context.set_trace_id(trace_id); + span_context.set_span_id(span_id); } //------------------------------------------------------------------------------ @@ -160,8 +180,8 @@ void LightStepSpan::FinishWithOptions( return; } - // If the span isn't sampled do nothing. - if (!span_context_.sampled()) { + std::lock_guard lock_guard{mutex_}; + if (!sampled_) { return; } @@ -170,74 +190,25 @@ void LightStepSpan::FinishWithOptions( finish_timestamp = SteadyClock::now(); } - collector::Span span; - // Set timing information. auto duration = finish_timestamp - start_steady_; - span.set_duration_micros( + span_.set_duration_micros( std::chrono::duration_cast(duration).count()); - *span.mutable_start_timestamp() = ToTimestamp(start_timestamp_); - - // Set references. - auto references = span.mutable_references(); - references->Reserve(static_cast(references_.size())); - for (const auto& reference : references_) { - *references->Add() = reference; - } - // Set tags, logs, and operation name. - { - std::lock_guard lock_guard{mutex_}; - span.set_operation_name(std::move(operation_name_)); - auto tags = span.mutable_tags(); - tags->Reserve(static_cast(tags_.size())); - for (const auto& tag : tags_) { - try { - *tags->Add() = ToKeyValue(tag.first, tag.second); - } catch (const std::exception& e) { - logger_.Error(R"(Dropping tag for key ")", tag.first, - R"(": )", e.what()); - } - } - auto logs = span.mutable_logs(); - logs->Reserve(static_cast(logs_.size()) + - static_cast(options.log_records.size())); - for (auto& log : logs_) { - try { - *logs->Add() = std::move(log); - } catch (const std::exception& e) { - logger_.Error("Dropping log record: ", e.what()); - } - } - for (auto& log_record : options.log_records) { - try { - collector::Log log; - *log.mutable_timestamp() = ToTimestamp(log_record.timestamp); - auto key_values = log.mutable_fields(); - for (auto& field : log_record.fields) { - *key_values->Add() = ToKeyValue(field.first, field.second); - } - *logs->Add() = std::move(log); - } catch (const std::exception& e) { - logger_.Error("Dropping log record: ", e.what()); - } + // Set logs + auto& logs = *span_.mutable_logs(); + logs.Reserve(logs.size() + static_cast(options.log_records.size())); + for (auto& log_record : options.log_records) { + try { + *logs.Add() = ToLog(log_record.timestamp, std::begin(log_record.fields), + std::end(log_record.fields)); + } catch (const std::exception& e) { + logger_.Error("Dropping log record: ", e.what()); } } - // Set the span context. - auto span_context = span.mutable_span_context(); - span_context->set_trace_id(span_context_.trace_id()); - span_context->set_span_id(span_context_.span_id()); - auto baggage = span_context->mutable_baggage(); - span_context_.ForeachBaggageItem( - [baggage](const std::string& key, const std::string& value) { - using StringMap = google::protobuf::Map; - baggage->insert(StringMap::value_type(key, value)); - return true; - }); - // Record the span - recorder_.RecordSpan(std::move(span)); + recorder_.RecordSpan(span_); } catch (const std::exception& e) { logger_.Error("FinishWithOptions failed: ", e.what()); } @@ -248,7 +219,7 @@ void LightStepSpan::FinishWithOptions( void LightStepSpan::SetOperationName( opentracing::string_view name) noexcept try { std::lock_guard lock_guard{mutex_}; - operation_name_ = name; + span_.set_operation_name(name.data(), name.size()); } catch (const std::exception& e) { logger_.Error("SetOperationName failed: ", e.what()); } @@ -259,10 +230,10 @@ void LightStepSpan::SetOperationName( void LightStepSpan::SetTag(opentracing::string_view key, const opentracing::Value& value) noexcept try { std::lock_guard lock_guard{mutex_}; - tags_[key] = value; + *span_.mutable_tags()->Add() = ToKeyValue(key, value); if (key == opentracing::ext::sampling_priority) { - span_context_.set_sampled(is_sampled(value)); + sampled_ = is_sampled(value); } } catch (const std::exception& e) { logger_.Error("SetTag failed: ", e.what()); @@ -273,7 +244,9 @@ void LightStepSpan::SetTag(opentracing::string_view key, //------------------------------------------------------------------------------ void LightStepSpan::SetBaggageItem(opentracing::string_view restricted_key, opentracing::string_view value) noexcept { - span_context_.set_baggage_item(restricted_key, value); + std::lock_guard lock_guard{mutex_}; + auto& baggage = *span_.mutable_span_context()->mutable_baggage(); + baggage.insert(BaggageMap::value_type(restricted_key, value)); } //------------------------------------------------------------------------------ @@ -281,7 +254,13 @@ void LightStepSpan::SetBaggageItem(opentracing::string_view restricted_key, //------------------------------------------------------------------------------ std::string LightStepSpan::BaggageItem( opentracing::string_view restricted_key) const noexcept try { - return span_context_.baggage_item(restricted_key); + std::lock_guard lock_guard{mutex_}; + auto& baggage = span_.span_context().baggage(); + auto lookup = baggage.find(restricted_key); + if (lookup != baggage.end()) { + return lookup->second; + } + return {}; } catch (const std::exception& e) { logger_.Error("BaggageItem failed, returning empty string: ", e.what()); return {}; @@ -294,15 +273,32 @@ void LightStepSpan::Log(std::initializer_list< std::pair> fields) noexcept try { auto timestamp = SystemClock::now(); - collector::Log log; - *log.mutable_timestamp() = ToTimestamp(timestamp); - auto key_values = log.mutable_fields(); - for (const auto& field : fields) { - *key_values->Add() = ToKeyValue(field.first, field.second); - } std::lock_guard lock_guard{mutex_}; - logs_.emplace_back(std::move(log)); + *span_.mutable_logs()->Add() = + ToLog(timestamp, std::begin(fields), std::end(fields)); } catch (const std::exception& e) { logger_.Error("Log failed: ", e.what()); } + +//------------------------------------------------------------------------------ +// ForeachBaggageItem +//------------------------------------------------------------------------------ +void LightStepSpan::ForeachBaggageItem( + std::function f) + const { + std::lock_guard lock_guard{mutex_}; + for (const auto& baggage_item : span_.span_context().baggage()) { + if (!f(baggage_item.first, baggage_item.second)) { + return; + } + } +} + +//------------------------------------------------------------------------------ +// sampled +//------------------------------------------------------------------------------ +bool LightStepSpan::sampled() const noexcept { + std::lock_guard lock_guard{mutex_}; + return sampled_; +} } // namespace lightstep diff --git a/src/lightstep_span.h b/src/lightstep_span.h index 16d1c54d..78f1c1dc 100644 --- a/src/lightstep_span.h +++ b/src/lightstep_span.h @@ -1,16 +1,19 @@ #pragma once -#include -#include -#include -#include #include "lightstep-tracer-common/collector.pb.h" #include "lightstep_span_context.h" #include "logger.h" #include "recorder.h" +#include + +#include +#include +#include + namespace lightstep { -class LightStepSpan : public opentracing::Span { +class LightStepSpan final : public opentracing::Span, + public LightStepSpanContext { public: LightStepSpan(std::shared_ptr&& tracer, Logger& logger, Recorder& recorder, @@ -43,28 +46,64 @@ class LightStepSpan : public opentracing::Span { fields) noexcept override; const opentracing::SpanContext& context() const noexcept override { - return span_context_; + return *this; } const opentracing::Tracer& tracer() const noexcept override { return *tracer_; } + void ForeachBaggageItem( + std::function f) + const override; + + bool sampled() const noexcept override; + + uint64_t trace_id() const noexcept override { + return span_.span_context().trace_id(); + } + + uint64_t span_id() const noexcept override { + return span_.span_context().span_id(); + } + + virtual opentracing::expected Inject( + const PropagationOptions& propagation_options, + std::ostream& writer) const override { + return this->InjectImpl(propagation_options, writer); + } + + virtual opentracing::expected Inject( + const PropagationOptions& propagation_options, + const opentracing::TextMapWriter& writer) const override { + return this->InjectImpl(propagation_options, writer); + } + + virtual opentracing::expected Inject( + const PropagationOptions& propagation_options, + const opentracing::HTTPHeadersWriter& writer) const override { + return this->InjectImpl(propagation_options, writer); + } + private: // Fields set in StartSpan() are not protected by a mutex. + collector::Span span_; + std::chrono::steady_clock::time_point start_steady_; + bool sampled_; + mutable std::mutex mutex_; std::shared_ptr tracer_; Logger& logger_; Recorder& recorder_; - std::vector references_; - std::chrono::system_clock::time_point start_timestamp_; - std::chrono::steady_clock::time_point start_steady_; - LightStepSpanContext span_context_; std::atomic is_finished_{false}; - // Mutex protects tags_, logs_, and operation_name_. - std::mutex mutex_; - std::string operation_name_; - std::unordered_map tags_; - std::vector logs_; + template + opentracing::expected InjectImpl( + const PropagationOptions& propagation_options, Carrier& writer) const { + std::lock_guard lock_guard{mutex_}; + auto& span_context = span_.span_context(); + return InjectSpanContext(propagation_options, writer, + span_context.trace_id(), span_context.span_id(), + sampled_, span_context.baggage()); + } }; } // namespace lightstep diff --git a/src/lightstep_span_context.cpp b/src/lightstep_span_context.cpp index 751f96bc..76e6a962 100644 --- a/src/lightstep_span_context.cpp +++ b/src/lightstep_span_context.cpp @@ -1,88 +1,6 @@ #include "lightstep_span_context.h" namespace lightstep { -//------------------------------------------------------------------------------ -// Constructor -//------------------------------------------------------------------------------ -LightStepSpanContext::LightStepSpanContext( - uint64_t trace_id, uint64_t span_id, - std::unordered_map&& baggage) noexcept - : trace_id_{trace_id}, span_id_{span_id}, baggage_{std::move(baggage)} {} - -LightStepSpanContext::LightStepSpanContext( - uint64_t trace_id, uint64_t span_id, bool sampled, - std::unordered_map&& baggage) noexcept - : trace_id_{trace_id}, - span_id_{span_id}, - sampled_{sampled}, - baggage_{std::move(baggage)} {} - -//------------------------------------------------------------------------------ -// operator= -//------------------------------------------------------------------------------ -LightStepSpanContext& LightStepSpanContext::operator=( - LightStepSpanContext&& other) noexcept { - trace_id_ = other.trace_id_; - span_id_ = other.span_id_; - sampled_ = other.sampled_; - baggage_ = std::move(other.baggage_); - return *this; -} - -//------------------------------------------------------------------------------ -// set_baggage_item -//------------------------------------------------------------------------------ -void LightStepSpanContext::set_baggage_item( - opentracing::string_view key, opentracing::string_view value) noexcept try { - std::lock_guard lock_guard{mutex_}; - baggage_.emplace(key, value); -} catch (const std::exception&) { - // Drop baggage item upon error. -} - -//------------------------------------------------------------------------------ -// baggage_item -//------------------------------------------------------------------------------ -std::string LightStepSpanContext::baggage_item( - opentracing::string_view key) const { - std::lock_guard lock_guard{mutex_}; - auto lookup = baggage_.find(key); - if (lookup != baggage_.end()) { - return lookup->second; - } - return {}; -} - -//------------------------------------------------------------------------------ -// ForeachBaggageItem -//------------------------------------------------------------------------------ -void LightStepSpanContext::ForeachBaggageItem( - std::function f) - const { - std::lock_guard lock_guard{mutex_}; - for (const auto& baggage_item : baggage_) { - if (!f(baggage_item.first, baggage_item.second)) { - return; - } - } -} - -//------------------------------------------------------------------------------ -// sampled -//------------------------------------------------------------------------------ -bool LightStepSpanContext::sampled() const noexcept { - std::lock_guard lock_guard{mutex_}; - return sampled_; -} - -//------------------------------------------------------------------------------ -// set_sampled -//------------------------------------------------------------------------------ -void LightStepSpanContext::set_sampled(bool sampled) noexcept { - std::lock_guard lock_guard{mutex_}; - sampled_ = sampled; -} - //------------------------------------------------------------------------------ // operator== //------------------------------------------------------------------------------ diff --git a/src/lightstep_span_context.h b/src/lightstep_span_context.h index 12052383..d0a44967 100644 --- a/src/lightstep_span_context.h +++ b/src/lightstep_span_context.h @@ -10,62 +10,23 @@ namespace lightstep { class LightStepSpanContext : public opentracing::SpanContext { public: - LightStepSpanContext() = default; + virtual bool sampled() const noexcept = 0; - LightStepSpanContext( - uint64_t trace_id, uint64_t span_id, - std::unordered_map&& baggage) noexcept; + virtual uint64_t trace_id() const noexcept = 0; - LightStepSpanContext( - uint64_t trace_id, uint64_t span_id, bool sampled, - std::unordered_map&& baggage) noexcept; + virtual uint64_t span_id() const noexcept = 0; - LightStepSpanContext(const LightStepSpanContext&) = delete; - LightStepSpanContext(LightStepSpanContext&&) = delete; + virtual opentracing::expected Inject( + const PropagationOptions& propagation_options, + std::ostream& writer) const = 0; - ~LightStepSpanContext() override = default; + virtual opentracing::expected Inject( + const PropagationOptions& propagation_options, + const opentracing::TextMapWriter& writer) const = 0; - LightStepSpanContext& operator=(LightStepSpanContext&) = delete; - LightStepSpanContext& operator=(LightStepSpanContext&& other) noexcept; - - void set_baggage_item(opentracing::string_view key, - opentracing::string_view value) noexcept; - - std::string baggage_item(opentracing::string_view key) const; - - void ForeachBaggageItem( - std::function f) - const override; - - template - opentracing::expected Inject( - const PropagationOptions& propagation_options, Carrier& writer) const { - std::lock_guard lock_guard{mutex_}; - return InjectSpanContext(propagation_options, writer, trace_id_, span_id_, - sampled_, baggage_); - } - - template - opentracing::expected Extract( - const PropagationOptions& propagation_options, Carrier& reader) { - std::lock_guard lock_guard{mutex_}; - return ExtractSpanContext(propagation_options, reader, trace_id_, span_id_, - sampled_, baggage_); - } - - uint64_t trace_id() const noexcept { return trace_id_; } - uint64_t span_id() const noexcept { return span_id_; } - - bool sampled() const noexcept; - void set_sampled(bool sampled) noexcept; - - private: - uint64_t trace_id_ = 0; - uint64_t span_id_ = 0; - - mutable std::mutex mutex_; - bool sampled_ = true; - std::unordered_map baggage_; + virtual opentracing::expected Inject( + const PropagationOptions& propagation_options, + const opentracing::HTTPHeadersWriter& writer) const = 0; }; bool operator==(const LightStepSpanContext& lhs, diff --git a/src/lightstep_tracer_factory.h b/src/lightstep_tracer_factory.h index 90b00948..7e7df050 100644 --- a/src/lightstep_tracer_factory.h +++ b/src/lightstep_tracer_factory.h @@ -3,7 +3,7 @@ #include namespace lightstep { -class LightStepTracerFactory : public opentracing::TracerFactory { +class LightStepTracerFactory final : public opentracing::TracerFactory { public: opentracing::expected> MakeTracer( const char* configuration, std::string& error_message) const diff --git a/src/lightstep_tracer_impl.cpp b/src/lightstep_tracer_impl.cpp index 44ba926a..76700e2c 100644 --- a/src/lightstep_tracer_impl.cpp +++ b/src/lightstep_tracer_impl.cpp @@ -1,6 +1,6 @@ #include "lightstep_tracer_impl.h" +#include "lightstep_immutable_span_context.h" #include "lightstep_span.h" -#include "lightstep_span_context.h" namespace lightstep { @@ -25,24 +25,25 @@ static opentracing::expected InjectImpl( //------------------------------------------------------------------------------ template opentracing::expected> ExtractImpl( - const PropagationOptions& propagation_options, Carrier& reader) { - LightStepSpanContext* lightstep_span_context; - try { - lightstep_span_context = new LightStepSpanContext{}; - } catch (const std::bad_alloc&) { - return opentracing::make_unexpected( - make_error_code(std::errc::not_enough_memory)); - } - std::unique_ptr span_context( - lightstep_span_context); - auto result = lightstep_span_context->Extract(propagation_options, reader); - if (!result) { - return opentracing::make_unexpected(result.error()); + const PropagationOptions& propagation_options, Carrier& reader) try { + uint64_t trace_id, span_id; + bool sampled; + BaggageMap baggage; + auto extract_maybe = ExtractSpanContext(propagation_options, reader, trace_id, + span_id, sampled, baggage); + if (!extract_maybe) { + return opentracing::make_unexpected(extract_maybe.error()); } - if (!*result) { - span_context.reset(); + if (!*extract_maybe) { + return std::unique_ptr{nullptr}; } - return std::move(span_context); + std::unique_ptr result{ + new LightStepImmutableSpanContext{trace_id, span_id, sampled, + std::move(baggage)}}; + return std::move(result); +} catch (const std::bad_alloc&) { + return opentracing::make_unexpected( + make_error_code(std::errc::not_enough_memory)); } //------------------------------------------------------------------------------ diff --git a/src/lightstep_tracer_impl.h b/src/lightstep_tracer_impl.h index d9f44d1e..4dfa4d83 100644 --- a/src/lightstep_tracer_impl.h +++ b/src/lightstep_tracer_impl.h @@ -6,7 +6,7 @@ #include "recorder.h" namespace lightstep { -class LightStepTracerImpl +class LightStepTracerImpl final : public LightStepTracer, public std::enable_shared_from_this { public: diff --git a/src/manual_recorder.cpp b/src/manual_recorder.cpp index d73137a6..2bc44650 100644 --- a/src/manual_recorder.cpp +++ b/src/manual_recorder.cpp @@ -20,7 +20,7 @@ ManualRecorder::ManualRecorder(Logger& logger, LightStepTracerOptions options, //------------------------------------------------------------------------------ // RecordSpan //------------------------------------------------------------------------------ -void ManualRecorder::RecordSpan(collector::Span&& span) noexcept try { +void ManualRecorder::RecordSpan(const collector::Span& span) noexcept try { if (disabled_) { dropped_spans_++; options_.metrics_observer->OnSpansDropped(1); @@ -41,7 +41,7 @@ void ManualRecorder::RecordSpan(collector::Span&& span) noexcept try { return; } } - builder_.AddSpan(std::move(span)); + builder_.AddSpan(span); if (builder_.num_pending_spans() >= max_buffered_spans) { FlushOne(); } diff --git a/src/manual_recorder.h b/src/manual_recorder.h index 01b7fa38..9daf4ede 100644 --- a/src/manual_recorder.h +++ b/src/manual_recorder.h @@ -8,12 +8,13 @@ namespace lightstep { // ManualRecorder buffers spans finished by a tracer and sends them over to // the provided AsyncTransporter when FlushWithTimeout is called. -class ManualRecorder : public Recorder, private AsyncTransporter::Callback { +class ManualRecorder final : public Recorder, + private AsyncTransporter::Callback { public: ManualRecorder(Logger& logger, LightStepTracerOptions options, std::unique_ptr&& transporter); - void RecordSpan(collector::Span&& span) noexcept override; + void RecordSpan(const collector::Span& span) noexcept override; bool FlushWithTimeout( std::chrono::system_clock::duration timeout) noexcept override; diff --git a/src/propagation.cpp b/src/propagation.cpp index effd4640..e79c799e 100644 --- a/src/propagation.cpp +++ b/src/propagation.cpp @@ -80,8 +80,7 @@ static opentracing::expected LookupKey( //------------------------------------------------------------------------------ static opentracing::expected InjectSpanContextMultiKey( const opentracing::TextMapWriter& carrier, uint64_t trace_id, - uint64_t span_id, bool sampled, - const std::unordered_map& baggage) { + uint64_t span_id, bool sampled, const BaggageMap& baggage) { std::string trace_id_hex, span_id_hex, baggage_key; try { trace_id_hex = Uint64ToHex(trace_id); @@ -128,8 +127,7 @@ static opentracing::expected InjectSpanContextMultiKey( //------------------------------------------------------------------------------ static opentracing::expected InjectSpanContextSingleKey( const opentracing::TextMapWriter& carrier, uint64_t trace_id, - uint64_t span_id, bool sampled, - const std::unordered_map& baggage) { + uint64_t span_id, bool sampled, const BaggageMap& baggage) { std::ostringstream ostream; auto result = InjectSpanContext(PropagationOptions{}, ostream, trace_id, span_id, sampled, baggage); @@ -158,7 +156,7 @@ static opentracing::expected InjectSpanContextSingleKey( //------------------------------------------------------------------------------ static opentracing::expected InjectSpanContext( BinaryCarrier& carrier, uint64_t trace_id, uint64_t span_id, bool sampled, - const std::unordered_map& baggage) noexcept try { + const BaggageMap& baggage) noexcept try { carrier.Clear(); auto basic = carrier.mutable_basic_ctx(); basic->set_trace_id(trace_id); @@ -177,7 +175,7 @@ static opentracing::expected InjectSpanContext( opentracing::expected InjectSpanContext( const PropagationOptions& /*propagation_options*/, std::ostream& carrier, uint64_t trace_id, uint64_t span_id, bool sampled, - const std::unordered_map& baggage) { + const BaggageMap& baggage) { BinaryCarrier binary_carrier; auto result = InjectSpanContext(binary_carrier, trace_id, span_id, sampled, baggage); @@ -203,8 +201,7 @@ opentracing::expected InjectSpanContext( opentracing::expected InjectSpanContext( const PropagationOptions& propagation_options, const opentracing::TextMapWriter& carrier, uint64_t trace_id, - uint64_t span_id, bool sampled, - const std::unordered_map& baggage) { + uint64_t span_id, bool sampled, const BaggageMap& baggage) { if (propagation_options.use_single_key) { return InjectSpanContextSingleKey(carrier, trace_id, span_id, sampled, baggage); @@ -219,37 +216,36 @@ opentracing::expected InjectSpanContext( template static opentracing::expected ExtractSpanContextMultiKey( const opentracing::TextMapReader& carrier, uint64_t& trace_id, - uint64_t& span_id, bool& sampled, - std::unordered_map& baggage, + uint64_t& span_id, bool& sampled, BaggageMap& baggage, KeyCompare key_compare) { int count = 0; - auto result = carrier.ForeachKey( - [&](opentracing::string_view key, - opentracing::string_view value) -> opentracing::expected { - try { - if (key_compare(key, FieldNameTraceID)) { - trace_id = HexToUint64(value); - count++; - } else if (key_compare(key, FieldNameSpanID)) { - span_id = HexToUint64(value); - count++; - } else if (key_compare(key, FieldNameSampled)) { - sampled = !(value == "false" || value == "0"); - count++; - } else if (key.length() > PrefixBaggage.size() && - key_compare(opentracing::string_view{key.data(), - PrefixBaggage.size()}, - PrefixBaggage)) { - baggage.emplace(std::string{std::begin(key) + PrefixBaggage.size(), - std::end(key)}, - value); - } - return {}; - } catch (const std::bad_alloc&) { - return opentracing::make_unexpected( - std::make_error_code(std::errc::not_enough_memory)); - } - }); + auto result = carrier.ForeachKey([&](opentracing::string_view key, + opentracing::string_view value) + -> opentracing::expected { + try { + if (key_compare(key, FieldNameTraceID)) { + trace_id = HexToUint64(value); + count++; + } else if (key_compare(key, FieldNameSpanID)) { + span_id = HexToUint64(value); + count++; + } else if (key_compare(key, FieldNameSampled)) { + sampled = !(value == "false" || value == "0"); + count++; + } else if (key.length() > PrefixBaggage.size() && + key_compare( + opentracing::string_view{key.data(), PrefixBaggage.size()}, + PrefixBaggage)) { + baggage.insert(BaggageMap::value_type( + std::string{std::begin(key) + PrefixBaggage.size(), std::end(key)}, + value)); + } + return {}; + } catch (const std::bad_alloc&) { + return opentracing::make_unexpected( + std::make_error_code(std::errc::not_enough_memory)); + } + }); if (!result) { return opentracing::make_unexpected(result.error()); } @@ -269,8 +265,7 @@ static opentracing::expected ExtractSpanContextMultiKey( template static opentracing::expected ExtractSpanContextSingleKey( const opentracing::TextMapReader& carrier, uint64_t& trace_id, - uint64_t& span_id, bool& sampled, - std::unordered_map& baggage, + uint64_t& span_id, bool& sampled, BaggageMap& baggage, KeyCompare key_compare) { auto value_maybe = LookupKey(carrier, PropagationSingleKey, key_compare); if (!value_maybe) { @@ -301,15 +296,12 @@ static opentracing::expected ExtractSpanContextSingleKey( //------------------------------------------------------------------------------ static opentracing::expected ExtractSpanContext( const BinaryCarrier& carrier, uint64_t& trace_id, uint64_t& span_id, - bool& sampled, - std::unordered_map& baggage) noexcept try { + bool& sampled, BaggageMap& baggage) noexcept try { auto& basic = carrier.basic_ctx(); trace_id = basic.trace_id(); span_id = basic.span_id(); sampled = basic.sampled(); - for (const auto& entry : basic.baggage_items()) { - baggage.emplace(entry.first, entry.second); - } + baggage = basic.baggage_items(); return true; } catch (const std::bad_alloc&) { return opentracing::make_unexpected( @@ -319,7 +311,7 @@ static opentracing::expected ExtractSpanContext( opentracing::expected ExtractSpanContext( const PropagationOptions& /*propagation_options*/, std::istream& carrier, uint64_t& trace_id, uint64_t& span_id, bool& sampled, - std::unordered_map& baggage) try { + BaggageMap& baggage) try { // istream::peek returns EOF if it's in an error state, so check for an error // state first before checking for an empty stream. if (!carrier.good()) { @@ -348,8 +340,7 @@ template static opentracing::expected ExtractSpanContext( const PropagationOptions& propagation_options, const opentracing::TextMapReader& carrier, uint64_t& trace_id, - uint64_t& span_id, bool& sampled, - std::unordered_map& baggage, + uint64_t& span_id, bool& sampled, BaggageMap& baggage, KeyCompare key_compare) { if (propagation_options.use_single_key) { auto span_context_maybe = ExtractSpanContextSingleKey( @@ -369,8 +360,7 @@ static opentracing::expected ExtractSpanContext( opentracing::expected ExtractSpanContext( const PropagationOptions& propagation_options, const opentracing::TextMapReader& carrier, uint64_t& trace_id, - uint64_t& span_id, bool& sampled, - std::unordered_map& baggage) { + uint64_t& span_id, bool& sampled, BaggageMap& baggage) { return ExtractSpanContext(propagation_options, carrier, trace_id, span_id, sampled, baggage, std::equal_to()); @@ -383,8 +373,7 @@ opentracing::expected ExtractSpanContext( opentracing::expected ExtractSpanContext( const PropagationOptions& propagation_options, const opentracing::HTTPHeadersReader& carrier, uint64_t& trace_id, - uint64_t& span_id, bool& sampled, - std::unordered_map& baggage) { + uint64_t& span_id, bool& sampled, BaggageMap& baggage) { auto iequals = [](opentracing::string_view lhs, opentracing::string_view rhs) { return lhs.length() == rhs.length() && diff --git a/src/propagation.h b/src/propagation.h index f4cb0372..514b405c 100644 --- a/src/propagation.h +++ b/src/propagation.h @@ -1,9 +1,12 @@ #pragma once +#include #include #include namespace lightstep { +using BaggageMap = google::protobuf::Map; + struct PropagationOptions { bool use_single_key = false; }; @@ -11,28 +14,24 @@ struct PropagationOptions { opentracing::expected InjectSpanContext( const PropagationOptions& propagation_options, std::ostream& carrier, uint64_t trace_id, uint64_t span_id, bool sampled, - const std::unordered_map& baggage); + const BaggageMap& baggage); opentracing::expected InjectSpanContext( const PropagationOptions& propagation_options, const opentracing::TextMapWriter& carrier, uint64_t trace_id, - uint64_t span_id, bool sampled, - const std::unordered_map& baggage); + uint64_t span_id, bool sampled, const BaggageMap& baggage); opentracing::expected ExtractSpanContext( const PropagationOptions& propagation_options, std::istream& carrier, - uint64_t& trace_id, uint64_t& span_id, bool& sampled, - std::unordered_map& baggage); + uint64_t& trace_id, uint64_t& span_id, bool& sampled, BaggageMap& baggage); opentracing::expected ExtractSpanContext( const PropagationOptions& propagation_options, const opentracing::TextMapReader& carrier, uint64_t& trace_id, - uint64_t& span_id, bool& sampled, - std::unordered_map& baggage); + uint64_t& span_id, bool& sampled, BaggageMap& baggage); opentracing::expected ExtractSpanContext( const PropagationOptions& propagation_options, const opentracing::HTTPHeadersReader& carrier, uint64_t& trace_id, - uint64_t& span_id, bool& sampled, - std::unordered_map& baggage); + uint64_t& span_id, bool& sampled, BaggageMap& baggage); } // namespace lightstep diff --git a/src/recorder.h b/src/recorder.h index e094f7a4..5e6b5882 100644 --- a/src/recorder.h +++ b/src/recorder.h @@ -10,7 +10,7 @@ class Recorder { public: virtual ~Recorder() = default; - virtual void RecordSpan(collector::Span&& span) noexcept = 0; + virtual void RecordSpan(const collector::Span& span) noexcept = 0; virtual bool FlushWithTimeout( std::chrono::system_clock::duration /*timeout*/) noexcept { diff --git a/src/report_builder.cpp b/src/report_builder.cpp index eef06594..9f640958 100644 --- a/src/report_builder.cpp +++ b/src/report_builder.cpp @@ -20,7 +20,7 @@ ReportBuilder::ReportBuilder( //------------------------------------------------------------------------------ // AddSpan //------------------------------------------------------------------------------ -void ReportBuilder::AddSpan(collector::Span&& span) { +void ReportBuilder::AddSpan(const collector::Span& span) { if (reset_next_) { pending_.Clear(); pending_.CopyFrom(preamble_); diff --git a/src/report_builder.h b/src/report_builder.h index 9be75c2d..3a474e5f 100644 --- a/src/report_builder.h +++ b/src/report_builder.h @@ -16,7 +16,7 @@ class ReportBuilder { const std::unordered_map& tags); // AddSpan adds the span to the currently-building ReportRequest. - void AddSpan(collector::Span&& span); + void AddSpan(const collector::Span& span); // num_pending_spans() is the number of pending spans. size_t num_pending_spans() const { return pending_.spans_size(); } diff --git a/src/tracer.cpp b/src/tracer.cpp index 2c3d0ba3..6122fef5 100644 --- a/src/tracer.cpp +++ b/src/tracer.cpp @@ -12,7 +12,7 @@ #include "auto_recorder.h" #include "grpc_transporter.h" #include "lightstep-tracer-common/collector.pb.h" -#include "lightstep_span_context.h" +#include "lightstep_immutable_span_context.h" #include "lightstep_tracer_impl.h" #include "logger.h" #include "manual_recorder.h" @@ -84,7 +84,7 @@ LightStepTracer::MakeSpanContext( uint64_t trace_id, uint64_t span_id, bool sampled, std::unordered_map&& baggage) const noexcept try { std::unique_ptr result{ - new LightStepSpanContext{trace_id, span_id, sampled, std::move(baggage)}}; + new LightStepImmutableSpanContext{trace_id, span_id, sampled, baggage}}; return std::move(result); } catch (const std::bad_alloc&) { return opentracing::make_unexpected( diff --git a/test/in_memory_recorder.h b/test/in_memory_recorder.h index 2ee8d974..5fd4f778 100644 --- a/test/in_memory_recorder.h +++ b/test/in_memory_recorder.h @@ -7,11 +7,11 @@ namespace lightstep { // InMemoryRecorder is used for testing only. -class InMemoryRecorder : public Recorder { +class InMemoryRecorder final : public Recorder { public: - void RecordSpan(collector::Span&& span) noexcept override { + void RecordSpan(const collector::Span& span) noexcept override { std::lock_guard lock_guard{mutex_}; - spans_.emplace_back(std::move(span)); + spans_.emplace_back(span); } std::vector spans() const { diff --git a/test/propagation_test.cpp b/test/propagation_test.cpp index 95691610..8f629ede 100644 --- a/test/propagation_test.cpp +++ b/test/propagation_test.cpp @@ -7,7 +7,7 @@ #include #include #include -#include "../src/lightstep_span_context.h" +#include "../src/lightstep_immutable_span_context.h" #include "../src/lightstep_tracer_impl.h" #include "../src/utility.h" #include "in_memory_recorder.h" @@ -119,21 +119,22 @@ static std::vector> MakeTestSpanContexts() { std::vector> result; // most basic span context - result.push_back( - std::unique_ptr{new LightStepSpanContext{ - 123, 456, std::unordered_map{}}}); + result.push_back(std::unique_ptr{ + new LightStepImmutableSpanContext{ + 123, 456, true, std::unordered_map{}}}); // span context with single baggage item result.push_back(std::unique_ptr{ - new LightStepSpanContext{123, 456, {{"abc", "123"}}}}); + new LightStepImmutableSpanContext{123, 456, true, {{"abc", "123"}}}}); // span context with multiple baggage items result.push_back(std::unique_ptr{ - new LightStepSpanContext{123, 456, {{"abc", "123"}, {"xyz", "qrz"}}}}); + new LightStepImmutableSpanContext{ + 123, 456, true, {{"abc", "123"}, {"xyz", "qrz"}}}}); // unsampled span context - result.push_back( - std::unique_ptr{new LightStepSpanContext{ + result.push_back(std::unique_ptr{ + new LightStepImmutableSpanContext{ 123, 456, false, std::unordered_map{}}}); return result;