Skip to content

Commit 33a7fc9

Browse files
committed
Serialize span events via a dedicated field
1 parent 3dddec7 commit 33a7fc9

File tree

19 files changed

+271
-47
lines changed

19 files changed

+271
-47
lines changed

Diff for: .github/forced-tests-list.json

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
11
{
2-
2+
"DEFAULT":
3+
[
4+
"tests/test_span_events.py::Test_SpanEvents_WithAgentSupport::test_v04_v07_default_format"
5+
],
6+
"AGENT_NOT_SUPPORTING_SPAN_EVENTS":
7+
[
8+
"tests/test_span_events.py"
9+
],
10+
"PARAMETRIC":
11+
[
12+
"tests/parametric/test_span_events.py"
13+
]
314
}

Diff for: Steepfile

-2
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,8 @@ target :datadog do
137137
ignore 'lib/datadog/tracing/transport/http/traces.rb'
138138
ignore 'lib/datadog/tracing/transport/io/client.rb'
139139
ignore 'lib/datadog/tracing/transport/io/traces.rb'
140-
ignore 'lib/datadog/tracing/transport/serializable_trace.rb'
141140
ignore 'lib/datadog/tracing/transport/statistics.rb'
142141
ignore 'lib/datadog/tracing/transport/trace_formatter.rb'
143-
ignore 'lib/datadog/tracing/transport/traces.rb'
144142
ignore 'lib/datadog/tracing/workers.rb'
145143
ignore 'lib/datadog/tracing/workers/trace_writer.rb'
146144
ignore 'lib/datadog/tracing/writer.rb'

Diff for: lib/datadog/core/configuration/components.rb

+7-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
require_relative '../../di/component'
1717
require_relative '../crashtracking/component'
1818

19+
require_relative '../environment/agent_info'
20+
1921
module Datadog
2022
module Core
2123
module Configuration
@@ -85,7 +87,8 @@ def build_crashtracker(settings, agent_settings, logger:)
8587
:tracer,
8688
:crashtracker,
8789
:dynamic_instrumentation,
88-
:appsec
90+
:appsec,
91+
:agent_info
8992

9093
def initialize(settings)
9194
@logger = self.class.build_logger(settings)
@@ -96,6 +99,9 @@ def initialize(settings)
9699
# the Core resolver from within your product/component's namespace.
97100
agent_settings = AgentSettingsResolver.call(settings, logger: @logger)
98101

102+
# Exposes agent capability information for detection by any components
103+
@agent_info = Core::Environment::AgentInfo.new(agent_settings)
104+
99105
@telemetry = self.class.build_telemetry(settings, agent_settings, @logger)
100106

101107
@remote = Remote::Component.build(settings, agent_settings, telemetry: telemetry)

Diff for: lib/datadog/core/encoding.rb

+16
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ module Encoding
1010
# Encoder interface that provides the logic to encode traces and service
1111
# @abstract
1212
module Encoder
13+
# :nocov:
1314
def content_type
1415
raise NotImplementedError
1516
end
@@ -23,6 +24,13 @@ def join(encoded_elements)
2324
def encode(_)
2425
raise NotImplementedError
2526
end
27+
28+
# Deserializes a value serialized with {#encode}.
29+
# This method is used for debugging purposes.
30+
def decode(_)
31+
raise NotImplementedError
32+
end
33+
# :nocov:
2634
end
2735

2836
# Encoder for the JSON format
@@ -41,6 +49,10 @@ def encode(obj)
4149
JSON.dump(obj)
4250
end
4351

52+
def decode(obj)
53+
JSON.parse(obj)
54+
end
55+
4456
def join(encoded_data)
4557
"[#{encoded_data.join(',')}]"
4658
end
@@ -62,6 +74,10 @@ def encode(obj)
6274
MessagePack.pack(obj)
6375
end
6476

77+
def decode(obj)
78+
MessagePack.unpack(obj)
79+
end
80+
6581
def join(encoded_data)
6682
packer = MessagePack::Packer.new
6783
packer.write_array_header(encoded_data.size)

Diff for: lib/datadog/core/remote/transport/http/negotiation.rb

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ def initialize(http_response, options = {})
4343
@version = options[:version]
4444
@endpoints = options[:endpoints]
4545
@config = options[:config]
46+
@span_events = options[:span_events]
4647
end
4748
end
4849

Diff for: lib/datadog/core/remote/transport/negotiation.rb

+13-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,19 @@ class Request < Datadog::Core::Transport::Request
3232

3333
# Negotiation response
3434
module Response
35-
attr_reader :version, :endpoints, :config
35+
# @!attribute [r] version
36+
# The version of the agent.
37+
# @return [String]
38+
# @!attribute [r] endpoints
39+
# The HTTP endpoints the agent supports.
40+
# @return [Array<String>]
41+
# @!attribute [r] config
42+
# The agent configuration. These are configured by the user when starting the agent, as well as any defaults.
43+
# @return [Hash]
44+
# @!attribute [r] span_events
45+
# Whether the agent supports the top-level span events field in flushed spans.
46+
# @return [Boolean,nil]
47+
attr_reader :version, :endpoints, :config, :span_events
3648
end
3749

3850
# Negotiation transport

Diff for: lib/datadog/tracing/transport/serializable_trace.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class SerializableTrace
1414

1515
# @param trace [Datadog::Trace] the trace to serialize
1616
# @param native_events_supported [Boolean] whether the agent supports span events as a top-level field
17-
def initialize(trace, native_events_supported = false)
17+
def initialize(trace, native_events_supported)
1818
@trace = trace
1919
@native_events_supported = native_events_supported
2020
end

Diff for: lib/datadog/tracing/transport/traces.rb

+22-8
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,9 @@ class Chunker
5050
#
5151
# @param encoder [Datadog::Core::Encoding::Encoder]
5252
# @param max_size [String] maximum acceptable payload size
53-
def initialize(encoder, max_size: DEFAULT_MAX_PAYLOAD_SIZE)
53+
def initialize(encoder, native_events_supported, max_size: DEFAULT_MAX_PAYLOAD_SIZE)
5454
@encoder = encoder
55+
@native_events_supported = native_events_supported
5556
@max_size = max_size
5657
end
5758

@@ -77,7 +78,7 @@ def encode_in_chunks(traces)
7778
private
7879

7980
def encode_one(trace)
80-
encoded = Encoder.encode_trace(encoder, trace)
81+
encoded = Encoder.encode_trace(encoder, trace, @native_events_supported)
8182

8283
if encoded.size > max_size
8384
# This single trace is too large, we can't flush it
@@ -95,17 +96,18 @@ def encode_one(trace)
9596
module Encoder
9697
module_function
9798

98-
def encode_trace(encoder, trace)
99+
def encode_trace(encoder, trace, native_events_supported)
99100
# Format the trace for transport
100101
TraceFormatter.format!(trace)
101102

102103
# Make the trace serializable
103-
serializable_trace = SerializableTrace.new(trace)
104-
105-
Datadog.logger.debug { "Flushing trace: #{JSON.dump(serializable_trace)}" }
104+
serializable_trace = SerializableTrace.new(trace, native_events_supported)
106105

107106
# Encode the trace
108-
encoder.encode(serializable_trace)
107+
encoder.encode(serializable_trace).tap do |encoded|
108+
# Print the actual serialized trace, since the encoder can change make non-trivial changes
109+
Datadog.logger.debug { "Flushing trace: #{encoder.decode(encoded)}" }
110+
end
109111
end
110112
end
111113

@@ -126,7 +128,7 @@ def initialize(apis, default_api)
126128

127129
def send_traces(traces)
128130
encoder = current_api.encoder
129-
chunker = Datadog::Tracing::Transport::Traces::Chunker.new(encoder)
131+
chunker = Datadog::Tracing::Transport::Traces::Chunker.new(encoder, native_events_supported?)
130132

131133
responses = chunker.encode_in_chunks(traces.lazy).map do |encoded_traces, trace_count|
132134
request = Request.new(EncodedParcel.new(encoded_traces, trace_count))
@@ -188,6 +190,18 @@ def change_api!(api_id)
188190
@client = HTTP::Client.new(current_api)
189191
end
190192

193+
# Queries the agent for native span events serialization support.
194+
# This changes how the serialization of span events performed.
195+
def native_events_supported?
196+
return @native_events_supported if defined?(@native_events_supported)
197+
198+
if (res = Datadog.send(:components).agent_info.fetch)
199+
@native_events_supported = res.span_events == true
200+
else
201+
false
202+
end
203+
end
204+
191205
# Raised when configured with an unknown API version
192206
class UnknownApiVersionError < StandardError
193207
attr_reader :version

Diff for: sig/datadog/core/configuration/components.rbs

+2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ module Datadog
3636

3737
attr_reader remote: Datadog::Core::Remote::Component
3838

39+
attr_reader agent_info: Datadog::Core::Environment::AgentInfo
40+
3941
def initialize: (untyped settings) -> untyped
4042

4143
def startup!: (untyped settings) -> untyped

Diff for: sig/datadog/core/encoding.rbs

+17-13
Original file line numberDiff line numberDiff line change
@@ -5,39 +5,43 @@ module Datadog
55
# Encoder interface that provides the logic to encode traces and service
66
# @abstract
77
module Encoder
8-
def content_type: () -> untyped
8+
def content_type: () -> String
99

10-
# Concatenates a list of elements previously encoded by +#encode+.
11-
def join: (untyped encoded_elements) -> untyped
10+
def encode: (untyped obj) -> String
1211

13-
# Serializes a single trace into a String suitable for network transmission.
14-
def encode: (untyped _) -> untyped
12+
def join: (Array[untyped] encoded_data) -> String
13+
14+
def decode: (String obj)-> untyped
1515
end
1616

1717
# Encoder for the JSON format
1818
module JSONEncoder
1919
extend Encoder
2020

21-
CONTENT_TYPE: "application/json"
21+
CONTENT_TYPE: String
22+
23+
def self?.content_type: () -> String
2224

23-
def self?.content_type: () -> untyped
25+
def self?.encode: (untyped obj) -> String
2426

25-
def self?.encode: (untyped obj) -> untyped
27+
def self?.join: (Array[untyped] encoded_data) -> String
2628

27-
def self?.join: (untyped encoded_data) -> ::String
29+
def self?.decode: (String obj)-> untyped
2830
end
2931

3032
# Encoder for the Msgpack format
3133
module MsgpackEncoder
3234
extend Encoder
3335

34-
CONTENT_TYPE: "application/msgpack"
36+
CONTENT_TYPE: String
37+
38+
def self?.content_type: () -> String
3539

36-
def self?.content_type: () -> untyped
40+
def self?.encode: (untyped obj) -> String
3741

38-
def self?.encode: (untyped obj) -> untyped
42+
def self?.join: (Array[untyped] encoded_data) -> String
3943

40-
def self?.join: (untyped encoded_data) -> untyped
44+
def self?.decode: (String obj)-> untyped
4145
end
4246
end
4347
end

Diff for: sig/datadog/core/remote/transport/negotiation.rbs

+8-4
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ module Datadog
77
end
88

99
module Response
10-
attr_reader version: untyped
10+
attr_reader version: String
1111

12-
attr_reader endpoints: untyped
12+
attr_reader endpoints: Array[String]
1313

14-
attr_reader config: untyped
14+
attr_reader config: Hash[String,untyped]
15+
16+
attr_reader span_events: bool
1517
end
1618

1719
class Transport
@@ -25,7 +27,9 @@ module Datadog
2527

2628
def initialize: (untyped apis, untyped default_api) -> void
2729

28-
def send_info: () -> untyped
30+
type send_info_return = HTTP::Negotiation::Response & Core::Transport::InternalErrorResponse
31+
32+
def send_info: () -> send_info_return
2933

3034
def current_api: () -> untyped
3135
end

Diff for: sig/datadog/core/transport/response.rbs

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ module Datadog
2222
class InternalErrorResponse
2323
include Response
2424

25-
attr_reader error: untyped
25+
attr_reader error: Exception
2626

2727
def initialize: (untyped error) -> void
2828

Diff for: sig/datadog/tracing/transport/serializable_trace.rbs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ module Datadog
44
class SerializableTrace
55
@native_events_supported: bool
66

7-
attr_reader trace: Span
7+
attr_reader trace: TraceSegment
88

99
def initialize: (untyped trace, bool native_events_supported) -> void
1010

Diff for: sig/datadog/tracing/transport/traces.rbs

+7-3
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ module Datadog
2828

2929
attr_reader max_size: untyped
3030

31-
def initialize: (untyped encoder, ?max_size: untyped) -> void
31+
def initialize: (untyped encoder, bool native_events_supported, ?max_size: untyped) -> void
3232

3333
def encode_in_chunks: (untyped traces) -> untyped
3434

@@ -38,10 +38,12 @@ module Datadog
3838
end
3939

4040
module Encoder
41-
def self?.encode_trace: (untyped encoder, untyped trace) -> untyped
41+
def self?.encode_trace: (untyped encoder, untyped trace, bool native_events_supported) -> untyped
4242
end
4343

4444
class Transport
45+
@native_events_supported: bool
46+
4547
attr_reader client: untyped
4648

4749
attr_reader apis: untyped
@@ -52,7 +54,7 @@ module Datadog
5254

5355
def initialize: (untyped apis, untyped default_api) -> void
5456

55-
def send_traces: (untyped traces) -> untyped
57+
def send_traces: (Array[Tracing::TraceOperation] traces) -> untyped
5658

5759
def stats: () -> untyped
5860

@@ -81,6 +83,8 @@ module Datadog
8183

8284
def message: () -> ::String
8385
end
86+
87+
def native_events_supported?: -> bool
8488
end
8589
end
8690
end

Diff for: spec/datadog/core/configuration/components_spec.rb

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
let(:logger) { instance_double(Datadog::Core::Logger) }
3232
let(:settings) { Datadog::Core::Configuration::Settings.new }
3333
let(:agent_settings) { Datadog::Core::Configuration::AgentSettingsResolver.call(settings, logger: nil) }
34+
let(:agent_info) { Datadog::Core::Environment::AgentInfo.new(agent_settings) }
3435

3536
let(:profiler_setup_task) { Datadog::Profiling.supported? ? instance_double(Datadog::Profiling::Tasks::Setup) : nil }
3637
let(:remote) { instance_double(Datadog::Core::Remote::Component, start: nil, shutdown!: nil) }
@@ -95,6 +96,7 @@
9596
expect(components.profiler).to be profiler
9697
expect(components.runtime_metrics).to be runtime_metrics
9798
expect(components.health_metrics).to be health_metrics
99+
expect(components.agent_info).to eq agent_info
98100
end
99101

100102
describe '@environment_logger_extra' do

0 commit comments

Comments
 (0)