datadog 2.16.0 → 2.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -1
  3. data/ext/datadog_profiling_native_extension/encoded_profile.c +22 -12
  4. data/ext/datadog_profiling_native_extension/encoded_profile.h +1 -0
  5. data/ext/datadog_profiling_native_extension/http_transport.c +45 -72
  6. data/ext/datadog_profiling_native_extension/stack_recorder.c +4 -5
  7. data/ext/libdatadog_api/crashtracker.c +10 -3
  8. data/ext/libdatadog_api/macos_development.md +3 -3
  9. data/ext/libdatadog_extconf_helpers.rb +1 -1
  10. data/lib/datadog/appsec/api_security/lru_cache.rb +49 -0
  11. data/lib/datadog/appsec/api_security.rb +9 -0
  12. data/lib/datadog/core/buffer/random.rb +18 -2
  13. data/lib/datadog/core/configuration/agent_settings_resolver.rb +5 -5
  14. data/lib/datadog/core/configuration/components.rb +29 -20
  15. data/lib/datadog/core/configuration/components_state.rb +23 -0
  16. data/lib/datadog/core/configuration/option.rb +18 -18
  17. data/lib/datadog/core/configuration/option_definition.rb +4 -4
  18. data/lib/datadog/core/configuration/options.rb +1 -1
  19. data/lib/datadog/core/configuration/settings.rb +10 -10
  20. data/lib/datadog/core/configuration.rb +16 -16
  21. data/lib/datadog/core/crashtracking/component.rb +2 -1
  22. data/lib/datadog/core/encoding.rb +1 -1
  23. data/lib/datadog/core/environment/cgroup.rb +10 -12
  24. data/lib/datadog/core/environment/container.rb +38 -40
  25. data/lib/datadog/core/environment/ext.rb +6 -6
  26. data/lib/datadog/core/environment/identity.rb +3 -3
  27. data/lib/datadog/core/environment/platform.rb +3 -3
  28. data/lib/datadog/core/error.rb +11 -9
  29. data/lib/datadog/core/logger.rb +2 -2
  30. data/lib/datadog/core/metrics/client.rb +12 -14
  31. data/lib/datadog/core/metrics/logging.rb +5 -5
  32. data/lib/datadog/core/rate_limiter.rb +4 -2
  33. data/lib/datadog/core/remote/client.rb +32 -31
  34. data/lib/datadog/core/remote/component.rb +3 -3
  35. data/lib/datadog/core/remote/configuration/digest.rb +7 -7
  36. data/lib/datadog/core/remote/configuration/path.rb +1 -1
  37. data/lib/datadog/core/remote/transport/http/client.rb +1 -1
  38. data/lib/datadog/core/remote/transport/http/config.rb +21 -5
  39. data/lib/datadog/core/remote/transport/http/negotiation.rb +1 -1
  40. data/lib/datadog/core/runtime/metrics.rb +3 -3
  41. data/lib/datadog/core/telemetry/component.rb +39 -24
  42. data/lib/datadog/core/telemetry/emitter.rb +7 -1
  43. data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +65 -0
  44. data/lib/datadog/core/telemetry/event/app_closing.rb +18 -0
  45. data/lib/datadog/core/telemetry/event/app_dependencies_loaded.rb +33 -0
  46. data/lib/datadog/core/telemetry/event/app_heartbeat.rb +18 -0
  47. data/lib/datadog/core/telemetry/event/app_integrations_change.rb +58 -0
  48. data/lib/datadog/core/telemetry/event/app_started.rb +179 -0
  49. data/lib/datadog/core/telemetry/event/base.rb +40 -0
  50. data/lib/datadog/core/telemetry/event/distributions.rb +18 -0
  51. data/lib/datadog/core/telemetry/event/generate_metrics.rb +43 -0
  52. data/lib/datadog/core/telemetry/event/log.rb +76 -0
  53. data/lib/datadog/core/telemetry/event/message_batch.rb +42 -0
  54. data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +43 -0
  55. data/lib/datadog/core/telemetry/event.rb +17 -475
  56. data/lib/datadog/core/telemetry/logger.rb +1 -1
  57. data/lib/datadog/core/telemetry/metric.rb +3 -3
  58. data/lib/datadog/core/telemetry/transport/http/telemetry.rb +2 -2
  59. data/lib/datadog/core/telemetry/transport/telemetry.rb +0 -1
  60. data/lib/datadog/core/telemetry/worker.rb +48 -27
  61. data/lib/datadog/core/transport/http/adapters/test.rb +2 -1
  62. data/lib/datadog/core/transport/http/builder.rb +13 -13
  63. data/lib/datadog/core/utils/at_fork_monkey_patch.rb +6 -6
  64. data/lib/datadog/core/utils/duration.rb +32 -32
  65. data/lib/datadog/core/utils/forking.rb +2 -2
  66. data/lib/datadog/core/utils/network.rb +6 -6
  67. data/lib/datadog/core/utils/only_once_successful.rb +16 -5
  68. data/lib/datadog/core/utils/time.rb +10 -2
  69. data/lib/datadog/core/utils/truncation.rb +21 -0
  70. data/lib/datadog/core/vendor/multipart-post/multipart/post/composite_read_io.rb +1 -1
  71. data/lib/datadog/core/vendor/multipart-post/multipart/post/multipartable.rb +8 -8
  72. data/lib/datadog/core/vendor/multipart-post/multipart/post/parts.rb +7 -7
  73. data/lib/datadog/core/worker.rb +1 -1
  74. data/lib/datadog/core/workers/async.rb +9 -10
  75. data/lib/datadog/error_tracking/component.rb +2 -2
  76. data/lib/datadog/profiling/collectors/code_provenance.rb +1 -1
  77. data/lib/datadog/profiling/ext.rb +0 -1
  78. data/lib/datadog/profiling/flush.rb +1 -1
  79. data/lib/datadog/profiling/http_transport.rb +1 -6
  80. data/lib/datadog/profiling/scheduler.rb +8 -1
  81. data/lib/datadog/profiling/tag_builder.rb +1 -5
  82. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +4 -1
  83. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +33 -0
  84. data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +4 -0
  85. data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +2 -4
  86. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +10 -0
  87. data/lib/datadog/tracing/contrib/aws/parsed_context.rb +5 -1
  88. data/lib/datadog/tracing/contrib/http/instrumentation.rb +1 -5
  89. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +1 -5
  90. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +1 -5
  91. data/lib/datadog/tracing/contrib/patcher.rb +5 -2
  92. data/lib/datadog/tracing/contrib/support.rb +28 -0
  93. data/lib/datadog/tracing/metadata/errors.rb +4 -4
  94. data/lib/datadog/version.rb +1 -1
  95. metadata +23 -6
@@ -17,8 +17,6 @@ module Datadog
17
17
  DEFAULT_BUFFER_MAX_SIZE = 1000
18
18
  APP_STARTED_EVENT_RETRIES = 10
19
19
 
20
- TELEMETRY_STARTED_ONCE = Utils::OnlyOnceSuccessful.new(APP_STARTED_EVENT_RETRIES)
21
-
22
20
  def initialize(
23
21
  heartbeat_interval_seconds:,
24
22
  metrics_aggregation_interval_seconds:,
@@ -48,16 +46,22 @@ module Datadog
48
46
  @buffer_size = buffer_size
49
47
 
50
48
  self.buffer = buffer_klass.new(@buffer_size)
49
+
50
+ @initial_event_once = Utils::OnlyOnceSuccessful.new(APP_STARTED_EVENT_RETRIES)
51
51
  end
52
52
 
53
53
  attr_reader :logger
54
+ attr_reader :initial_event_once
55
+ attr_reader :initial_event
54
56
 
55
57
  # Returns true if worker thread is successfully started,
56
58
  # false if worker thread was not started but telemetry is enabled,
57
59
  # nil if telemetry is disabled.
58
- def start
60
+ def start(initial_event)
59
61
  return if !enabled? || forked?
60
62
 
63
+ @initial_event = initial_event
64
+
61
65
  # starts async worker
62
66
  # perform should return true if thread was actually started,
63
67
  # false otherwise
@@ -81,12 +85,16 @@ module Datadog
81
85
  true
82
86
  end
83
87
 
84
- def sent_started_event?
85
- TELEMETRY_STARTED_ONCE.success?
88
+ def sent_initial_event?
89
+ initial_event_once.success?
90
+ end
91
+
92
+ def failed_initial_event?
93
+ initial_event_once.failed?
86
94
  end
87
95
 
88
- def failed_to_start?
89
- TELEMETRY_STARTED_ONCE.failed?
96
+ def need_initial_event?
97
+ !sent_initial_event? && !failed_initial_event?
90
98
  end
91
99
 
92
100
  # Wait for the worker to send out all events that have already
@@ -114,7 +122,7 @@ module Datadog
114
122
  # Note that the first wait interval between telemetry event
115
123
  # sending is 10 seconds, the timeout needs to be strictly
116
124
  # greater than that.
117
- return true if buffer.empty? && !in_iteration? && TELEMETRY_STARTED_ONCE.success?
125
+ return true if buffer.empty? && !in_iteration? && sent_initial_event?
118
126
 
119
127
  sleep 0.5
120
128
 
@@ -127,11 +135,26 @@ module Datadog
127
135
  def perform(*events)
128
136
  return if !enabled? || forked?
129
137
 
130
- started! unless sent_started_event?
138
+ if need_initial_event?
139
+ started!
140
+ unless sent_initial_event?
141
+ # We still haven't succeeded in sending the started event,
142
+ # which will make flush_events do nothing - but the events
143
+ # given to us as the parameter have already been removed
144
+ # from the queue.
145
+ # Put the events back to the front of the queue to not
146
+ # lose them.
147
+ buffer.unshift(*events)
148
+ return
149
+ end
150
+ end
131
151
 
132
152
  metric_events = @metrics_manager.flush!
133
153
  events = [] if events.nil?
134
- flush_events(events + metric_events)
154
+ events += metric_events
155
+ if events.any?
156
+ flush_events(events)
157
+ end
135
158
 
136
159
  @current_ticks += 1
137
160
  return if @current_ticks < @ticks_per_heartbeat
@@ -141,11 +164,6 @@ module Datadog
141
164
  end
142
165
 
143
166
  def flush_events(events)
144
- return if events.empty?
145
- # TODO: can this method silently drop events which are
146
- # generated prior to the started event being submitted?
147
- return if !enabled? || !sent_started_event?
148
-
149
167
  events = deduplicate_logs(events)
150
168
 
151
169
  logger.debug { "Sending #{events&.count} telemetry events" }
@@ -153,7 +171,7 @@ module Datadog
153
171
  end
154
172
 
155
173
  def heartbeat!
156
- return if !enabled? || !sent_started_event?
174
+ return if !enabled? || !sent_initial_event?
157
175
 
158
176
  send_event(Event::AppHeartbeat.new)
159
177
  end
@@ -161,26 +179,29 @@ module Datadog
161
179
  def started!
162
180
  return unless enabled?
163
181
 
164
- if failed_to_start?
165
- logger.debug('Telemetry app-started event exhausted retries, disabling telemetry worker')
166
- disable!
167
- return
168
- end
169
-
170
- TELEMETRY_STARTED_ONCE.run do
171
- res = send_event(Event::AppStarted.new)
182
+ initial_event_once.run do
183
+ res = send_event(initial_event)
172
184
 
173
185
  if res.ok?
174
- logger.debug('Telemetry app-started event is successfully sent')
186
+ logger.debug { "Telemetry initial event (#{initial_event.type}) is successfully sent" }
175
187
 
176
- send_event(Event::AppDependenciesLoaded.new) if @dependency_collection
188
+ # TODO Dependencies loaded event should probably check for new
189
+ # dependencies and send the new ones.
190
+ # System tests demand only one instance of this event per
191
+ # dependency.
192
+ send_event(Event::AppDependenciesLoaded.new) if @dependency_collection && initial_event.class.eql?(Telemetry::Event::AppStarted) # standard:disable Style/ClassEqualityComparison:
177
193
 
178
194
  true
179
195
  else
180
- logger.debug('Error sending telemetry app-started event, retry after heartbeat interval...')
196
+ logger.debug("Error sending telemetry initial event (#{initial_event.type}), retry after heartbeat interval...")
181
197
  false
182
198
  end
183
199
  end
200
+
201
+ if failed_initial_event?
202
+ logger.debug { "Telemetry initial event (#{initial_event.type}) exhausted retries, disabling telemetry worker" }
203
+ disable!
204
+ end
184
205
  end
185
206
 
186
207
  def send_event(event)
@@ -38,7 +38,8 @@ module Datadog
38
38
  @status = status
39
39
  end
40
40
 
41
- def url; end
41
+ def url
42
+ end
42
43
 
43
44
  # Response for test adapter
44
45
  class Response
@@ -41,19 +41,19 @@ module Datadog
41
41
 
42
42
  def adapter(config, *args, **kwargs)
43
43
  @default_adapter = case config
44
- when Core::Configuration::AgentSettingsResolver::AgentSettings
45
- registry_klass = REGISTRY.get(config.adapter)
46
- raise UnknownAdapterError, config.adapter if registry_klass.nil?
47
-
48
- registry_klass.build(config)
49
- when Symbol
50
- registry_klass = REGISTRY.get(config)
51
- raise UnknownAdapterError, config if registry_klass.nil?
52
-
53
- registry_klass.new(*args, **kwargs)
54
- else
55
- config
56
- end
44
+ when Core::Configuration::AgentSettingsResolver::AgentSettings
45
+ registry_klass = REGISTRY.get(config.adapter)
46
+ raise UnknownAdapterError, config.adapter if registry_klass.nil?
47
+
48
+ registry_klass.build(config)
49
+ when Symbol
50
+ registry_klass = REGISTRY.get(config)
51
+ raise UnknownAdapterError, config if registry_klass.nil?
52
+
53
+ registry_klass.new(*args, **kwargs)
54
+ else
55
+ config
56
+ end
57
57
  end
58
58
 
59
59
  def headers(values = {})
@@ -51,13 +51,13 @@ module Datadog
51
51
  def fork
52
52
  # If a block is provided, it must be wrapped to trigger callbacks.
53
53
  child_block = if block_given?
54
- proc do
55
- AtForkMonkeyPatch.run_at_fork_blocks(:child)
54
+ proc do
55
+ AtForkMonkeyPatch.run_at_fork_blocks(:child)
56
56
 
57
- # Invoke original block
58
- yield
59
- end
60
- end
57
+ # Invoke original block
58
+ yield
59
+ end
60
+ end
61
61
 
62
62
  # Start fork
63
63
  # If a block is provided, use the wrapped version.
@@ -7,42 +7,42 @@ module Datadog
7
7
  module Duration
8
8
  def self.call(value, base: :s)
9
9
  cast = if value.include?('.')
10
- method(:Float)
11
- else
12
- method(:Integer)
13
- end
10
+ method(:Float)
11
+ else
12
+ method(:Integer)
13
+ end
14
14
 
15
15
  scale = case base
16
- when :s
17
- 1_000_000_000
18
- when :ms
19
- 1_000_000
20
- when :us
21
- 1000
22
- when :ns
23
- 1
24
- else
25
- raise ArgumentError, "invalid base: #{base.inspect}"
26
- end
16
+ when :s
17
+ 1_000_000_000
18
+ when :ms
19
+ 1_000_000
20
+ when :us
21
+ 1000
22
+ when :ns
23
+ 1
24
+ else
25
+ raise ArgumentError, "invalid base: #{base.inspect}"
26
+ end
27
27
 
28
28
  result = case value
29
- when /^(\d+(?:\.\d+)?)h$/
30
- cast.call(Regexp.last_match(1)) * 1_000_000_000 * 60 * 60 / scale
31
- when /^(\d+(?:\.\d+)?)m$/
32
- cast.call(Regexp.last_match(1)) * 1_000_000_000 * 60 / scale
33
- when /^(\d+(?:\.\d+)?)s$/
34
- cast.call(Regexp.last_match(1)) * 1_000_000_000 / scale
35
- when /^(\d+(?:\.\d+)?)ms$/
36
- cast.call(Regexp.last_match(1)) * 1_000_000 / scale
37
- when /^(\d+(?:\.\d+)?)us$/
38
- cast.call(Regexp.last_match(1)) * 1_000 / scale
39
- when /^(\d+(?:\.\d+)?)ns$/
40
- cast.call(Regexp.last_match(1)) / scale
41
- when /^(\d+(?:\.\d+)?)$/
42
- cast.call(Regexp.last_match(1))
43
- else
44
- raise ArgumentError, "invalid duration: #{value.inspect}"
45
- end
29
+ when /^(\d+(?:\.\d+)?)h$/
30
+ cast.call(Regexp.last_match(1)) * 1_000_000_000 * 60 * 60 / scale
31
+ when /^(\d+(?:\.\d+)?)m$/
32
+ cast.call(Regexp.last_match(1)) * 1_000_000_000 * 60 / scale
33
+ when /^(\d+(?:\.\d+)?)s$/
34
+ cast.call(Regexp.last_match(1)) * 1_000_000_000 / scale
35
+ when /^(\d+(?:\.\d+)?)ms$/
36
+ cast.call(Regexp.last_match(1)) * 1_000_000 / scale
37
+ when /^(\d+(?:\.\d+)?)us$/
38
+ cast.call(Regexp.last_match(1)) * 1_000 / scale
39
+ when /^(\d+(?:\.\d+)?)ns$/
40
+ cast.call(Regexp.last_match(1)) / scale
41
+ when /^(\d+(?:\.\d+)?)$/
42
+ cast.call(Regexp.last_match(1))
43
+ else
44
+ raise ArgumentError, "invalid duration: #{value.inspect}"
45
+ end
46
46
  # @type var result: Numeric
47
47
  result.round
48
48
  end
@@ -47,12 +47,12 @@ module Datadog
47
47
  # This wrapper prevents this by initializing the fork PID when the object is created.
48
48
  if RUBY_VERSION >= '3'
49
49
  def initialize(*args, **kwargs, &block)
50
- super(*args, **kwargs, &block)
50
+ super
51
51
  update_fork_pid!
52
52
  end
53
53
  else
54
54
  def initialize(*args, &block)
55
- super(*args, &block)
55
+ super
56
56
  update_fork_pid!
57
57
  end
58
58
  end
@@ -32,7 +32,7 @@ module Datadog
32
32
  def stripped_ip_from_request_headers(headers, ip_headers_to_check: DEFAULT_IP_HEADERS_NAMES)
33
33
  ip = ip_header(headers, ip_headers_to_check)
34
34
 
35
- ip ? ip.to_s : nil
35
+ ip&.to_s
36
36
  end
37
37
 
38
38
  # @param [String] IP value.
@@ -40,7 +40,7 @@ module Datadog
40
40
  # @return [nil] when no valid IP value found.
41
41
  def stripped_ip(ip)
42
42
  ip = ip_to_ipaddr(ip)
43
- ip ? ip.to_s : nil
43
+ ip&.to_s
44
44
  end
45
45
 
46
46
  private
@@ -52,10 +52,10 @@ module Datadog
52
52
  return unless ip
53
53
 
54
54
  clean_ip = if likely_ipv4?(ip)
55
- strip_ipv4_port(ip)
56
- else
57
- strip_zone_specifier(strip_ipv6_port(ip))
58
- end
55
+ strip_ipv4_port(ip)
56
+ else
57
+ strip_zone_specifier(strip_ipv6_port(ip))
58
+ end
59
59
 
60
60
  begin
61
61
  IPAddr.new(clean_ip)
@@ -5,14 +5,25 @@ require_relative 'only_once'
5
5
  module Datadog
6
6
  module Core
7
7
  module Utils
8
- # Helper class to execute something with only one success.
8
+ # Helper class to execute something with only one successful execution.
9
9
  #
10
- # This is useful for cases where we want to ensure that a block of code is only executed once, and only if it
11
- # succeeds. One such example is sending app-started telemetry event.
10
+ # If limit is not provided to the constructor, +run+ will execute the
11
+ # block an unlimited number of times until the block indicates that it
12
+ # executed successfully by returning a truthy value. After a block
13
+ # executes successfully, subsequent +run+ calls will not invoke the
14
+ # block.
12
15
  #
13
- # Successful execution is determined by the return value of the block: any truthy value is considered success.
16
+ # If a non-zero limit is provided to the constructor, +run+ will
17
+ # execute the block up to that many times, and will mark the instance
18
+ # of OnlyOneSuccessful as failed if none of the executions succeeded.
14
19
  #
15
- # Thread-safe when used correctly (e.g. be careful of races when lazily initializing instances of this class).
20
+ # One consumer of this class is sending the app-started telemetry event.
21
+ #
22
+ # Successful execution is determined by the return value of the block:
23
+ # any truthy value is considered success.
24
+ #
25
+ # This class is thread-safe (however, instances of it must also be
26
+ # created in a thread-safe manner).
16
27
  #
17
28
  # Note: In its current state, this class is not Ractor-safe.
18
29
  # In https://github.com/DataDog/dd-trace-rb/pull/1398#issuecomment-797378810 we have a discussion of alternatives,
@@ -35,7 +35,11 @@ module Datadog
35
35
  # Avoid method redefinition warning.
36
36
  # `rescue nil` is added in case customers remove the method
37
37
  # themselves to squelch the warning.
38
- remove_method(:now) rescue nil
38
+ begin
39
+ remove_method(:now)
40
+ rescue
41
+ nil
42
+ end
39
43
  end
40
44
  define_singleton_method(:now, &block)
41
45
  end
@@ -53,7 +57,11 @@ module Datadog
53
57
  # Avoid method redefinition warning
54
58
  # `rescue nil` is added in case customers remove the method
55
59
  # themselves to squelch the warning.
56
- remove_method(:get_time) rescue nil
60
+ begin
61
+ remove_method(:get_time)
62
+ rescue
63
+ nil
64
+ end
57
65
  end
58
66
  define_singleton_method(:get_time, &block)
59
67
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module Core
5
+ module Utils
6
+ # Helper methods for truncating data
7
+ module Truncation
8
+ module_function
9
+
10
+ def truncate_in_middle(string, max_prefix_length, max_suffix_length)
11
+ max_length = max_prefix_length + 3 + max_suffix_length
12
+ if string.length > max_length
13
+ "#{string[0...max_prefix_length]}...#{string[-max_suffix_length..-1]}"
14
+ else
15
+ string
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -108,7 +108,7 @@ module Datadog
108
108
  end
109
109
 
110
110
  def respond_to?(meth, include_all = false)
111
- @io.respond_to?(meth, include_all) || super(meth, include_all)
111
+ @io.respond_to?(meth, include_all) || super
112
112
  end
113
113
  end
114
114
  end
@@ -28,29 +28,29 @@ module Datadog
28
28
  "--#{SecureRandom.uuid}"
29
29
  end
30
30
 
31
- def initialize(path, params, headers={}, boundary = Multipartable.secure_boundary)
31
+ def initialize(path, params, headers = {}, boundary = Multipartable.secure_boundary)
32
32
  headers = headers.clone # don't want to modify the original variable
33
33
  parts_headers = headers.delete(:parts) || {}
34
34
  super(path, headers)
35
- parts = params.map do |k,v|
35
+ parts = params.map do |k, v|
36
36
  case v
37
37
  when Array
38
- v.map {|item| Parts::Part.new(boundary, "#{k}[]", item, parts_headers[k]) }
38
+ v.map { |item| Parts::Part.new(boundary, "#{k}[]", item, parts_headers[k]) }
39
39
  else
40
40
  Parts::Part.new(boundary, k, v, parts_headers[k])
41
41
  end
42
42
  end.flatten
43
43
  parts << Parts::EpiloguePart.new(boundary)
44
- ios = parts.map {|p| p.to_io }
45
- self.set_content_type(headers["Content-Type"] || "multipart/form-data",
46
- { "boundary" => boundary })
47
- self.content_length = parts.inject(0) {|sum,i| sum + i.length }
44
+ ios = parts.map { |p| p.to_io }
45
+ set_content_type(headers["Content-Type"] || "multipart/form-data",
46
+ {"boundary" => boundary})
47
+ self.content_length = parts.inject(0) { |sum, i| sum + i.length }
48
48
  self.body_stream = CompositeReadIO.new(*ios)
49
49
 
50
50
  @boundary = boundary
51
51
  end
52
52
 
53
- attr :boundary
53
+ attr_reader :boundary
54
54
  end
55
55
  end
56
56
  end
@@ -58,7 +58,7 @@ module Datadog
58
58
  part = ''
59
59
  part << "--#{boundary}\r\n"
60
60
  part << "Content-ID: #{headers["Content-ID"]}\r\n" if headers["Content-ID"]
61
- part << "Content-Disposition: form-data; name=\"#{name.to_s}\"\r\n"
61
+ part << "Content-Disposition: form-data; name=\"#{name}\"\r\n"
62
62
  part << "Content-Type: #{headers["Content-Type"]}\r\n" if headers["Content-Type"]
63
63
  part << "\r\n"
64
64
  part << "#{value}\r\n"
@@ -76,9 +76,9 @@ module Datadog
76
76
  # @param io [IO]
77
77
  # @param headers [Hash]
78
78
  def initialize(boundary, name, io, headers = {})
79
- file_length = io.respond_to?(:length) ? io.length : File.size(io.local_path)
79
+ file_length = io.respond_to?(:length) ? io.length : File.size(io.local_path)
80
80
  @head = build_head(boundary, name, io.original_filename, io.content_type, file_length,
81
- io.respond_to?(:opts) ? io.opts.merge(headers) : headers)
81
+ io.respond_to?(:opts) ? io.opts.merge(headers) : headers)
82
82
  @foot = "\r\n"
83
83
  @length = @head.bytesize + file_length + @foot.length
84
84
  @io = CompositeReadIO.new(StringIO.new(@head), io, StringIO.new(@foot))
@@ -98,16 +98,16 @@ module Datadog
98
98
 
99
99
  part = ''
100
100
  part << "--#{boundary}\r\n"
101
- part << "Content-Disposition: #{content_disposition}; name=\"#{name.to_s}\"; filename=\"#{filename}\"\r\n"
101
+ part << "Content-Disposition: #{content_disposition}; name=\"#{name}\"; filename=\"#{filename}\"\r\n"
102
102
  part << "Content-Length: #{content_len}\r\n"
103
103
  if content_id = opts.delete("Content-ID")
104
104
  part << "Content-ID: #{content_id}\r\n"
105
105
  end
106
106
 
107
- if opts["Content-Type"] != nil
108
- part << "Content-Type: " + opts["Content-Type"] + "\r\n"
107
+ part << if !opts["Content-Type"].nil?
108
+ "Content-Type: " + opts["Content-Type"] + "\r\n"
109
109
  else
110
- part << "Content-Type: #{type}\r\n"
110
+ "Content-Type: #{type}\r\n"
111
111
  end
112
112
 
113
113
  part << "Content-Transfer-Encoding: #{trans_encoding}\r\n"
@@ -12,7 +12,7 @@ module Datadog
12
12
  end
13
13
 
14
14
  def perform(*args)
15
- task.call(*args) unless task.nil?
15
+ task&.call(*args)
16
16
  end
17
17
 
18
18
  protected
@@ -154,16 +154,15 @@ module Datadog
154
154
  Datadog.logger.debug { "Starting thread for: #{self}" }
155
155
 
156
156
  @worker = ::Thread.new do
157
- begin
158
- yield
159
- # rubocop:disable Lint/RescueException
160
- rescue Exception => e
161
- @error = e
162
- Datadog.logger.debug(
163
- "Worker thread error. Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
164
- )
165
- raise
166
- end
157
+ yield
158
+ # rubocop:disable Lint/RescueException
159
+ rescue Exception => e
160
+ @error = e
161
+ Datadog.logger.debug(
162
+ "Worker thread error. Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
163
+ )
164
+ raise
165
+
167
166
  # rubocop:enable Lint/RescueException
168
167
  end
169
168
  @worker.name = self.class.name
@@ -33,9 +33,9 @@ module Datadog
33
33
  if RUBY_ENGINE != 'ruby'
34
34
  logger.warn("error tracking: cannot enable error tracking: MRI is required, but running on #{RUBY_ENGINE}")
35
35
  false
36
- elsif RUBY_VERSION < '2.6'
36
+ elsif RUBY_VERSION < '2.7'
37
37
  logger.warn(
38
- "error tracking: cannot enable error tracking: Ruby 2.6+ is required, but running
38
+ "error tracking: cannot enable error tracking: Ruby 2.7+ is required, but running
39
39
  on #{RUBY_VERSION}"
40
40
  )
41
41
  false
@@ -42,7 +42,7 @@ module Datadog
42
42
  end
43
43
 
44
44
  def generate_json
45
- JSON.fast_generate(v1: seen_libraries.to_a)
45
+ JSON.generate(v1: seen_libraries.to_a)
46
46
  end
47
47
 
48
48
  private
@@ -19,7 +19,6 @@ module Datadog
19
19
  FORM_FIELD_TAG_RUNTIME = "runtime"
20
20
  FORM_FIELD_TAG_RUNTIME_ENGINE = "runtime_engine"
21
21
  FORM_FIELD_TAG_RUNTIME_ID = "runtime-id"
22
- FORM_FIELD_TAG_RUNTIME_PLATFORM = "runtime_platform"
23
22
  FORM_FIELD_TAG_RUNTIME_VERSION = "runtime_version"
24
23
  FORM_FIELD_TAG_SERVICE = "service"
25
24
  FORM_FIELD_TAG_VERSION = "version"
@@ -32,7 +32,7 @@ module Datadog
32
32
  @code_provenance_file_name = code_provenance_file_name
33
33
  @code_provenance_data = code_provenance_data
34
34
  @tags_as_array = tags_as_array
35
- @internal_metadata_json = JSON.fast_generate(internal_metadata)
35
+ @internal_metadata_json = JSON.generate(internal_metadata)
36
36
  @info_json = info_json
37
37
  end
38
38
  end
@@ -29,12 +29,7 @@ module Datadog
29
29
  status, result = self.class._native_do_export(
30
30
  exporter_configuration,
31
31
  @upload_timeout_milliseconds,
32
- flush,
33
- # TODO: This is going to be removed once we move to libdatadog 17
34
- flush.start.tv_sec,
35
- flush.start.tv_nsec,
36
- flush.finish.tv_sec,
37
- flush.finish.tv_nsec,
32
+ flush
38
33
  )
39
34
 
40
35
  if status == :ok
@@ -37,6 +37,7 @@ module Datadog
37
37
  @exporter = exporter
38
38
  @transport = transport
39
39
  @profiler_failed = false
40
+ @stop_requested = false
40
41
 
41
42
  # Workers::Async::Thread settings
42
43
  self.fork_policy = fork_policy
@@ -88,7 +89,7 @@ module Datadog
88
89
  end
89
90
 
90
91
  def work_pending?
91
- !profiler_failed && exporter.can_flush?
92
+ !profiler_failed && exporter.can_flush? && (run_loop? || !stop_requested?)
92
93
  end
93
94
 
94
95
  def reset_after_fork
@@ -138,8 +139,14 @@ module Datadog
138
139
  Datadog::Core::Telemetry::Logger.report(e, description: "Unable to report profile")
139
140
  end
140
141
 
142
+ @stop_requested = !run_loop?
143
+
141
144
  true
142
145
  end
146
+
147
+ def stop_requested?
148
+ @stop_requested
149
+ end
143
150
  end
144
151
  end
145
152
  end