Skip to content

Commit 65b2901

Browse files
authored
Merge pull request #4334 from DataDog/vpellan/meta-struct
Add meta_struct support on traces and spans
2 parents f7b904d + a70a07e commit 65b2901

14 files changed

+166
-3
lines changed

Steepfile

+1
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ target :datadog do
160160
library 'zlib'
161161
library 'time'
162162
library 'pp'
163+
library 'forwardable'
163164

164165
# Load all dependency signatures from the `vendor/rbs` directory
165166
repo_path 'vendor/rbs'

lib/datadog/tracing/metadata.rb

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

33
require_relative 'metadata/analytics'
44
require_relative 'metadata/tagging'
5+
require_relative 'metadata/metastruct_tagging'
56
require_relative 'metadata/errors'
67

78
module Datadog
@@ -10,6 +11,7 @@ module Tracing
1011
module Metadata
1112
def self.included(base)
1213
base.include(Metadata::Tagging)
14+
base.include(Metadata::MetastructTagging)
1315
base.include(Metadata::Errors)
1416

1517
# Additional extensions
+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# frozen_string_literal: true
2+
3+
require 'forwardable'
4+
5+
module Datadog
6+
module Tracing
7+
module Metadata
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.
12+
class Metastruct
13+
extend Forwardable
14+
15+
def_delegators :@metastruct, :[], :[]=, :to_h
16+
17+
def initialize
18+
@metastruct = {}
19+
end
20+
21+
def to_msgpack(packer = nil)
22+
# JRuby doesn't pass the packer
23+
packer ||= MessagePack::Packer.new
24+
25+
packer.write(@metastruct.transform_values(&:to_msgpack))
26+
end
27+
28+
def pretty_print(q)
29+
q.seplist @metastruct.each do |key, value|
30+
q.text "#{key} => #{value}"
31+
end
32+
end
33+
end
34+
end
35+
end
36+
end
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

lib/datadog/tracing/span.rb

+10-1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ class Span
3333
:status,
3434
:trace_id
3535

36+
attr_reader \
37+
:metastruct
38+
3639
attr_writer \
3740
:duration
3841

@@ -54,6 +57,7 @@ def initialize(
5457
id: nil,
5558
meta: nil,
5659
metrics: nil,
60+
metastruct: nil,
5761
parent_id: 0,
5862
resource: name,
5963
service: nil,
@@ -76,6 +80,7 @@ def initialize(
7680

7781
@meta = meta || {}
7882
@metrics = metrics || {}
83+
@metastruct = metastruct || {}
7984
@status = status || 0
8085

8186
# start_time and end_time track wall clock. In Ruby, wall clock
@@ -144,6 +149,7 @@ def to_hash
144149
error: @status,
145150
meta: @meta,
146151
metrics: @metrics,
152+
meta_struct: @metastruct.to_h,
147153
name: @name,
148154
parent_id: @parent_id,
149155
resource: @resource,
@@ -185,12 +191,15 @@ def pretty_print(q)
185191
q.text "#{key} => #{value}"
186192
end
187193
end
188-
q.group(2, 'Metrics: [', ']') do
194+
q.group(2, 'Metrics: [', "]\n") do
189195
q.breakable
190196
q.seplist @metrics.each do |key, value|
191197
q.text "#{key} => #{value}"
192198
end
193199
end
200+
q.group(2, 'Metastruct: [', ']') do
201+
metastruct.pretty_print(q)
202+
end
194203
end
195204
end
196205

lib/datadog/tracing/span_operation.rb

+6-1
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ def to_hash
289289
id: @id,
290290
meta: meta,
291291
metrics: metrics,
292+
metastruct: metastruct,
292293
name: @name,
293294
parent_id: @parent_id,
294295
resource: @resource,
@@ -328,12 +329,15 @@ def pretty_print(q)
328329
q.text "#{key} => #{value}"
329330
end
330331
end
331-
q.group(2, 'Metrics: [', ']') do
332+
q.group(2, 'Metrics: [', "]\n") do
332333
q.breakable
333334
q.seplist metrics.each do |key, value|
334335
q.text "#{key} => #{value}"
335336
end
336337
end
338+
q.group(2, 'Metastruct: [', ']') do
339+
metastruct.pretty_print(q)
340+
end
337341
end
338342
end
339343

@@ -456,6 +460,7 @@ def build_span
456460
id: @id,
457461
meta: Core::Utils::SafeDup.frozen_or_dup(meta),
458462
metrics: Core::Utils::SafeDup.frozen_or_dup(metrics),
463+
metastruct: Core::Utils::SafeDup.frozen_or_dup(metastruct),
459464
parent_id: @parent_id,
460465
resource: @resource,
461466
service: @service,

lib/datadog/tracing/transport/serializable_trace.rb

+3-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def initialize(span, native_events_supported:)
6969
def to_msgpack(packer = nil)
7070
packer ||= MessagePack::Packer.new
7171

72-
number_of_elements_to_write = 11
72+
number_of_elements_to_write = 12
7373

7474
number_of_elements_to_write += 1 if span.events.any? && @native_events_supported
7575

@@ -117,6 +117,8 @@ def to_msgpack(packer = nil)
117117
packer.write(span.meta)
118118
packer.write('metrics')
119119
packer.write(span.metrics)
120+
packer.write('meta_struct')
121+
packer.write(span.metastruct)
120122
packer.write('span_links')
121123
packer.write(span.links.map(&:to_hash))
122124
packer.write('error')

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
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
module Datadog
2+
module Tracing
3+
module Metadata
4+
class Metastruct
5+
extend Forwardable
6+
7+
def []: (String | Symbol key) -> untyped
8+
9+
def []=: (String | Symbol key, untyped value) -> untyped
10+
11+
def to_h: () -> ::Hash[String | Symbol, untyped]
12+
13+
def to_msgpack: (untyped packer) -> void
14+
15+
def pretty_print: (untyped q) -> void
16+
end
17+
end
18+
end
19+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module Datadog
2+
module Tracing
3+
module Metadata
4+
module MetastructTagging
5+
def set_metastruct_tag: (String | Symbol key, untyped value) -> untyped
6+
def get_metastruct_tag: (String | Symbol key) -> untyped
7+
private def metastruct: () -> Datadog::Tracing::Metadata::Metastruct
8+
end
9+
end
10+
end
11+
end

sig/datadog/tracing/span.rbs

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ module Datadog
1818
attr_accessor status: Integer
1919
attr_accessor trace_id: Integer
2020
attr_writer duration: (Float | nil)
21+
attr_reader metastruct: Hash[String | Symbol, untyped]
2122

2223
def initialize: (
2324
String name,
@@ -26,6 +27,7 @@ module Datadog
2627
?id: (Integer | nil),
2728
?meta: (Hash[String, String] | nil),
2829
?metrics: (Hash[String, Float] | nil),
30+
?metastruct: Hash[String | Symbol, untyped],
2931
?parent_id: Integer,
3032
?resource: String,
3133
?service: (String | nil),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
require 'spec_helper'
2+
3+
require 'datadog/tracing/metadata/metastruct_tagging'
4+
5+
RSpec.describe Datadog::Tracing::Metadata::MetastructTagging do
6+
subject(:object) { test_class.new }
7+
8+
let(:test_class) do
9+
Class.new { include Datadog::Tracing::Metadata::MetastructTagging }
10+
end
11+
12+
describe '#set_metastruct_tag' do
13+
it 'sets the metastruct to a hash with given key / value pair' do
14+
expect { object.set_metastruct_tag(:foo, [{ some: 'value' }]) }
15+
.to change { object.get_metastruct_tag(:foo) }.from(nil).to([{ some: 'value' }])
16+
end
17+
18+
it 'does not lose previous entries' do
19+
object.set_metastruct_tag(:foo, [{ some: 'value' }])
20+
21+
expect { object.set_metastruct_tag(:bar, [{ another: 'value' }]) }
22+
.not_to(change { object.get_metastruct_tag(:foo) })
23+
end
24+
end
25+
26+
describe '#get_metastruct_tag' do
27+
it 'returns nil if the key does not exist' do
28+
expect(object.get_metastruct_tag(:foo)).to be_nil
29+
end
30+
end
31+
end

spec/datadog/tracing/span_spec.rb

+1
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@
244244
type: nil,
245245
meta: {},
246246
metrics: {},
247+
meta_struct: {},
247248
span_links: [],
248249
error: 0
249250
)

spec/datadog/tracing/transport/serializable_trace_spec.rb

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
'type',
4141
'meta',
4242
'metrics',
43+
'meta_struct',
4344
'span_links',
4445
'error',
4546
]

0 commit comments

Comments
 (0)