From be2749ac859f0353c21bceacce1865b35e55d356 Mon Sep 17 00:00:00 2001 From: Munir Abdinur Date: Wed, 10 Jul 2024 15:53:08 -0400 Subject: [PATCH] feat(otel): support span events --- .../opentelemetry/sdk/span_processor.rb | 10 ++++++ lib/datadog/tracing/span.rb | 9 +++-- lib/datadog/tracing/span_operation.rb | 5 ++- .../tracing/transport/serializable_trace.rb | 3 ++ spec/datadog/opentelemetry_spec.rb | 35 +++++++++++++++++++ 5 files changed, 59 insertions(+), 3 deletions(-) diff --git a/lib/datadog/opentelemetry/sdk/span_processor.rb b/lib/datadog/opentelemetry/sdk/span_processor.rb index 65af6e621da..901bf2b8fc8 100644 --- a/lib/datadog/opentelemetry/sdk/span_processor.rb +++ b/lib/datadog/opentelemetry/sdk/span_processor.rb @@ -2,6 +2,7 @@ require_relative 'trace/span' require_relative '../../tracing/span_link' +require_relative '../../tracing/span_event' require_relative '../../tracing/trace_digest' module Datadog @@ -31,6 +32,15 @@ def on_start(span, parent_context) # # @param [Span] span the {Span} that just ended. def on_finish(span) + unless span.events.nil? + span.datadog_span.span_events = span.events.map do |event| + Datadog::Tracing::SpanEvent.new( + event.name, + attributes: event.attributes, + time_unix_nano: event.timestamp + ) + end + end span.datadog_span.finish(ns_to_time(span.end_timestamp)) end diff --git a/lib/datadog/tracing/span.rb b/lib/datadog/tracing/span.rb index 57f156dcef1..507469fed64 100644 --- a/lib/datadog/tracing/span.rb +++ b/lib/datadog/tracing/span.rb @@ -27,6 +27,7 @@ class Span :resource, :service, :links, + :events, :type, :start_time, :status, @@ -60,7 +61,8 @@ def initialize( type: nil, trace_id: nil, service_entry: nil, - links: nil + links: nil, + events: nil ) @name = Core::Utils::SafeDup.frozen_or_dup(name) @service = Core::Utils::SafeDup.frozen_or_dup(service) @@ -90,6 +92,8 @@ def initialize( @links = links || [] + @events = events || [] + # Mark with the service entry span metric, if applicable set_metric(Metadata::Ext::TAG_TOP_LEVEL, 1.0) if service_entry end @@ -141,7 +145,8 @@ def to_hash span_id: @id, trace_id: @trace_id, type: @type, - span_links: @links.map(&:to_hash) + span_links: @links.map(&:to_hash), + events: @events.map(&:to_hash) } if stopped? diff --git a/lib/datadog/tracing/span_operation.rb b/lib/datadog/tracing/span_operation.rb index 84052145095..fce4d8b8c05 100644 --- a/lib/datadog/tracing/span_operation.rb +++ b/lib/datadog/tracing/span_operation.rb @@ -35,7 +35,7 @@ class SpanOperation :start_time, :trace_id, :type - attr_accessor :links, :status + attr_accessor :links, :status, :span_events def initialize( name, @@ -49,6 +49,7 @@ def initialize( trace_id: nil, type: nil, links: nil, + span_events: nil, id: nil ) # Ensure dynamically created strings are UTF-8 encoded. @@ -68,6 +69,7 @@ def initialize( @status = 0 # stores array of span links @links = links || [] + @span_events = span_events || [] # start_time and end_time track wall clock. In Ruby, wall clock # has less accuracy than monotonic clock, so if possible we look to only use wall clock @@ -455,6 +457,7 @@ def build_span type: @type, trace_id: @trace_id, links: @links, + events: @span_events, service_entry: parent.nil? || (service && parent.service != service) ) end diff --git a/lib/datadog/tracing/transport/serializable_trace.rb b/lib/datadog/tracing/transport/serializable_trace.rb index b056af71c2a..aedae953a91 100644 --- a/lib/datadog/tracing/transport/serializable_trace.rb +++ b/lib/datadog/tracing/transport/serializable_trace.rb @@ -72,6 +72,9 @@ def to_msgpack(packer = nil) packer.write_map_header(number_of_elements_to_write) # Set header with how many elements in the map end + # convert span events to tags + # span.set_tag('events', span.events.map(&:to_hash).to_json) if span.events + # DEV: We use strings as keys here, instead of symbols, as # DEV: MessagePack will ultimately convert them to strings. # DEV: By providing strings directly, we skip this indirection operation. diff --git a/spec/datadog/opentelemetry_spec.rb b/spec/datadog/opentelemetry_spec.rb index 0e0cfaa3286..5016b62817d 100644 --- a/spec/datadog/opentelemetry_spec.rb +++ b/spec/datadog/opentelemetry_spec.rb @@ -626,6 +626,41 @@ end end + describe '#add_event' do + subject! do + start_span + start_span.add_event('Exception was raised!', **event_options) + start_span.finish + end + + let(:start_span) { otel_tracer.start_span('start-span', **span_options) } + let(:active_span) { Datadog::Tracing.active_span } + + context 'with name, attributes and timestamp' do + let(:event_options) do + { attributes: { 'raised' => false, 'handler' => 'default', 'count' => 1 }, timestamp: 17206369349 } + end + + it 'adds one event to the span' do + expect(span.events.count).to eq(1) + expect(span.events[0].name).to eq('Exception was raised!') + expect(span.events[0].time_unix_nano).to eq(17206369349000000000) + expect(span.events[0].attributes).to eq({ 'raised' => 'false', 'handler' => 'default', 'count' => '1' }) + end + end + + context 'without a timestamp or attributes' do + let(:event_options) { {} } + + it 'adds one event with timestamp set to the current time and attributes set to an empty hash' do + expect(span.events.count).to eq(1) + expect(span.events[0].name).to eq('Exception was raised!') + expect(span.events[0].time_unix_nano / 1e9).to be_within(1).of(Time.now.to_f) + expect(span.events[0].attributes).to eq({}) + end + end + end + describe '#status=' do subject! do start_span