diff --git a/README.md b/README.md index 8ce7e35..5f9c96a 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ use ZipkinTracer::RackHandler, config * `:async` - By default senders will flush traces asynchronously. Set to `false` to make that process synchronous. Only supported by the HTTP, RabbitMQ, and SQS senders. * `:logger` - The default logger for Rails apps is `Rails.logger`, else it is `STDOUT`. Use this option to pass a custom logger. * `:write_b3_single_format` - When set to true, only writes a single b3 header for outbound propagation. +* `:supports_join` - When set to false, it will force client and server spans to have different spanId's. This may be needed because zipkin traces may be reported to non-zipkin backends that might not support the concept of joining spans. #### Sender specific * `:json_api_host` - Hostname with protocol of a zipkin api instance (e.g. `https://zipkin.example.com`) to use the HTTP sender diff --git a/lib/zipkin-tracer/config.rb b/lib/zipkin-tracer/config.rb index d0a36f0..1710264 100644 --- a/lib/zipkin-tracer/config.rb +++ b/lib/zipkin-tracer/config.rb @@ -8,7 +8,7 @@ class Config attr_reader :service_name, :sample_rate, :sampled_as_boolean, :check_routes, :trace_id_128bit, :async, :logger, :json_api_host, :zookeeper, :kafka_producer, :kafka_topic, :sqs_queue_name, :sqs_region, :log_tracing, :annotate_plugin, :filter_plugin, :whitelist_plugin, :rabbit_mq_connection, :rabbit_mq_exchange, - :rabbit_mq_routing_key, :write_b3_single_format + :rabbit_mq_routing_key, :write_b3_single_format, :supports_join def initialize(app, config_hash) config = config_hash || Application.config(app) @@ -58,6 +58,10 @@ def initialize(app, config_hash) # When set to true, only writes a single b3 header for outbound propagation. @write_b3_single_format = config[:write_b3_single_format].nil? ? DEFAULTS[:write_b3_single_format] : config[:write_b3_single_format] + # When set to false, the it will force client and server spans to have different spanId's. This is important + # because zipkin traces may be reported to non-zipkin backends that might not support the concept of + # joining spans. + @supports_join = config[:supports_join].nil? ? DEFAULTS[:supports_join] : config[:supports_join] Trace.sample_rate = @sample_rate Trace.trace_id_128bit = @trace_id_128bit @@ -99,7 +103,8 @@ def domain_service_name(default_name) sampled_as_boolean: true, check_routes: false, trace_id_128bit: false, - write_b3_single_format: false + write_b3_single_format: false, + supports_join: true } def present?(str) diff --git a/lib/zipkin-tracer/rack/zipkin_env.rb b/lib/zipkin-tracer/rack/zipkin_env.rb index 5311945..6e88901 100644 --- a/lib/zipkin-tracer/rack/zipkin_env.rb +++ b/lib/zipkin-tracer/rack/zipkin_env.rb @@ -30,6 +30,10 @@ def called_with_zipkin_headers? B3_REQUIRED_HEADERS = %w[HTTP_X_B3_TRACEID HTTP_X_B3_SPANID].freeze B3_OPT_HEADERS = %w[HTTP_X_B3_PARENTSPANID HTTP_X_B3_SAMPLED HTTP_X_B3_FLAGS].freeze + def supports_join? + @config.supports_join + end + def retrieve_or_generate_ids if called_with_zipkin_b3_single_header? trace_id, span_id, parent_span_id, sampled, flags = @@ -40,6 +44,12 @@ def retrieve_or_generate_ids shared = true end + unless supports_join? + parent_span_id = span_id + span_id = TraceGenerator.new.generate_id + shared = false + end + unless trace_id span_id = TraceGenerator.new.generate_id trace_id = TraceGenerator.new.generate_id_from_span_id(span_id) diff --git a/spec/lib/config_spec.rb b/spec/lib/config_spec.rb index 4f74c4a..4d3080b 100644 --- a/spec/lib/config_spec.rb +++ b/spec/lib/config_spec.rb @@ -8,7 +8,7 @@ module ZipkinTracer [:service_name, :json_api_host, :zookeeper, :log_tracing, - :annotate_plugin, :filter_plugin, :whitelist_plugin].each do |method| + :annotate_plugin, :filter_plugin, :whitelist_plugin, :supports_join].each do |method| it "can set and read configuration values for #{method}" do value = rand(100) config = Config.new(nil, { method => value }) @@ -22,7 +22,7 @@ module ZipkinTracer it 'sets defaults' do config = Config.new(nil, {}) - [:sample_rate, :sampled_as_boolean, :check_routes, :trace_id_128bit, :write_b3_single_format].each do |key| + [:sample_rate, :sampled_as_boolean, :check_routes, :trace_id_128bit, :write_b3_single_format, :supports_join].each do |key| expect(config.send(key)).to_not eq(nil) end end diff --git a/spec/lib/rack/zipkin_env_spec.rb b/spec/lib/rack/zipkin_env_spec.rb index 671f393..aa95f25 100644 --- a/spec/lib/rack/zipkin_env_spec.rb +++ b/spec/lib/rack/zipkin_env_spec.rb @@ -19,11 +19,13 @@ def mock_env(params = {}, path = '/') whitelist_plugin: whitelist_plugin, sample_rate: sample_rate, sampled_as_boolean: sampled_as_boolean, - check_routes: check_routes + check_routes: check_routes, + supports_join: supports_join ) end let(:env) { mock_env } let(:zipkin_env) { described_class.new(env, config) } + let(:supports_join) { true } it 'allows access to the original environment' do expect(zipkin_env.env).to eq(env) @@ -188,6 +190,21 @@ def mock_env(params = {}, path = '/') it 'uses the flags' do expect(zipkin_env.trace_id.flags.to_i).to eq(0) end + + context 'supports joins is false' do + let(:supports_join) { false } + + it 'generates a new span id' do + trace_id = zipkin_env.trace_id + expect(trace_id.trace_id.to_i).to eq(id) + expect(trace_id.span_id.to_i).not_to eq(id) + expect(trace_id.parent_id.to_i).to eq(id) + end + + it 'shared is false' do + expect(zipkin_env.trace_id.shared).to eq(false) + end + end end context 'Sampled admits using 1 as well as true' do