Skip to content

Commit 1fe22fc

Browse files
committed
Add MetaspanTagging module and Metastruct data class
1 parent 11f47ce commit 1fe22fc

25 files changed

+144
-223
lines changed

Diff for: lib/datadog/tracing/metadata.rb

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
require_relative 'metadata/analytics'
44
require_relative 'metadata/tagging'
5-
require_relative 'metadata/metastruct'
5+
require_relative 'metadata/metastruct_tagging'
66
require_relative 'metadata/errors'
77

88
module Datadog
@@ -11,6 +11,7 @@ module Tracing
1111
module Metadata
1212
def self.included(base)
1313
base.include(Metadata::Tagging)
14+
base.include(Metadata::MetastructTagging)
1415
base.include(Metadata::Errors)
1516

1617
# Additional extensions

Diff for: lib/datadog/tracing/metadata/metastruct.rb

+12-40
Original file line numberDiff line numberDiff line change
@@ -5,59 +5,31 @@
55
module Datadog
66
module Tracing
77
module Metadata
8-
# Adds complex structures tagging behavior through metastruct
8+
# This class is a data structure that is used to store
9+
# complex metadata, such as an array of objects.
10+
#
11+
# It is serialized to MessagePack format when sent to the agent.
912
class Metastruct
1013
extend Forwardable
1114

12-
MERGER = proc do |_, v1, v2|
13-
if v1.is_a?(Hash) && v2.is_a?(Hash)
14-
v1.merge(v2, &MERGER)
15-
elsif v1.is_a?(Array) && v2.is_a?(Array)
16-
v1.concat(v2)
17-
elsif v2.nil?
18-
v1
19-
else
20-
v2
21-
end
22-
end
15+
def_delegators :@metastruct, :[], :[]=
2316

24-
def self.empty
25-
new({})
17+
def initialize
18+
@metastruct = {}
2619
end
2720

28-
def initialize(metastruct)
29-
@metastruct = metastruct
30-
end
21+
def to_msgpack(packer = nil)
22+
# JRuby doesn't pass the packer
23+
packer ||= MessagePack::Packer.new
3124

32-
# Deep merge two metastructs
33-
# If the types are not both Arrays or Hashes, the second one will overwrite the first one
34-
#
35-
# Example with same types:
36-
# metastruct = { a: { b: [1, 2] } }
37-
# second = { a: { b: [3, 4], c: 5 } }
38-
# result = { a: { b: [1, 2, 3, 4], c: 5 } }
39-
#
40-
# Example with different types:
41-
# metastruct = { a: { b: 1 } }
42-
# second = { a: { b: [2, 3] } }
43-
# result = { a: { b: [2, 3] } }
44-
def deep_merge!(second)
45-
@metastruct.merge!(second.to_h, &MERGER)
25+
packer.write(@metastruct.transform_values(&:to_msgpack))
4626
end
4727

48-
def_delegators :@metastruct, :[], :[]=, :dig, :to_h
49-
5028
def pretty_print(q)
5129
q.seplist @metastruct.each do |key, value|
52-
q.text "#{key} => #{value}\n"
30+
q.text "#{key} => #{value}"
5331
end
5432
end
55-
56-
def to_msgpack(packer = nil)
57-
packer ||= MessagePack::Packer.new
58-
59-
packer.write(@metastruct.transform_values(&:to_msgpack))
60-
end
6133
end
6234
end
6335
end

Diff for: lib/datadog/tracing/metadata/metastruct_tagging.rb

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# frozen_string_literal: true
2+
3+
require_relative 'metastruct'
4+
5+
module Datadog
6+
module Tracing
7+
module Metadata
8+
# Adds data storage for the `meta_struct` field.
9+
#
10+
# This field is used to send more complex data like an array of objects
11+
# in MessagePack format to the agent, and has no size limitations.
12+
#
13+
# The agent fully supports meta_struct from version v7.35.0 (April 2022).
14+
#
15+
# On versions older than v7.35.0, sending traces containing meta_struct
16+
# has no unexpected side-effects; traces are sent to the backend as expected,
17+
# while the meta_struct field is stripped.
18+
module MetastructTagging
19+
# Set the given key / value tag pair on the metastruct.
20+
#
21+
# A valid example is:
22+
#
23+
# span.set_metastruct_tag('_dd.stack', [])
24+
def set_metastruct_tag(key, value)
25+
metastruct[key] = value
26+
end
27+
28+
# Return the metastruct tag value for the given key,
29+
# returns nil if the key doesn't exist.
30+
def get_metastruct_tag(key)
31+
metastruct[key]
32+
end
33+
34+
private
35+
36+
def metastruct
37+
@metastruct ||= Metastruct.new
38+
end
39+
end
40+
end
41+
end
42+
end

Diff for: lib/datadog/tracing/span.rb

+8-7
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ class Span
2121
:end_time,
2222
:id,
2323
:meta,
24-
:metastruct,
2524
:metrics,
2625
:name,
2726
:parent_id,
@@ -34,6 +33,9 @@ class Span
3433
:status,
3534
:trace_id
3635

36+
attr_reader \
37+
:metastruct
38+
3739
attr_writer \
3840
:duration
3941

@@ -54,8 +56,8 @@ def initialize(
5456
end_time: nil,
5557
id: nil,
5658
meta: nil,
57-
metastruct: {},
5859
metrics: nil,
60+
metastruct: nil,
5961
parent_id: 0,
6062
resource: name,
6163
service: nil,
@@ -77,8 +79,8 @@ def initialize(
7779
@trace_id = trace_id || Tracing::Utils.next_id
7880

7981
@meta = meta || {}
80-
@metastruct = Tracing::Metadata::Metastruct.new(metastruct)
8182
@metrics = metrics || {}
83+
@metastruct = metastruct || {}
8284
@status = status || 0
8385

8486
# start_time and end_time track wall clock. In Ruby, wall clock
@@ -147,7 +149,7 @@ def to_hash
147149
error: @status,
148150
meta: @meta,
149151
metrics: @metrics,
150-
meta_struct: @metastruct.to_h,
152+
meta_struct: @metastruct,
151153
name: @name,
152154
parent_id: @parent_id,
153155
resource: @resource,
@@ -195,9 +197,8 @@ def pretty_print(q)
195197
q.text "#{key} => #{value}"
196198
end
197199
end
198-
q.group(2, 'Metastruct: ') do
199-
q.breakable
200-
q.pp metastruct
200+
q.group(2, 'Metastruct: [', ']') do
201+
metastruct.pretty_print(q)
201202
end
202203
end
203204
end

Diff for: lib/datadog/tracing/span_operation.rb

+5-8
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,7 @@ class SpanOperation
3636
:service,
3737
:start_time,
3838
:trace_id,
39-
:type,
40-
:metastruct
39+
:type
4140
attr_accessor :links, :status, :span_events
4241

4342
def initialize(
@@ -89,7 +88,6 @@ def initialize(
8988

9089
# Set tags if provided.
9190
set_tags(tags) if tags
92-
@metastruct = Tracing::Metadata::Metastruct.empty
9391

9492
# Some other SpanOperation-specific behavior
9593
@events = events || Events.new
@@ -291,7 +289,7 @@ def to_hash
291289
id: @id,
292290
meta: meta,
293291
metrics: metrics,
294-
metastruct: @metastruct.to_h,
292+
metastruct: metastruct,
295293
name: @name,
296294
parent_id: @parent_id,
297295
resource: @resource,
@@ -337,9 +335,8 @@ def pretty_print(q)
337335
q.text "#{key} => #{value}"
338336
end
339337
end
340-
q.group(2, 'Metastruct: ') do
341-
q.breakable
342-
q.pp metastruct
338+
q.group(2, 'Metastruct: [', ']') do
339+
metastruct.pretty_print(q)
343340
end
344341
end
345342
end
@@ -463,7 +460,7 @@ def build_span
463460
id: @id,
464461
meta: Core::Utils::SafeDup.frozen_or_dup(meta),
465462
metrics: Core::Utils::SafeDup.frozen_or_dup(metrics),
466-
metastruct: @metastruct.to_h.dup,
463+
metastruct: Core::Utils::SafeDup.frozen_or_dup(metastruct),
467464
parent_id: @parent_id,
468465
resource: @resource,
469466
service: @service,

Diff for: lib/datadog/tracing/trace_operation.rb

+3-8
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
require_relative '../core/utils'
55
require_relative 'tracer'
66
require_relative 'event'
7-
require_relative 'metadata'
7+
require_relative 'metadata/tagging'
88
require_relative 'sampling/ext'
99
require_relative 'span_operation'
1010
require_relative 'trace_digest'
@@ -25,7 +25,7 @@ module Tracing
2525
#
2626
# @public_api
2727
class TraceOperation
28-
include Metadata
28+
include Metadata::Tagging
2929

3030
DEFAULT_MAX_LENGTH = 100_000
3131

@@ -46,8 +46,7 @@ class TraceOperation
4646
:max_length,
4747
:parent_span_id,
4848
:trace_state,
49-
:trace_state_unknown_fields,
50-
:metastruct
49+
:trace_state_unknown_fields
5150

5251
attr_writer \
5352
:name,
@@ -74,7 +73,6 @@ def initialize(
7473
profiling_enabled: nil,
7574
tags: nil,
7675
metrics: nil,
77-
metastruct: {},
7876
trace_state: nil,
7977
trace_state_unknown_fields: nil,
8078
remote_parent: false,
@@ -107,7 +105,6 @@ def initialize(
107105
# Generic tags
108106
set_tags(tags) if tags
109107
set_tags(metrics) if metrics
110-
@metastruct = Tracing::Metadata::Metastruct.new(metastruct)
111108

112109
# State
113110
@root_span = nil
@@ -372,7 +369,6 @@ def fork_clone
372369
trace_state_unknown_fields: (@trace_state_unknown_fields && @trace_state_unknown_fields.dup),
373370
tags: meta.dup,
374371
metrics: metrics.dup,
375-
metastruct: @metastruct.to_h.dup,
376372
remote_parent: @remote_parent
377373
)
378374
end
@@ -512,7 +508,6 @@ def build_trace(spans, partial = false)
512508
service: service,
513509
tags: meta,
514510
metrics: metrics,
515-
metastruct: @metastruct.to_h.dup,
516511
root_span_id: !partial ? root_span && root_span.id : nil,
517512
profiling_enabled: @profiling_enabled,
518513
)

Diff for: lib/datadog/tracing/trace_segment.rb

+1-4
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ def initialize(
5858
service: nil,
5959
tags: nil,
6060
metrics: nil,
61-
metastruct: {},
6261
profiling_enabled: nil
6362
)
6463
@id = id
@@ -69,7 +68,6 @@ def initialize(
6968
# The caller is expected to have done that
7069
@meta = (tags && tags.dup) || {}
7170
@metrics = (metrics && metrics.dup) || {}
72-
@metastruct = Tracing::Metadata::Metastruct.new(metastruct)
7371

7472
# Set well-known tags, defaulting to getting the values from tags
7573
@agent_sample_rate = agent_sample_rate || agent_sample_rate_tag
@@ -148,8 +146,7 @@ def high_order_tid
148146
attr_reader \
149147
:root_span_id,
150148
:meta,
151-
:metrics,
152-
:metastruct
149+
:metrics
153150

154151
private
155152

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

-1
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,6 @@ def to_msgpack(packer = nil)
118118
packer.write('metrics')
119119
packer.write(span.metrics)
120120
packer.write('meta_struct')
121-
# We encapsulate the resulting msgpack in a binary msgpack
122121
packer.write(span.metastruct)
123122
packer.write('span_links')
124123
packer.write(span.links.map(&:to_hash))

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

-7
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ def format!
4343
# Apply generic trace tags. Any more specific value will be overridden
4444
# by the subsequent calls below.
4545
set_trace_tags!
46-
set_metastruct!
4746

4847
set_resource!
4948

@@ -90,12 +89,6 @@ def set_trace_tags!
9089
root_span.set_tags(trace.send(:metrics))
9190
end
9291

93-
def set_metastruct!
94-
return if partial?
95-
96-
root_span.metastruct.deep_merge!(trace.send(:metastruct))
97-
end
98-
9992
def tag_agent_sample_rate!
10093
return unless trace.agent_sample_rate
10194

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

-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,6 @@ def initialize(apis, default_api)
127127
end
128128

129129
def send_traces(traces)
130-
# object that extends Datadog::Core::Encoding::Encoder (MsgpackEncoder or JSONEncoder)
131130
encoder = current_api.encoder
132131
chunker = Datadog::Tracing::Transport::Traces::Chunker.new(
133132
encoder,

Diff for: sig/datadog/tracing/metadata.rbs

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ module Datadog
22
module Tracing
33
module Metadata
44
include Metadata::Tagging
5+
include Metadata::MetastructTagging
56
include Metadata::Errors
67
prepend Metadata::Analytics
78
end

0 commit comments

Comments
 (0)