datadog 2.8.0 → 2.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +36 -1
  3. data/ext/datadog_profiling_native_extension/clock_id.h +2 -2
  4. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +64 -54
  5. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +1 -1
  6. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h +1 -1
  7. data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +16 -16
  8. data/ext/datadog_profiling_native_extension/collectors_stack.c +7 -7
  9. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +219 -122
  10. data/ext/datadog_profiling_native_extension/heap_recorder.h +1 -1
  11. data/ext/datadog_profiling_native_extension/http_transport.c +4 -4
  12. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +3 -0
  13. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +3 -1
  14. data/ext/datadog_profiling_native_extension/profiling.c +10 -8
  15. data/ext/datadog_profiling_native_extension/ruby_helpers.c +8 -8
  16. data/ext/datadog_profiling_native_extension/stack_recorder.c +54 -54
  17. data/ext/datadog_profiling_native_extension/stack_recorder.h +1 -1
  18. data/ext/datadog_profiling_native_extension/time_helpers.h +1 -1
  19. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.c +47 -0
  20. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.h +31 -0
  21. data/ext/libdatadog_api/crashtracker.c +3 -0
  22. data/lib/datadog/appsec/assets/waf_rules/recommended.json +355 -157
  23. data/lib/datadog/appsec/assets/waf_rules/strict.json +62 -32
  24. data/lib/datadog/appsec/context.rb +54 -0
  25. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +7 -7
  26. data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +6 -6
  27. data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +4 -4
  28. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +19 -28
  29. data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +5 -5
  30. data/lib/datadog/appsec/contrib/rack/gateway/response.rb +3 -3
  31. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +64 -96
  32. data/lib/datadog/appsec/contrib/rack/reactive/request.rb +10 -10
  33. data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +5 -5
  34. data/lib/datadog/appsec/contrib/rack/reactive/response.rb +6 -6
  35. data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +10 -11
  36. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +43 -49
  37. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +21 -32
  38. data/lib/datadog/appsec/contrib/rails/patcher.rb +1 -1
  39. data/lib/datadog/appsec/contrib/rails/reactive/action.rb +6 -6
  40. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +41 -63
  41. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +2 -2
  42. data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +5 -5
  43. data/lib/datadog/appsec/event.rb +6 -6
  44. data/lib/datadog/appsec/ext.rb +3 -1
  45. data/lib/datadog/appsec/monitor/gateway/watcher.rb +22 -32
  46. data/lib/datadog/appsec/monitor/reactive/set_user.rb +5 -5
  47. data/lib/datadog/appsec/processor/rule_loader.rb +0 -3
  48. data/lib/datadog/appsec.rb +3 -3
  49. data/lib/datadog/auto_instrument.rb +3 -0
  50. data/lib/datadog/core/configuration/agent_settings_resolver.rb +39 -11
  51. data/lib/datadog/core/configuration/components.rb +4 -2
  52. data/lib/datadog/core/configuration.rb +1 -1
  53. data/lib/datadog/{tracing → core}/contrib/rails/utils.rb +1 -3
  54. data/lib/datadog/core/crashtracking/component.rb +1 -3
  55. data/lib/datadog/core/telemetry/event.rb +87 -3
  56. data/lib/datadog/core/telemetry/logging.rb +2 -2
  57. data/lib/datadog/core/telemetry/metric.rb +22 -0
  58. data/lib/datadog/core/telemetry/worker.rb +33 -0
  59. data/lib/datadog/di/base.rb +115 -0
  60. data/lib/datadog/di/code_tracker.rb +7 -4
  61. data/lib/datadog/di/component.rb +17 -11
  62. data/lib/datadog/di/configuration/settings.rb +11 -1
  63. data/lib/datadog/di/contrib/railtie.rb +15 -0
  64. data/lib/datadog/di/contrib.rb +26 -0
  65. data/lib/datadog/di/error.rb +5 -0
  66. data/lib/datadog/di/instrumenter.rb +39 -18
  67. data/lib/datadog/di/{init.rb → preload.rb} +2 -4
  68. data/lib/datadog/di/probe_manager.rb +4 -4
  69. data/lib/datadog/di/probe_notification_builder.rb +16 -2
  70. data/lib/datadog/di/probe_notifier_worker.rb +5 -6
  71. data/lib/datadog/di/remote.rb +4 -4
  72. data/lib/datadog/di/transport.rb +2 -4
  73. data/lib/datadog/di.rb +5 -108
  74. data/lib/datadog/kit/appsec/events.rb +3 -3
  75. data/lib/datadog/kit/identity.rb +4 -4
  76. data/lib/datadog/profiling/component.rb +55 -53
  77. data/lib/datadog/profiling/http_transport.rb +1 -26
  78. data/lib/datadog/tracing/contrib/action_cable/integration.rb +5 -2
  79. data/lib/datadog/tracing/contrib/action_mailer/integration.rb +6 -2
  80. data/lib/datadog/tracing/contrib/action_pack/integration.rb +5 -2
  81. data/lib/datadog/tracing/contrib/action_view/integration.rb +5 -2
  82. data/lib/datadog/tracing/contrib/active_job/integration.rb +5 -2
  83. data/lib/datadog/tracing/contrib/active_record/integration.rb +6 -2
  84. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +3 -1
  85. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +3 -1
  86. data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +10 -0
  87. data/lib/datadog/tracing/contrib/active_support/integration.rb +5 -2
  88. data/lib/datadog/tracing/contrib/auto_instrument.rb +2 -2
  89. data/lib/datadog/tracing/contrib/aws/integration.rb +3 -0
  90. data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +3 -0
  91. data/lib/datadog/tracing/contrib/httprb/integration.rb +3 -0
  92. data/lib/datadog/tracing/contrib/kafka/integration.rb +3 -0
  93. data/lib/datadog/tracing/contrib/mongodb/integration.rb +3 -0
  94. data/lib/datadog/tracing/contrib/opensearch/integration.rb +3 -0
  95. data/lib/datadog/tracing/contrib/presto/integration.rb +3 -0
  96. data/lib/datadog/tracing/contrib/rack/integration.rb +2 -2
  97. data/lib/datadog/tracing/contrib/rails/framework.rb +2 -2
  98. data/lib/datadog/tracing/contrib/rails/patcher.rb +1 -1
  99. data/lib/datadog/tracing/contrib/rest_client/integration.rb +3 -0
  100. data/lib/datadog/tracing/span.rb +12 -4
  101. data/lib/datadog/tracing/span_event.rb +123 -3
  102. data/lib/datadog/tracing/span_operation.rb +6 -0
  103. data/lib/datadog/tracing/transport/serializable_trace.rb +24 -6
  104. data/lib/datadog/version.rb +1 -1
  105. metadata +19 -10
  106. data/lib/datadog/appsec/reactive/operation.rb +0 -68
  107. data/lib/datadog/appsec/scope.rb +0 -58
  108. data/lib/datadog/core/crashtracking/agent_base_url.rb +0 -21
@@ -4,7 +4,7 @@ require_relative 'configuration/settings'
4
4
  require_relative 'patcher'
5
5
  require_relative '../integration'
6
6
  require_relative '../rails/ext'
7
- require_relative '../rails/utils'
7
+ require_relative '../../../core/contrib/rails/utils'
8
8
 
9
9
  module Datadog
10
10
  module Tracing
@@ -18,6 +18,9 @@ module Datadog
18
18
 
19
19
  # @public_api Changing the integration name or integration options can cause breaking changes
20
20
  register_as :action_view, auto_patch: false
21
+ def self.gem_name
22
+ 'actionview'
23
+ end
21
24
 
22
25
  def self.version
23
26
  # ActionView is its own gem in Rails 4.1+
@@ -41,7 +44,7 @@ module Datadog
41
44
  # enabled by rails integration so should only auto instrument
42
45
  # if detected that it is being used without rails
43
46
  def auto_instrument?
44
- !Contrib::Rails::Utils.railtie_supported?
47
+ !Core::Contrib::Rails::Utils.railtie_supported?
45
48
  end
46
49
 
47
50
  def new_configuration
@@ -3,7 +3,7 @@
3
3
  require_relative 'configuration/settings'
4
4
  require_relative 'patcher'
5
5
  require_relative '../integration'
6
- require_relative '../rails/utils'
6
+ require_relative '../../../core/contrib/rails/utils'
7
7
 
8
8
  module Datadog
9
9
  module Tracing
@@ -17,6 +17,9 @@ module Datadog
17
17
 
18
18
  # @public_api Changing the integration name or integration options can cause breaking changes
19
19
  register_as :active_job, auto_patch: false
20
+ def self.gem_name
21
+ 'activejob'
22
+ end
20
23
 
21
24
  def self.version
22
25
  Gem.loaded_specs['activejob'] && Gem.loaded_specs['activejob'].version
@@ -33,7 +36,7 @@ module Datadog
33
36
  # enabled by rails integration so should only auto instrument
34
37
  # if detected that it is being used without rails
35
38
  def auto_instrument?
36
- !Contrib::Rails::Utils.railtie_supported?
39
+ !Core::Contrib::Rails::Utils.railtie_supported?
37
40
  end
38
41
 
39
42
  def new_configuration
@@ -7,7 +7,7 @@ require_relative 'patcher'
7
7
  require_relative '../component'
8
8
  require_relative '../integration'
9
9
  require_relative '../rails/ext'
10
- require_relative '../rails/utils'
10
+ require_relative '../../../core/contrib/rails/utils'
11
11
 
12
12
  module Datadog
13
13
  module Tracing
@@ -22,6 +22,10 @@ module Datadog
22
22
  # @public_api Changing the integration name or integration options can cause breaking changes
23
23
  register_as :active_record, auto_patch: false
24
24
 
25
+ def self.gem_name
26
+ 'activerecord'
27
+ end
28
+
25
29
  def self.version
26
30
  Gem.loaded_specs['activerecord'] && Gem.loaded_specs['activerecord'].version
27
31
  end
@@ -37,7 +41,7 @@ module Datadog
37
41
  # enabled by rails integration so should only auto instrument
38
42
  # if detected that it is being used without rails
39
43
  def auto_instrument?
40
- !Contrib::Rails::Utils.railtie_supported?
44
+ !Core::Contrib::Rails::Utils.railtie_supported?
41
45
  end
42
46
 
43
47
  def new_configuration
@@ -81,7 +81,9 @@ module Datadog
81
81
 
82
82
  span.set_tag('EVENT', event)
83
83
 
84
- set_cache_key(span, key, mapping[:multi_key])
84
+ if Datadog.configuration.tracing[:active_support][:cache_key].enabled
85
+ set_cache_key(span, key, mapping[:multi_key])
86
+ end
85
87
  rescue StandardError => e
86
88
  Datadog.logger.error(e.message)
87
89
  Datadog::Core::Telemetry::Logger.report(e)
@@ -3,6 +3,7 @@
3
3
  require_relative '../../../../core/utils'
4
4
  require_relative '../../../metadata/ext'
5
5
  require_relative '../ext'
6
+ require_relative 'event'
6
7
 
7
8
  module Datadog
8
9
  module Tracing
@@ -58,7 +59,8 @@ module Datadog
58
59
  end
59
60
 
60
61
  span.set_tag(Ext::TAG_CACHE_BACKEND, store) if store
61
- set_cache_key(span, key, multi_key)
62
+
63
+ set_cache_key(span, key, multi_key) if Datadog.configuration.tracing[:active_support][:cache_key].enabled
62
64
 
63
65
  yield
64
66
  end
@@ -39,6 +39,16 @@ module Datadog
39
39
  )
40
40
  end
41
41
  end
42
+
43
+ # grouped "cache_key.*" settings
44
+ settings :cache_key do
45
+ # enable or disabling the inclusion of the cache_key in the span
46
+ option :enabled do |o|
47
+ # cache_key.enabled
48
+ o.type :bool
49
+ o.default true
50
+ end
51
+ end
42
52
  end
43
53
  end
44
54
  end
@@ -5,7 +5,7 @@ require_relative 'configuration/settings'
5
5
  require_relative 'patcher'
6
6
  require_relative 'cache/redis'
7
7
  require_relative '../rails/ext'
8
- require_relative '../rails/utils'
8
+ require_relative '../../../core/contrib/rails/utils'
9
9
 
10
10
  module Datadog
11
11
  module Tracing
@@ -19,6 +19,9 @@ module Datadog
19
19
 
20
20
  # @public_api Changing the integration name or integration options can cause breaking changes
21
21
  register_as :active_support, auto_patch: false
22
+ def self.gem_name
23
+ 'activesupport'
24
+ end
22
25
 
23
26
  def self.version
24
27
  Gem.loaded_specs['activesupport'] && Gem.loaded_specs['activesupport'].version
@@ -35,7 +38,7 @@ module Datadog
35
38
  # enabled by rails integration so should only auto instrument
36
39
  # if detected that it is being used without rails
37
40
  def auto_instrument?
38
- !Contrib::Rails::Utils.railtie_supported?
41
+ !Core::Contrib::Rails::Utils.railtie_supported?
39
42
  end
40
43
 
41
44
  def new_configuration
@@ -9,10 +9,10 @@ module Datadog
9
9
  module Contrib
10
10
  # Auto-activate instrumentation
11
11
  def self.auto_instrument!
12
- require_relative 'rails/utils'
12
+ require_relative '../../core/contrib/rails/utils'
13
13
 
14
14
  # Defer to Rails if this is a Rails application
15
- if Datadog::Tracing::Contrib::Rails::Utils.railtie_supported?
15
+ if Datadog::Core::Contrib::Rails::Utils.railtie_supported?
16
16
  require_relative 'rails/auto_instrument_railtie'
17
17
  else
18
18
  AutoInstrument.patch_all!
@@ -16,6 +16,9 @@ module Datadog
16
16
 
17
17
  # @public_api Changing the integration name or integration options can cause breaking changes
18
18
  register_as :aws, auto_patch: true
19
+ def self.gem_name
20
+ 'aws-sdk-core'
21
+ end
19
22
 
20
23
  def self.version
21
24
  if Gem.loaded_specs['aws-sdk']
@@ -16,6 +16,9 @@ module Datadog
16
16
 
17
17
  # @public_api Changing the integration name or integration options can cause breaking changes
18
18
  register_as :concurrent_ruby
19
+ def self.gem_name
20
+ 'concurrent-ruby'
21
+ end
19
22
 
20
23
  def self.version
21
24
  Gem.loaded_specs['concurrent-ruby'] && Gem.loaded_specs['concurrent-ruby'].version
@@ -17,6 +17,9 @@ module Datadog
17
17
 
18
18
  # @public_api Changing the integration name or integration options can cause breaking changes
19
19
  register_as :httprb
20
+ def self.gem_name
21
+ 'http'
22
+ end
20
23
 
21
24
  def self.version
22
25
  Gem.loaded_specs['http'] && Gem.loaded_specs['http'].version
@@ -16,6 +16,9 @@ module Datadog
16
16
 
17
17
  # @public_api Changing the integration name or integration options can cause breaking changes
18
18
  register_as :kafka, auto_patch: false
19
+ def self.gem_name
20
+ 'ruby-kafka'
21
+ end
19
22
 
20
23
  def self.version
21
24
  Gem.loaded_specs['ruby-kafka'] && Gem.loaded_specs['ruby-kafka'].version
@@ -17,6 +17,9 @@ module Datadog
17
17
 
18
18
  # @public_api Changing the integration name or integration options can cause breaking changes
19
19
  register_as :mongo, auto_patch: true
20
+ def self.gem_name
21
+ 'mongo'
22
+ end
20
23
 
21
24
  def self.version
22
25
  Gem.loaded_specs['mongo'] && Gem.loaded_specs['mongo'].version
@@ -16,6 +16,9 @@ module Datadog
16
16
 
17
17
  # @public_api Changing the integration name or integration options can cause breaking changes
18
18
  register_as :opensearch, auto_patch: true
19
+ def self.gem_name
20
+ 'opensearch-ruby'
21
+ end
19
22
 
20
23
  def self.version
21
24
  Gem.loaded_specs['opensearch-ruby'] \
@@ -16,6 +16,9 @@ module Datadog
16
16
 
17
17
  # @public_api Changing the integration name or integration options can cause breaking changes
18
18
  register_as :presto
19
+ def self.gem_name
20
+ 'presto-client'
21
+ end
19
22
 
20
23
  def self.version
21
24
  Gem.loaded_specs['presto-client'] && Gem.loaded_specs['presto-client'].version
@@ -3,7 +3,7 @@
3
3
  require_relative '../integration'
4
4
  require_relative 'configuration/settings'
5
5
  require_relative 'patcher'
6
- require_relative '../rails/utils'
6
+ require_relative '../../../core/contrib/rails/utils'
7
7
 
8
8
  module Datadog
9
9
  module Tracing
@@ -33,7 +33,7 @@ module Datadog
33
33
  # enabled by rails integration so should only auto instrument
34
34
  # if detected that it is being used without rails
35
35
  def auto_instrument?
36
- !Contrib::Rails::Utils.railtie_supported?
36
+ !Core::Contrib::Rails::Utils.railtie_supported?
37
37
  end
38
38
 
39
39
  def new_configuration
@@ -9,7 +9,7 @@ require_relative '../active_support/integration'
9
9
  require_relative '../grape/endpoint'
10
10
  require_relative '../lograge/integration'
11
11
  require_relative 'ext'
12
- require_relative 'utils'
12
+ require_relative '../../../core/contrib/rails/utils'
13
13
  require_relative '../semantic_logger/integration'
14
14
 
15
15
  module Datadog
@@ -41,7 +41,7 @@ module Datadog
41
41
  # being executed, but here we know better, get it from Rails config.
42
42
  # Don't set this if service has been explicitly provided by the user.
43
43
  if datadog_config.service_without_fallback.nil?
44
- datadog_config.service = rails_config[:service_name] || Utils.app_name
44
+ datadog_config.service = rails_config[:service_name] || Core::Contrib::Rails::Utils.app_name
45
45
  end
46
46
 
47
47
  activate_rack!(datadog_config, rails_config)
@@ -6,7 +6,7 @@ require_relative 'framework'
6
6
  require_relative 'log_injection'
7
7
  require_relative 'middlewares'
8
8
  require_relative 'runner'
9
- require_relative 'utils'
9
+ require_relative '../../../core/contrib/rails/utils'
10
10
  require_relative '../semantic_logger/patcher'
11
11
 
12
12
  module Datadog
@@ -16,6 +16,9 @@ module Datadog
16
16
 
17
17
  # @public_api Changing the integration name or integration options can cause breaking changes
18
18
  register_as :rest_client
19
+ def self.gem_name
20
+ 'rest-client'
21
+ end
19
22
 
20
23
  def self.version
21
24
  Gem.loaded_specs['rest-client'] && Gem.loaded_specs['rest-client'].version
@@ -112,7 +112,10 @@ module Datadog
112
112
 
113
113
  def duration
114
114
  return @duration if @duration
115
- return @end_time - @start_time if @start_time && @end_time
115
+
116
+ start_time = @start_time
117
+ end_time = @end_time
118
+ end_time - start_time if start_time && end_time
116
119
  end
117
120
 
118
121
  def set_error(e)
@@ -135,6 +138,8 @@ module Datadog
135
138
  # TODO: Change this to reflect attributes when serialization
136
139
  # isn't handled by this method.
137
140
  def to_hash
141
+ @meta['events'] = @events.map(&:to_hash).to_json unless @events.empty?
142
+
138
143
  h = {
139
144
  error: @status,
140
145
  meta: @meta,
@@ -154,8 +159,6 @@ module Datadog
154
159
  h[:duration] = duration_nano
155
160
  end
156
161
 
157
- h[:meta]['events'] = @events.map(&:to_hash).to_json unless @events.empty?
158
-
159
162
  h
160
163
  end
161
164
 
@@ -196,12 +199,17 @@ module Datadog
196
199
  # Used for serialization
197
200
  # @return [Integer] in nanoseconds since Epoch
198
201
  def start_time_nano
199
- @start_time.to_i * 1000000000 + @start_time.nsec
202
+ return unless (start_time = @start_time)
203
+
204
+ start_time.to_i * 1000000000 + start_time.nsec
200
205
  end
201
206
 
202
207
  # Used for serialization
203
208
  # @return [Integer] in nanoseconds since Epoch
204
209
  def duration_nano
210
+ duration = self.duration
211
+ return unless duration
212
+
205
213
  (duration * 1e9).to_i
206
214
  end
207
215
 
@@ -19,23 +19,143 @@ module Datadog
19
19
  # @return [Integer]
20
20
  attr_reader :time_unix_nano
21
21
 
22
+ # TODO: Accept {Time} as the time_unix_nano parameter, possibly in addition to the current nano integer.
22
23
  def initialize(
23
24
  name,
24
25
  attributes: nil,
25
26
  time_unix_nano: nil
26
27
  )
27
28
  @name = name
28
- @attributes = attributes || {}
29
+
30
+ @attributes = attributes.dup || {}
31
+ validate_attributes!(@attributes)
32
+ @attributes.transform_keys!(&:to_s)
33
+
29
34
  # OpenTelemetry SDK stores span event timestamps in nanoseconds (not seconds).
30
35
  # We will do the same here to avoid unnecessary conversions and inconsistencies.
31
36
  @time_unix_nano = time_unix_nano || (Time.now.to_r * 1_000_000_000).to_i
32
37
  end
33
38
 
39
+ # Converts the span event into a hash to be used by with the span tag serialization
40
+ # (`span.set_tag('events) = [event.to_hash]`). This serialization format has the drawback
41
+ # of being limiting span events to the size limit of a span tag.
42
+ # All Datadog agents support this format.
34
43
  def to_hash
35
- h = { name: @name, time_unix_nano: @time_unix_nano }
36
- h[:attributes] = attributes unless @attributes.empty?
44
+ h = { 'name' => @name, 'time_unix_nano' => @time_unix_nano }
45
+ h['attributes'] = @attributes unless @attributes.empty?
46
+ h
47
+ end
48
+
49
+ # Converts the span event into a hash to be used by the MessagePack serialization as a
50
+ # top-level span field (span.span_events = [event.to_native_format]).
51
+ # This serialization format removes the serialization limitations of the `span.set_tag('events)` approach,
52
+ # but is only supported by newer version of the Datadog agent.
53
+ def to_native_format
54
+ h = { 'name' => @name, 'time_unix_nano' => @time_unix_nano }
55
+
56
+ attr = {}
57
+ @attributes.each do |key, value|
58
+ attr[key] = if value.is_a?(Array)
59
+ { type: ARRAY_TYPE, array_value: value.map { |v| serialize_native_attribute(v) } }
60
+ else
61
+ serialize_native_attribute(value)
62
+ end
63
+ end
64
+
65
+ h['attributes'] = attr unless @attributes.empty?
66
+
37
67
  h
38
68
  end
69
+
70
+ private
71
+
72
+ MIN_INT64_SIGNED = -2**63
73
+ MAX_INT64_SIGNED = 2 << 63 - 1
74
+
75
+ # Checks the attributes hash to ensure it only contains serializable values.
76
+ # Invalid values are removed from the hash.
77
+ def validate_attributes!(attributes)
78
+ attributes.select! do |key, value|
79
+ case value
80
+ when Array
81
+ next true if value.empty?
82
+
83
+ first = value.first
84
+ case first
85
+ when String, Integer, Float
86
+ first_type = first.class
87
+ if value.all? { |v| v.is_a?(first_type) }
88
+ value.all? { |v| validate_scalar_attribute!(key, v) }
89
+ else
90
+ Datadog.logger.warn("Attribute #{key} array must be homogenous: #{value}.")
91
+ false
92
+ end
93
+ when TrueClass, FalseClass
94
+ if value.all? { |v| v.is_a?(TrueClass) || v.is_a?(FalseClass) }
95
+ value.all? { |v| validate_scalar_attribute!(key, v) }
96
+ else
97
+ Datadog.logger.warn("Attribute #{key} array must be homogenous: #{value}.")
98
+ false
99
+ end
100
+ else
101
+ Datadog.logger.warn("Attribute #{key} must be a string, number, or boolean: #{value}.")
102
+ false
103
+ end
104
+ when String, Numeric, TrueClass, FalseClass
105
+ validate_scalar_attribute!(key, value)
106
+ else
107
+ Datadog.logger.warn("Attribute #{key} must be a string, number, boolean, or array: #{value}.")
108
+ false
109
+ end
110
+ end
111
+ end
112
+
113
+ def validate_scalar_attribute!(key, value)
114
+ case value
115
+ when String, TrueClass, FalseClass
116
+ true
117
+ when Integer
118
+ # Cannot be larger than signed 64-bit integer
119
+ if value < MIN_INT64_SIGNED || value > MAX_INT64_SIGNED
120
+ Datadog.logger.warn("Attribute #{key} must be within the range of a signed 64-bit integer: #{value}.")
121
+ false
122
+ else
123
+ true
124
+ end
125
+ when Float
126
+ # Has to be finite
127
+ return true if value.finite?
128
+
129
+ Datadog.logger.warn("Attribute #{key} must be a finite number: #{value}.")
130
+ false
131
+ else
132
+ Datadog.logger.warn("Attribute #{key} must be a string, number, or boolean: #{value}.")
133
+ false
134
+ end
135
+ end
136
+
137
+ STRING_TYPE = 0
138
+ BOOLEAN_TYPE = 1
139
+ INTEGER_TYPE = 2
140
+ DOUBLE_TYPE = 3
141
+ ARRAY_TYPE = 4
142
+
143
+ # Serializes individual scalar attributes into the native format.
144
+ def serialize_native_attribute(value)
145
+ case value
146
+ when String
147
+ { type: STRING_TYPE, string_value: value }
148
+ when TrueClass, FalseClass
149
+ { type: BOOLEAN_TYPE, bool_value: value }
150
+ when Integer
151
+ { type: INTEGER_TYPE, int_value: value }
152
+ when Float
153
+ { type: DOUBLE_TYPE, double_value: value }
154
+ else
155
+ # This is technically unreachable due to the validation in #initialize.
156
+ raise ArgumentError, "Attribute must be a string, number, or boolean: #{value}."
157
+ end
158
+ end
39
159
  end
40
160
  end
41
161
  end
@@ -11,6 +11,8 @@ require_relative 'event'
11
11
  require_relative 'metadata'
12
12
  require_relative 'metadata/ext'
13
13
  require_relative 'span'
14
+ require_relative 'span_event'
15
+ require_relative 'span_link'
14
16
  require_relative 'utils'
15
17
 
16
18
  module Datadog
@@ -197,6 +199,9 @@ module Datadog
197
199
  end
198
200
 
199
201
  # Mark the span stopped at the current time
202
+ #
203
+ # steep:ignore:start
204
+ # Steep issue fixed in https://github.com/soutaro/steep/pull/1467
200
205
  def stop(stop_time = nil)
201
206
  # A span should not be stopped twice. Note that this is not thread-safe,
202
207
  # stop is called from multiple threads, a given span might be stopped
@@ -219,6 +224,7 @@ module Datadog
219
224
 
220
225
  self
221
226
  end
227
+ # steep:ignore:end
222
228
 
223
229
  # Return whether the duration is started or not
224
230
  def started?
@@ -12,8 +12,11 @@ module Datadog
12
12
  attr_reader \
13
13
  :trace
14
14
 
15
- def initialize(trace)
15
+ # @param trace [Datadog::Trace] the trace to serialize
16
+ # @param native_events_supported [Boolean] whether the agent supports span events as a top-level field
17
+ def initialize(trace, native_events_supported = false)
16
18
  @trace = trace
19
+ @native_events_supported = native_events_supported
17
20
  end
18
21
 
19
22
  # MessagePack serializer interface. Making this object
@@ -26,13 +29,13 @@ module Datadog
26
29
  # @param packer [MessagePack::Packer] serialization buffer, can be +nil+ with JRuby
27
30
  def to_msgpack(packer = nil)
28
31
  # As of 1.3.3, JRuby implementation doesn't pass an existing packer
29
- trace.spans.map { |s| SerializableSpan.new(s) }.to_msgpack(packer)
32
+ trace.spans.map { |s| SerializableSpan.new(s, @native_events_supported) }.to_msgpack(packer)
30
33
  end
31
34
 
32
35
  # JSON serializer interface.
33
36
  # Used by older version of the transport.
34
37
  def to_json(*args)
35
- trace.spans.map { |s| SerializableSpan.new(s).to_hash }.to_json(*args)
38
+ trace.spans.map { |s| SerializableSpan.new(s, @native_events_supported).to_hash }.to_json(*args)
36
39
  end
37
40
  end
38
41
 
@@ -41,9 +44,12 @@ module Datadog
41
44
  attr_reader \
42
45
  :span
43
46
 
44
- def initialize(span)
47
+ # @param span [Datadog::Span] the span to serialize
48
+ # @param native_events_supported [Boolean] whether the agent supports span events as a top-level field
49
+ def initialize(span, native_events_supported)
45
50
  @span = span
46
51
  @trace_id = Tracing::Utils::TraceId.to_low_order(span.trace_id)
52
+ @native_events_supported = native_events_supported
47
53
  end
48
54
 
49
55
  # MessagePack serializer interface. Making this object
@@ -55,11 +61,14 @@ module Datadog
55
61
  #
56
62
  # @param packer [MessagePack::Packer] serialization buffer, can be +nil+ with JRuby
57
63
  # rubocop:disable Metrics/AbcSize
64
+ # rubocop:disable Metrics/MethodLength
58
65
  def to_msgpack(packer = nil)
59
66
  packer ||= MessagePack::Packer.new
60
67
 
61
68
  number_of_elements_to_write = 11
62
69
 
70
+ number_of_elements_to_write += 1 if span.events.any? && @native_events_supported
71
+
63
72
  if span.stopped?
64
73
  packer.write_map_header(number_of_elements_to_write + 2) # Set header with how many elements in the map
65
74
 
@@ -72,8 +81,16 @@ module Datadog
72
81
  packer.write_map_header(number_of_elements_to_write) # Set header with how many elements in the map
73
82
  end
74
83
 
75
- # serialize span events as meta tags
76
- span.set_tag('events', span.events.map(&:to_hash).to_json) if span.events.any?
84
+ if span.events.any?
85
+ if @native_events_supported
86
+ # Use top-level field for native events
87
+ packer.write('span_events')
88
+ packer.write(span.events.map(&:to_native_format))
89
+ else
90
+ # Serialize span events as meta tags
91
+ span.set_tag('events', span.events.map(&:to_hash).to_json)
92
+ end
93
+ end
77
94
 
78
95
  # DEV: We use strings as keys here, instead of symbols, as
79
96
  # DEV: MessagePack will ultimately convert them to strings.
@@ -103,6 +120,7 @@ module Datadog
103
120
  packer
104
121
  end
105
122
  # rubocop:enable Metrics/AbcSize
123
+ # rubocop:enable Metrics/MethodLength
106
124
 
107
125
  # JSON serializer interface.
108
126
  # Used by older version of the transport.
@@ -3,7 +3,7 @@
3
3
  module Datadog
4
4
  module VERSION
5
5
  MAJOR = 2
6
- MINOR = 8
6
+ MINOR = 9
7
7
  PATCH = 0
8
8
  PRE = nil
9
9
  BUILD = nil