diff --git a/docs/GettingStarted.md b/docs/GettingStarted.md index 2ab8796504..ad5480d910 100644 --- a/docs/GettingStarted.md +++ b/docs/GettingStarted.md @@ -62,6 +62,7 @@ For descriptions of terminology used in APM, take a look at the [official docume - [Processing pipeline](#processing-pipeline) - [Filtering](#filtering) - [Processing](#processing) + - [Trace correlation](#trace-correlation) - [OpenTracing](#opentracing) ## Compatibility @@ -1605,6 +1606,41 @@ Datadog::Pipeline.before_flush( ) ``` +### Trace correlation + +In many cases, such as logging, it may be useful to correlate trace IDs to other events or data streams, for easier cross referencing. The tracer can produce a correlation identifier for the currently active trace via `active_correlation_ids`, which can be used to decorate these other data sources. + +An example of this for the purpose of logging: + +```ruby +require 'ddtrace' +require 'logger' + +logger = Logger.new(STDOUT) +logger.progname = 'my_app' +logger.formatter = proc do |severity, datetime, progname, msg| + # Returns Datadog::Correlation::Identifier + ids = Datadog.tracer.active_correlation_ids + "[#{datetime}][#{progname}][#{severity}][dd.trace_id=#{ids.trace_id} dd.span_id=#{ids.span_id}] #{msg}\n" +end + +# When a trace is active... +Datadog.tracer.trace('logging.example') do + # And a warning is produced... + logger.warn('This is a warning.') + + # Prints: + # [2018-12-18 22:42:25 +0000][my_app][WARN][dd.trace_id=5963550561812073440 dd.span_id=2232727802607726424] This is a warning. +end + +# When no trace is active... +# And a warning is produced... +logger.warn('This is a warning.') + +# Prints: +# [2018-12-18 22:44:19 +0000][my_app][WARN][dd.trace_id= dd.span_id=] This is a warning. +``` + ### OpenTracing For setting up Datadog with OpenTracing, see out [Quickstart for OpenTracing](#quickstart-for-opentracing) section for details. diff --git a/lib/ddtrace/tracer.rb b/lib/ddtrace/tracer.rb index a7c19882aa..e001d2b152 100644 --- a/lib/ddtrace/tracer.rb +++ b/lib/ddtrace/tracer.rb @@ -10,6 +10,7 @@ require 'ddtrace/logger' require 'ddtrace/writer' require 'ddtrace/sampler' +require 'ddtrace/correlation' # \Datadog global namespace that includes all tracing functionality for Tracer and Span classes. module Datadog @@ -19,6 +20,8 @@ module Datadog # of these function calls and sub-requests would be encapsulated within a single trace. # rubocop:disable Metrics/ClassLength class Tracer + include Datadog::Correlation + attr_reader :sampler, :services, :tags, :provider attr_accessor :enabled, :writer attr_writer :default_service @@ -357,6 +360,11 @@ def active_root_span call_context.current_root_span end + # Return a CorrelationIdentifier for active span + def active_correlation_ids + correlation_ids_from_context(call_context) + end + # Send the trace to the writer to enqueue the spans list in the agent # sending queue. def write(trace) diff --git a/spec/ddtrace/tracer_spec.rb b/spec/ddtrace/tracer_spec.rb index fbc377faa9..0cc61f0aae 100644 --- a/spec/ddtrace/tracer_spec.rb +++ b/spec/ddtrace/tracer_spec.rb @@ -96,4 +96,33 @@ is_expected.to be(span) end end + + describe '#active_correlation_ids' do + subject(:active_correlation_ids) { tracer.active_correlation_ids } + + context 'when a trace is active' do + let(:span) { @span } + + around(:each) do |example| + tracer.trace('test') do |span| + @span = span + example.run + end + end + + it 'produces an Datadog::Correlation::Identifier with data' do + is_expected.to be_a_kind_of(Datadog::Correlation::Identifier) + expect(active_correlation_ids.trace_id).to eq(span.trace_id) + expect(active_correlation_ids.span_id).to eq(span.span_id) + end + end + + context 'when no trace is active' do + it 'produces an empty Datadog::Correlation::Identifier' do + is_expected.to be_a_kind_of(Datadog::Correlation::Identifier) + expect(active_correlation_ids.trace_id).to be nil + expect(active_correlation_ids.span_id).to be nil + end + end + end end