diff --git a/.gitignore b/.gitignore index 6fc863d..87b0eb5 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,5 @@ *.app bazel-* + +.build/ diff --git a/zipkin/include/zipkin/span_context.h b/zipkin/include/zipkin/span_context.h index 04816e0..48c08f5 100644 --- a/zipkin/include/zipkin/span_context.h +++ b/zipkin/include/zipkin/span_context.h @@ -58,6 +58,8 @@ class SpanContext { : trace_id_{trace_id}, id_{id}, parent_id_{parent_id}, flags_{flags}, is_initialized_{true} {} + bool isSampled() const { return flags_ & zipkin::sampled_flag; } + /** * @return the span id as an integer */ diff --git a/zipkin/include/zipkin/zipkin_core_types.h b/zipkin/include/zipkin/zipkin_core_types.h index 04b275f..684bb14 100644 --- a/zipkin/include/zipkin/zipkin_core_types.h +++ b/zipkin/include/zipkin/zipkin_core_types.h @@ -331,6 +331,9 @@ class Span : public ZipkinBase { Span() : trace_id_(0), name_(), id_(0), debug_(false), monotonic_start_time_(0), tracer_(nullptr) {} + + void setSampled(const bool val) { sampled_ = val; } + bool isSampled() const { return sampled_; } /** * Sets the span's trace id attribute. @@ -566,6 +569,7 @@ class Span : public ZipkinBase { std::string name_; uint64_t id_; Optional parent_id_; + bool sampled_; bool debug_; std::vector annotations_; std::vector binary_annotations_; diff --git a/zipkin/src/span_context.cc b/zipkin/src/span_context.cc index b5954e6..994598f 100644 --- a/zipkin/src/span_context.cc +++ b/zipkin/src/span_context.cc @@ -8,6 +8,11 @@ SpanContext::SpanContext(const Span &span) { trace_id_ = span.traceId(); id_ = span.id(); parent_id_ = span.isSetParentId() ? span.parentId() : 0; + + if (span.isSampled()) { + flags_ |= static_cast(zipkin::sampled_flag); + flags_ |= static_cast(zipkin::sampling_set_flag); + } for (const Annotation &annotation : span.annotations()) { if (annotation.value() == ZipkinCoreConstants::get().CLIENT_RECV) { diff --git a/zipkin_opentracing/include/zipkin/opentracing.h b/zipkin_opentracing/include/zipkin/opentracing.h index 8c869dd..fc0722c 100644 --- a/zipkin_opentracing/include/zipkin/opentracing.h +++ b/zipkin_opentracing/include/zipkin/opentracing.h @@ -8,6 +8,7 @@ struct ZipkinOtTracerOptions { uint32_t collector_port = 9411; SteadyClock::duration reporting_period = DEFAULT_REPORTING_PERIOD; size_t max_buffered_spans = DEFAULT_SPAN_BUFFER_SIZE; + float sample_rate = 1.0f; std::string service_name; IpAddress service_address; diff --git a/zipkin_opentracing/src/opentracing.cc b/zipkin_opentracing/src/opentracing.cc index 771c331..d5573e7 100644 --- a/zipkin_opentracing/src/opentracing.cc +++ b/zipkin_opentracing/src/opentracing.cc @@ -1,4 +1,5 @@ #include +#include #include "propagation.h" #include "utility.h" @@ -6,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -156,7 +158,7 @@ class OtSpan : public ot::Span { parent_span_context->baggage_mutex_}; auto baggage = parent_span_context->baggage_; span_context_ = - OtSpanContext{zipkin::SpanContext{*span_}, std::move(baggage)}; + OtSpanContext{zipkin::SpanContext{*span_}, std::move(baggage)}; } else { span_context_ = OtSpanContext{zipkin::SpanContext{*span_}}; } @@ -277,11 +279,28 @@ class OtTracer : public ot::Tracer, StartSpanWithOptions(string_view operation_name, const ot::StartSpanOptions &options) const noexcept override { + // Create the core zipkin span. SpanPtr span{new zipkin::Span{}}; span->setName(operation_name); span->setTracer(tracer_.get()); + // TODO + // * sampling rate should be arg-based + // * sampling should probably be extracted into a sampler to allow + // different strategies + // * we should be guarding this to set sampling only when its a + // root span + auto value = RandomUtil::generateId(); + auto max = std::numeric_limits::max(); + long double sampling_rate = 0.5; + auto boundary = sampling_rate * max; // be false 50% of the time + auto samplingBoundary = static_cast(boundary); + + if (value > samplingBoundary) { + span->setSampled(true); + } + Endpoint endpoint{tracer_->serviceName(), tracer_->address()}; // Add a binary annotation for the serviceName. @@ -329,7 +348,7 @@ class OtTracer : public ot::Tracer, private: TracerPtr tracer_; - + template expected InjectImpl(const ot::SpanContext &sc, Carrier &writer) const try { diff --git a/zipkin_opentracing/src/propagation.cc b/zipkin_opentracing/src/propagation.cc index 1eb5aae..df512a5 100644 --- a/zipkin_opentracing/src/propagation.cc +++ b/zipkin_opentracing/src/propagation.cc @@ -64,7 +64,7 @@ injectSpanContext(const opentracing::TextMapWriter &carrier, if (!result) { return result; } - result = carrier.Set(zipkin_sampled, "1"); + result = carrier.Set(zipkin_sampled, span_context.isSampled() ? "1" : "0"); if (!result) { return result; } @@ -105,7 +105,7 @@ extractSpanContext(const opentracing::TextMapReader &carrier, TraceId trace_id; Optional parent_id; uint64_t span_id; - flags_t flags = 0; + flags_t flags = 0; auto result = carrier.ForeachKey( [&](ot::string_view key, ot::string_view value) -> ot::expected { if (keyCompare(key, zipkin_trace_id)) { diff --git a/zipkin_opentracing/src/tracer_factory.cc b/zipkin_opentracing/src/tracer_factory.cc index 34cb39f..d028de2 100644 --- a/zipkin_opentracing/src/tracer_factory.cc +++ b/zipkin_opentracing/src/tracer_factory.cc @@ -37,6 +37,11 @@ const char *const configuration_schema = R"( "description": "The maximum number of spans to buffer before sending them to the collector", "minimum": 1 + }, + "sample_rate": { + "type": "float", + "minimum": 0.0, + "maxiumum": 1.0, } } } @@ -91,6 +96,9 @@ OtTracerFactory::MakeTracer(const char *configuration, if (document.HasMember("max_buffered_spans")) { options.max_buffered_spans = document["max_buffered_spans"].GetInt(); } + if (document.HasMember("sample_rate")) { + options.sample_rate = document["sample_rate"].GetFloat(); + } return makeZipkinOtTracer(options); } catch (const std::bad_alloc &) { return opentracing::make_unexpected(