Skip to content

Commit

Permalink
Merge pull request #660 from DataDog/feature/add_correlation_identifier
Browse files Browse the repository at this point in the history
Add correlation identifier
  • Loading branch information
delner authored Dec 19, 2018
2 parents a57074f + dc6cbdb commit a66e427
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 0 deletions.
36 changes: 36 additions & 0 deletions docs/GettingStarted.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
17 changes: 17 additions & 0 deletions lib/ddtrace/correlation.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module Datadog
# Contains behavior for managing correlations with tracing
# e.g. Retrieve a correlation to the current trace for logging, etc.
module Correlation
# Struct representing correlation
Identifier = Struct.new(:trace_id, :span_id)
NULL_IDENTIFIER = Identifier.new.freeze

module_function

# Produces a CorrelationIdentifier from the Context provided
def identifier_from_context(context)
return NULL_IDENTIFIER if context.nil?
Identifier.new(context.trace_id, context.span_id).freeze
end
end
end
6 changes: 6 additions & 0 deletions lib/ddtrace/tracer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -357,6 +358,11 @@ def active_root_span
call_context.current_root_span
end

# Return a CorrelationIdentifier for active span
def active_correlation_ids
Datadog::Correlation.identifier_from_context(call_context)
end

# Send the trace to the writer to enqueue the spans list in the agent
# sending queue.
def write(trace)
Expand Down
39 changes: 39 additions & 0 deletions spec/ddtrace/correlation_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
require 'spec_helper'

require 'ddtrace/correlation'
require 'ddtrace/context'

RSpec.describe Datadog::Correlation do
describe '::identifier_from_context' do
subject(:correlation_ids) { described_class.identifier_from_context(context) }

context 'given nil' do
let(:context) { nil }

it 'returns an empty Correlation::Identifier' do
is_expected.to be_a_kind_of(Datadog::Correlation::Identifier)
expect(correlation_ids.trace_id).to be nil
expect(correlation_ids.span_id).to be nil
end
end

context 'given a Context object' do
let(:context) do
instance_double(
Datadog::Context,
trace_id: trace_id,
span_id: span_id
)
end

let(:trace_id) { double('trace id') }
let(:span_id) { double('span id') }

it 'returns a Correlation::Identifier matching the Context' do
is_expected.to be_a_kind_of(Datadog::Correlation::Identifier)
expect(correlation_ids.trace_id).to eq(trace_id)
expect(correlation_ids.span_id).to eq(span_id)
end
end
end
end
29 changes: 29 additions & 0 deletions spec/ddtrace/tracer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit a66e427

Please sign in to comment.