-
Notifications
You must be signed in to change notification settings - Fork 373
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[OpenTracing] Span and SpanContext implementation (#472)
* Added: Datadog::OpenTracer::SpanContext implementation. * Added: Datadog::OpenTracer::Span implementation. * Changed: Bump required Ruby version for OpenTracing to 2.1. * Added: Datadog::OpenTracer::SpanContextFactory. * Changed: OpenTracer::Span#set_baggage_item to create new SpanContexts. * Changed: Datadog::OpenTracer::SpanContext#baggage to be immutable. * Added: span_id, trace_id, parent_id to Datadog::OpenTracer::SpanContext. * Changed: Replaced span_id, trace_id, parent_id with reference to Datadog::Context.
- Loading branch information
Showing
7 changed files
with
319 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,90 @@ | ||
module Datadog | ||
module OpenTracer | ||
# OpenTracing adapter for Datadog::Span | ||
class Span < ::OpenTracing::Span | ||
attr_reader \ | ||
:datadog_span | ||
|
||
def initialize(datadog_span:, span_context:) | ||
@datadog_span = datadog_span | ||
@span_context = span_context | ||
end | ||
|
||
# Set the name of the operation | ||
# | ||
# @param [String] name | ||
def operation_name=(name) | ||
datadog_span.name = name | ||
end | ||
|
||
# Span Context | ||
# | ||
# @return [SpanContext] | ||
def context | ||
@span_context | ||
end | ||
|
||
# Set a tag value on this span | ||
# @param key [String] the key of the tag | ||
# @param value [String, Numeric, Boolean] the value of the tag. If it's not | ||
# a String, Numeric, or Boolean it will be encoded with to_s | ||
def set_tag(key, value) | ||
tap { datadog_span.set_tag(key, value) } | ||
end | ||
|
||
# Set a baggage item on the span | ||
# @param key [String] the key of the baggage item | ||
# @param value [String] the value of the baggage item | ||
def set_baggage_item(key, value) | ||
tap do | ||
# SpanContext is immutable, so to make changes | ||
# build a new span context. | ||
@span_context = SpanContextFactory.clone( | ||
span_context: context, | ||
baggage: { key => value } | ||
) | ||
end | ||
end | ||
|
||
# Get a baggage item | ||
# @param key [String] the key of the baggage item | ||
# @return [String] value of the baggage item | ||
def get_baggage_item(key) | ||
context.baggage[key] | ||
end | ||
|
||
# @deprecated Use {#log_kv} instead. | ||
# Reason: event is an optional standard log field defined in spec and not required. Also, | ||
# method name {#log_kv} is more consistent with other language implementations such as Python and Go. | ||
# | ||
# Add a log entry to this span | ||
# @param event [String] event name for the log | ||
# @param timestamp [Time] time of the log | ||
# @param fields [Hash] Additional information to log | ||
def log(event: nil, timestamp: Time.now, **fields) | ||
super # Log deprecation warning | ||
|
||
# If the fields specify an error | ||
if fields.key?(:'error.object') | ||
datadog_span.set_error(fields[:'error.object']) | ||
end | ||
end | ||
|
||
# Add a log entry to this span | ||
# @param timestamp [Time] time of the log | ||
# @param fields [Hash] Additional information to log | ||
def log_kv(timestamp: Time.now, **fields) | ||
# If the fields specify an error | ||
if fields.key?(:'error.object') | ||
datadog_span.set_error(fields[:'error.object']) | ||
end | ||
end | ||
|
||
# Finish the {Span} | ||
# @param end_time [Time] custom end time, if not now | ||
def finish(end_time: Time.now) | ||
datadog_span.finish(end_time) | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,14 @@ | ||
module Datadog | ||
module OpenTracer | ||
# OpenTracing adapter for SpanContext | ||
class SpanContext < ::OpenTracing::SpanContext | ||
attr_reader \ | ||
:datadog_context | ||
|
||
def initialize(datadog_context:, baggage: {}) | ||
@datadog_context = datadog_context | ||
@baggage = baggage.freeze | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
module Datadog | ||
module OpenTracer | ||
# Creates new Datadog::OpenTracer::SpanContext | ||
module SpanContextFactory | ||
module_function | ||
|
||
def build(datadog_context:, baggage: {}) | ||
SpanContext.new( | ||
datadog_context: datadog_context, | ||
baggage: baggage.dup | ||
) | ||
end | ||
|
||
def clone(span_context:, baggage: {}) | ||
SpanContext.new( | ||
datadog_context: span_context.datadog_context, | ||
# Merge baggage from previous SpanContext | ||
baggage: span_context.baggage.merge(baggage) | ||
) | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
require 'spec_helper' | ||
|
||
require 'ddtrace/opentracer' | ||
require 'ddtrace/opentracer/helper' | ||
|
||
if Datadog::OpenTracer.supported? | ||
RSpec.describe Datadog::OpenTracer::SpanContextFactory do | ||
include_context 'OpenTracing helpers' | ||
|
||
describe 'class methods' do | ||
describe '#build' do | ||
context 'given Datadog::Context' do | ||
subject(:span_context) do | ||
described_class.build( | ||
datadog_context: datadog_context | ||
) | ||
end | ||
let(:datadog_context) { instance_double(Datadog::Context) } | ||
|
||
it { is_expected.to be_a_kind_of(Datadog::OpenTracer::SpanContext) } | ||
|
||
describe 'builds a SpanContext where' do | ||
it { expect(span_context.datadog_context).to be(datadog_context) } | ||
|
||
describe '#baggage' do | ||
subject(:baggage) { span_context.baggage } | ||
it { is_expected.to be_a_kind_of(Hash) } | ||
it { is_expected.to be_empty } | ||
end | ||
end | ||
|
||
context 'and baggage' do | ||
subject(:span_context) do | ||
described_class.build( | ||
datadog_context: datadog_context, | ||
baggage: original_baggage | ||
) | ||
end | ||
let(:original_baggage) { { 'account_id' => '1234' } } | ||
|
||
it { is_expected.to be_a_kind_of(Datadog::OpenTracer::SpanContext) } | ||
|
||
describe 'builds a SpanContext where' do | ||
it { expect(span_context.datadog_context).to be(datadog_context) } | ||
|
||
describe '#baggage' do | ||
subject(:baggage) { span_context.baggage } | ||
it { is_expected.to be_a_kind_of(Hash) } | ||
|
||
context 'when the original baggage contains data' do | ||
it { is_expected.to include('account_id' => '1234') } | ||
it { is_expected.to_not be(original_baggage) } | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end | ||
|
||
describe '#clone' do | ||
context 'given a SpanContext' do | ||
subject(:span_context) { described_class.clone(span_context: original_span_context) } | ||
let(:original_span_context) do | ||
instance_double( | ||
Datadog::OpenTracer::SpanContext, | ||
datadog_context: original_datadog_context, | ||
baggage: original_baggage | ||
) | ||
end | ||
let(:original_datadog_context) { instance_double(Datadog::Context) } | ||
let(:original_baggage) { {} } | ||
|
||
it { is_expected.to be_a_kind_of(Datadog::OpenTracer::SpanContext) } | ||
|
||
describe 'builds a SpanContext where' do | ||
it { expect(span_context.datadog_context).to be(original_datadog_context) } | ||
|
||
describe '#baggage' do | ||
subject(:baggage) { span_context.baggage } | ||
it { is_expected.to be_a_kind_of(Hash) } | ||
|
||
context 'when the original SpanContext contains baggage' do | ||
let(:original_baggage) { { 'org_id' => '4321' } } | ||
it { is_expected.to include('org_id' => '4321') } | ||
it { is_expected.to_not be(original_baggage) } | ||
end | ||
end | ||
end | ||
|
||
context 'and baggage' do | ||
subject(:span_context) { described_class.clone(span_context: original_span_context, baggage: param_baggage) } | ||
let(:param_baggage) { {} } | ||
|
||
it { is_expected.to be_a_kind_of(Datadog::OpenTracer::SpanContext) } | ||
|
||
describe 'builds a SpanContext where' do | ||
describe '#baggage' do | ||
subject(:baggage) { span_context.baggage } | ||
it { is_expected.to be_a_kind_of(Hash) } | ||
|
||
context 'when the original SpanContext contains baggage' do | ||
let(:original_baggage) { { 'org_id' => '4321' } } | ||
it { is_expected.to include('org_id' => '4321') } | ||
it { is_expected.to_not be(original_baggage) } | ||
end | ||
|
||
context 'when the original baggage contains data' do | ||
let(:param_baggage) { { 'account_id' => '1234' } } | ||
it { is_expected.to include('account_id' => '1234') } | ||
it { is_expected.to_not be(param_baggage) } | ||
end | ||
|
||
context 'when the original SpanContext baggage and param baggage contains data' do | ||
context 'that doesn\'t overlap' do | ||
let(:original_baggage) { { 'org_id' => '4321' } } | ||
let(:param_baggage) { { 'account_id' => '1234' } } | ||
it { is_expected.to include('org_id' => '4321', 'account_id' => '1234') } | ||
it { is_expected.to_not be(original_baggage) } | ||
it { is_expected.to_not be(param_baggage) } | ||
end | ||
|
||
context 'that overlaps' do | ||
let(:original_baggage) { { 'org_id' => '4321' } } | ||
let(:param_baggage) { { 'org_id' => '1234' } } | ||
it { is_expected.to include('org_id' => '1234') } | ||
it { is_expected.to_not be(original_baggage) } | ||
it { is_expected.to_not be(param_baggage) } | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.