ddtrace 1.0.0 → 1.1.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 (122) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -16
  3. data/CHANGELOG.md +31 -2
  4. data/LICENSE-3rdparty.csv +3 -2
  5. data/README.md +2 -2
  6. data/ddtrace.gemspec +12 -3
  7. data/docs/GettingStarted.md +19 -2
  8. data/docs/ProfilingDevelopment.md +8 -8
  9. data/docs/UpgradeGuide.md +3 -3
  10. data/ext/ddtrace_profiling_loader/ddtrace_profiling_loader.c +118 -0
  11. data/ext/ddtrace_profiling_loader/extconf.rb +53 -0
  12. data/ext/ddtrace_profiling_native_extension/NativeExtensionDesign.md +31 -5
  13. data/ext/ddtrace_profiling_native_extension/clock_id_from_pthread.c +0 -8
  14. data/ext/ddtrace_profiling_native_extension/collectors_stack.c +278 -0
  15. data/ext/ddtrace_profiling_native_extension/extconf.rb +70 -100
  16. data/ext/ddtrace_profiling_native_extension/libddprof_helpers.h +13 -0
  17. data/ext/ddtrace_profiling_native_extension/native_extension_helpers.rb +186 -0
  18. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.c +579 -7
  19. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.h +30 -0
  20. data/ext/ddtrace_profiling_native_extension/profiling.c +7 -0
  21. data/ext/ddtrace_profiling_native_extension/stack_recorder.c +139 -0
  22. data/ext/ddtrace_profiling_native_extension/stack_recorder.h +28 -0
  23. data/lib/datadog/appsec/autoload.rb +2 -2
  24. data/lib/datadog/appsec/configuration/settings.rb +19 -0
  25. data/lib/datadog/appsec/configuration.rb +8 -0
  26. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +76 -33
  27. data/lib/datadog/appsec/contrib/rack/integration.rb +1 -0
  28. data/lib/datadog/appsec/contrib/rack/patcher.rb +0 -1
  29. data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +64 -0
  30. data/lib/datadog/appsec/contrib/rack/request.rb +6 -0
  31. data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +41 -0
  32. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +60 -5
  33. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +81 -0
  34. data/lib/datadog/appsec/contrib/rails/patcher.rb +34 -1
  35. data/lib/datadog/appsec/contrib/rails/reactive/action.rb +68 -0
  36. data/lib/datadog/appsec/contrib/rails/request.rb +33 -0
  37. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +124 -0
  38. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +69 -2
  39. data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +63 -0
  40. data/lib/datadog/appsec/event.rb +33 -18
  41. data/lib/datadog/appsec/extensions.rb +0 -3
  42. data/lib/datadog/appsec/processor.rb +45 -2
  43. data/lib/datadog/appsec/rate_limiter.rb +5 -0
  44. data/lib/datadog/appsec/reactive/operation.rb +0 -1
  45. data/lib/datadog/ci/ext/environment.rb +21 -7
  46. data/lib/datadog/core/configuration/agent_settings_resolver.rb +1 -1
  47. data/lib/datadog/core/configuration/components.rb +22 -4
  48. data/lib/datadog/core/configuration/settings.rb +3 -3
  49. data/lib/datadog/core/configuration.rb +7 -5
  50. data/lib/datadog/core/environment/cgroup.rb +3 -1
  51. data/lib/datadog/core/environment/container.rb +2 -1
  52. data/lib/datadog/core/environment/variable_helpers.rb +26 -2
  53. data/lib/datadog/core/logging/ext.rb +11 -0
  54. data/lib/datadog/core/metrics/client.rb +15 -5
  55. data/lib/datadog/core/runtime/metrics.rb +1 -1
  56. data/lib/datadog/core/workers/async.rb +3 -1
  57. data/lib/datadog/core/workers/runtime_metrics.rb +0 -3
  58. data/lib/datadog/core.rb +6 -0
  59. data/lib/datadog/kit/enable_core_dumps.rb +50 -0
  60. data/lib/datadog/kit/identity.rb +63 -0
  61. data/lib/datadog/kit.rb +11 -0
  62. data/lib/datadog/opentracer/tracer.rb +0 -2
  63. data/lib/datadog/profiling/collectors/old_stack.rb +298 -0
  64. data/lib/datadog/profiling/collectors/stack.rb +6 -287
  65. data/lib/datadog/profiling/encoding/profile.rb +0 -1
  66. data/lib/datadog/profiling/ext.rb +1 -1
  67. data/lib/datadog/profiling/flush.rb +1 -1
  68. data/lib/datadog/profiling/load_native_extension.rb +22 -0
  69. data/lib/datadog/profiling/recorder.rb +1 -1
  70. data/lib/datadog/profiling/scheduler.rb +1 -1
  71. data/lib/datadog/profiling/stack_recorder.rb +33 -0
  72. data/lib/datadog/profiling/tag_builder.rb +48 -0
  73. data/lib/datadog/profiling/tasks/exec.rb +2 -2
  74. data/lib/datadog/profiling/tasks/setup.rb +6 -4
  75. data/lib/datadog/profiling.rb +29 -27
  76. data/lib/datadog/tracing/buffer.rb +9 -3
  77. data/lib/datadog/tracing/contrib/action_view/patcher.rb +0 -1
  78. data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +2 -2
  79. data/lib/datadog/tracing/contrib/active_record/utils.rb +1 -1
  80. data/lib/datadog/tracing/contrib/active_record/vendor/connection_specification.rb +1 -1
  81. data/lib/datadog/tracing/contrib/active_support/notifications/subscription.rb +4 -2
  82. data/lib/datadog/tracing/contrib/concurrent_ruby/context_composite_executor_service.rb +10 -3
  83. data/lib/datadog/tracing/contrib/dalli/patcher.rb +0 -1
  84. data/lib/datadog/tracing/contrib/delayed_job/patcher.rb +0 -1
  85. data/lib/datadog/tracing/contrib/elasticsearch/integration.rb +9 -3
  86. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +38 -2
  87. data/lib/datadog/tracing/contrib/ethon/patcher.rb +0 -1
  88. data/lib/datadog/tracing/contrib/extensions.rb +0 -2
  89. data/lib/datadog/tracing/contrib/faraday/patcher.rb +0 -1
  90. data/lib/datadog/tracing/contrib/grape/patcher.rb +0 -1
  91. data/lib/datadog/tracing/contrib/graphql/patcher.rb +0 -1
  92. data/lib/datadog/tracing/contrib/grpc/patcher.rb +0 -1
  93. data/lib/datadog/tracing/contrib/kafka/patcher.rb +0 -1
  94. data/lib/datadog/tracing/contrib/lograge/instrumentation.rb +2 -1
  95. data/lib/datadog/tracing/contrib/qless/patcher.rb +0 -1
  96. data/lib/datadog/tracing/contrib/que/patcher.rb +0 -1
  97. data/lib/datadog/tracing/contrib/racecar/patcher.rb +0 -1
  98. data/lib/datadog/tracing/contrib/rails/log_injection.rb +3 -16
  99. data/lib/datadog/tracing/contrib/rake/instrumentation.rb +2 -2
  100. data/lib/datadog/tracing/contrib/rake/patcher.rb +0 -1
  101. data/lib/datadog/tracing/contrib/redis/patcher.rb +0 -1
  102. data/lib/datadog/tracing/contrib/resque/patcher.rb +0 -1
  103. data/lib/datadog/tracing/contrib/rest_client/patcher.rb +0 -1
  104. data/lib/datadog/tracing/contrib/semantic_logger/instrumentation.rb +2 -1
  105. data/lib/datadog/tracing/contrib/sidekiq/configuration/settings.rb +1 -0
  106. data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +20 -1
  107. data/lib/datadog/tracing/contrib/sinatra/framework.rb +11 -0
  108. data/lib/datadog/tracing/contrib/sinatra/patcher.rb +0 -1
  109. data/lib/datadog/tracing/contrib/sneakers/patcher.rb +0 -1
  110. data/lib/datadog/tracing/contrib/sucker_punch/patcher.rb +0 -1
  111. data/lib/datadog/tracing/event.rb +2 -1
  112. data/lib/datadog/tracing/sampling/priority_sampler.rb +4 -5
  113. data/lib/datadog/tracing/sampling/rule.rb +12 -6
  114. data/lib/datadog/tracing/sampling/rule_sampler.rb +3 -5
  115. data/lib/datadog/tracing/span_operation.rb +2 -3
  116. data/lib/datadog/tracing/trace_operation.rb +0 -1
  117. data/lib/ddtrace/transport/http/client.rb +2 -1
  118. data/lib/ddtrace/transport/http/response.rb +34 -4
  119. data/lib/ddtrace/transport/io/client.rb +3 -1
  120. data/lib/ddtrace/version.rb +1 -1
  121. data/lib/ddtrace.rb +1 -0
  122. metadata +43 -6
@@ -16,9 +16,40 @@ module Datadog
16
16
  end
17
17
  end
18
18
 
19
+ # Context manages a sequence of runs
20
+ class Context
21
+ attr_reader :time_ns, :time_ext_ns, :timeouts, :events
22
+
23
+ def initialize(processor)
24
+ @context = Datadog::AppSec::WAF::Context.new(processor.send(:handle))
25
+ @time_ns = 0.0
26
+ @time_ext_ns = 0.0
27
+ @timeouts = 0
28
+ @events = []
29
+ end
30
+
31
+ def run(*args)
32
+ start_ns = Core::Utils::Time.get_time(:nanosecond)
33
+
34
+ ret, res = @context.run(*args)
35
+
36
+ stop_ns = Core::Utils::Time.get_time(:nanosecond)
37
+
38
+ @time_ns += res.total_runtime
39
+ @time_ext_ns += (stop_ns - start_ns)
40
+ @timeouts += 1 if res.timeout
41
+
42
+ [ret, res]
43
+ end
44
+ end
45
+
46
+ attr_reader :ruleset_info, :addresses
47
+
19
48
  def initialize
20
49
  @ruleset = nil
21
50
  @handle = nil
51
+ @ruleset_info = nil
52
+ @addresses = nil
22
53
 
23
54
  unless load_libddwaf && load_ruleset && create_waf_handle
24
55
  Datadog.logger.warn { 'AppSec is disabled, see logged errors above' }
@@ -30,9 +61,13 @@ module Datadog
30
61
  end
31
62
 
32
63
  def new_context
33
- Datadog::AppSec::WAF::Context.new(@handle)
64
+ Context.new(self)
34
65
  end
35
66
 
67
+ protected
68
+
69
+ attr_reader :handle
70
+
36
71
  private
37
72
 
38
73
  def load_libddwaf
@@ -70,7 +105,13 @@ module Datadog
70
105
  # TODO: this may need to be reset if the main Datadog logging level changes after initialization
71
106
  Datadog::AppSec::WAF.logger = Datadog.logger if Datadog.logger.debug? && Datadog::AppSec.settings.waf_debug
72
107
 
73
- @handle = Datadog::AppSec::WAF::Handle.new(@ruleset)
108
+ obfuscator_config = {
109
+ key_regex: Datadog::AppSec.settings.obfuscator_key_regex,
110
+ value_regex: Datadog::AppSec.settings.obfuscator_value_regex,
111
+ }
112
+ @handle = Datadog::AppSec::WAF::Handle.new(@ruleset, obfuscator: obfuscator_config)
113
+ @ruleset_info = @handle.ruleset_info
114
+ @addresses = @handle.required_addresses
74
115
 
75
116
  true
76
117
  rescue StandardError => e
@@ -78,6 +119,8 @@ module Datadog
78
119
  "libddwaf failed to initialize, error: #{e.inspect}"
79
120
  end
80
121
 
122
+ @ruleset_info = e.ruleset_info if e.respond_to?(:ruleset_info)
123
+
81
124
  false
82
125
  end
83
126
 
@@ -35,6 +35,11 @@ module Datadog
35
35
  rate_limiter(name).limit(&block)
36
36
  end
37
37
 
38
+ # reset a rate limiter: used for testing
39
+ def reset!(name)
40
+ Thread.current[:datadog_security_trace_rate_limiter] = nil
41
+ end
42
+
38
43
  protected
39
44
 
40
45
  def rate_limiter(name)
@@ -1,6 +1,5 @@
1
1
  # typed: true
2
2
 
3
- require 'datadog/appsec'
4
3
  require 'datadog/appsec/reactive/engine'
5
4
 
6
5
  module Datadog
@@ -379,49 +379,63 @@ module Datadog
379
379
  committer_date: Time.at(fields[5].to_i).utc.to_datetime.iso8601
380
380
  }
381
381
  rescue => e
382
- Datadog.logger.debug("Unable to read git commit users: #{e.message} at #{Array(e.backtrace).first}")
382
+ Datadog.logger.debug(
383
+ "Unable to read git commit users: #{e.class.name} #{e.message} at #{Array(e.backtrace).first}"
384
+ )
383
385
  nil
384
386
  end
385
387
 
386
388
  def git_repository_url
387
389
  exec_git_command('git ls-remote --get-url')
388
390
  rescue => e
389
- Datadog.logger.debug("Unable to read git repository url: #{e.message} at #{Array(e.backtrace).first}")
391
+ Datadog.logger.debug(
392
+ "Unable to read git repository url: #{e.class.name} #{e.message} at #{Array(e.backtrace).first}"
393
+ )
390
394
  nil
391
395
  end
392
396
 
393
397
  def git_commit_message
394
398
  exec_git_command('git show -s --format=%s')
395
399
  rescue => e
396
- Datadog.logger.debug("Unable to read git commit message: #{e.message} at #{Array(e.backtrace).first}")
400
+ Datadog.logger.debug(
401
+ "Unable to read git commit message: #{e.class.name} #{e.message} at #{Array(e.backtrace).first}"
402
+ )
397
403
  nil
398
404
  end
399
405
 
400
406
  def git_branch
401
407
  exec_git_command('git rev-parse --abbrev-ref HEAD')
402
408
  rescue => e
403
- Datadog.logger.debug("Unable to read git branch: #{e.message} at #{Array(e.backtrace).first}")
409
+ Datadog.logger.debug(
410
+ "Unable to read git branch: #{e.class.name} #{e.message} at #{Array(e.backtrace).first}"
411
+ )
404
412
  nil
405
413
  end
406
414
 
407
415
  def git_commit_sha
408
416
  exec_git_command('git rev-parse HEAD')
409
417
  rescue => e
410
- Datadog.logger.debug("Unable to read git commit SHA: #{e.message} at #{Array(e.backtrace).first}")
418
+ Datadog.logger.debug(
419
+ "Unable to read git commit SHA: #{e.class.name} #{e.message} at #{Array(e.backtrace).first}"
420
+ )
411
421
  nil
412
422
  end
413
423
 
414
424
  def git_tag
415
425
  exec_git_command('git tag --points-at HEAD')
416
426
  rescue => e
417
- Datadog.logger.debug("Unable to read git tag: #{e.message} at #{Array(e.backtrace).first}")
427
+ Datadog.logger.debug(
428
+ "Unable to read git tag: #{e.class.name} #{e.message} at #{Array(e.backtrace).first}"
429
+ )
418
430
  nil
419
431
  end
420
432
 
421
433
  def git_base_directory
422
434
  exec_git_command('git rev-parse --show-toplevel')
423
435
  rescue => e
424
- Datadog.logger.debug("Unable to read git base directory: #{e.message} at #{Array(e.backtrace).first}")
436
+ Datadog.logger.debug(
437
+ "Unable to read git base directory: #{e.class.name} #{e.message} at #{Array(e.backtrace).first}"
438
+ )
425
439
  nil
426
440
  end
427
441
 
@@ -303,7 +303,7 @@ module Datadog
303
303
  if logger
304
304
  logger.debug do
305
305
  'Could not extract configuration from transport_options proc. ' \
306
- "Cause: #{e.message} Source: #{Array(e.backtrace).first}"
306
+ "Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
307
307
  end
308
308
  end
309
309
 
@@ -11,8 +11,6 @@ require 'datadog/tracing/tracer'
11
11
  require 'datadog/tracing/flush'
12
12
  require 'datadog/tracing/sync_writer'
13
13
 
14
- require 'datadog/profiling'
15
-
16
14
  module Datadog
17
15
  module Core
18
16
  module Configuration
@@ -181,7 +179,27 @@ module Datadog
181
179
  end
182
180
 
183
181
  def build_profiler(settings, agent_settings, tracer)
184
- return unless Profiling.supported? && settings.profiling.enabled
182
+ return unless settings.profiling.enabled
183
+
184
+ # Workaround for weird dependency direction: the Core::Configuration::Components class currently has a
185
+ # dependency on individual products, in this case the Profiler.
186
+ # (Note "currently": in the future we want to change this so core classes don't depend on specific products)
187
+ #
188
+ # If the current file included a `require 'datadog/profiler'` at its beginning, we would generate circular
189
+ # requires when used from profiling:
190
+ #
191
+ # datadog/profiling
192
+ # └─requires─> datadog/core
193
+ # └─requires─> datadog/core/configuration/components
194
+ # └─requires─> datadog/profiling # Loop!
195
+ #
196
+ # ...thus in #1998 we removed such a require.
197
+ #
198
+ # On the other hand, if datadog/core is loaded by a different product and no general `require 'ddtrace'` is
199
+ # done, then profiling may not be loaded, and thus to avoid this issue we do a require here (which is a
200
+ # no-op if profiling is already loaded).
201
+ require 'datadog/profiling'
202
+ return unless Profiling.supported?
185
203
 
186
204
  unless defined?(Profiling::Tasks::Setup)
187
205
  # In #1545 a user reported a NameError due to this constant being uninitialized
@@ -278,7 +296,7 @@ module Datadog
278
296
 
279
297
  def build_profiler_collectors(settings, recorder, trace_identifiers_helper)
280
298
  [
281
- Profiling::Collectors::Stack.new(
299
+ Profiling::Collectors::OldStack.new(
282
300
  recorder,
283
301
  trace_identifiers_helper: trace_identifiers_helper,
284
302
  max_frames: settings.profiling.advanced.max_frames
@@ -305,7 +305,7 @@ module Datadog
305
305
  tags = {}
306
306
 
307
307
  # Parse tags from environment
308
- env_to_list(Core::Environment::Ext::ENV_TAGS).each do |tag|
308
+ env_to_list(Core::Environment::Ext::ENV_TAGS, comma_separated_only: false).each do |tag|
309
309
  pair = tag.split(':')
310
310
  tags[pair.first] = pair.last if pair.length == 2
311
311
  end
@@ -412,7 +412,7 @@ module Datadog
412
412
  Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_DATADOG,
413
413
  Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3,
414
414
  Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_SINGLE_HEADER
415
- ]
415
+ ], comma_separated_only: true
416
416
  )
417
417
  end
418
418
 
@@ -430,7 +430,7 @@ module Datadog
430
430
  o.default do
431
431
  env_to_list(
432
432
  Tracing::Configuration::Ext::Distributed::ENV_PROPAGATION_STYLE_INJECT,
433
- [Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_DATADOG] # Only inject Datadog headers by default
433
+ [Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_DATADOG], comma_separated_only: true # Only inject Datadog headers by default
434
434
  )
435
435
  end
436
436
 
@@ -1,6 +1,5 @@
1
1
  # typed: true
2
2
 
3
- require 'forwardable'
4
3
  require 'datadog/core/configuration/components'
5
4
  require 'datadog/core/configuration/settings'
6
5
  require 'datadog/core/logger'
@@ -11,7 +10,6 @@ module Datadog
11
10
  # Configuration provides a unique access point for configurations
12
11
  module Configuration # rubocop:disable Metrics/ModuleLength
13
12
  include Kernel # Ensure that kernel methods are always available (https://sorbet.org/docs/error-reference#7003)
14
- extend Forwardable
15
13
 
16
14
  # Used to ensure that @components initialization/reconfiguration is performed one-at-a-time, by a single thread.
17
15
  #
@@ -154,9 +152,13 @@ module Datadog
154
152
  pin[option] if pin
155
153
  end
156
154
 
157
- def_delegators \
158
- :components,
159
- :health_metrics
155
+ # Internal {Datadog::Statsd} metrics collection.
156
+ #
157
+ # The list of metrics collected can be found in {Datadog::Core::Diagnostics::Ext::Health::Metrics}.
158
+ # @public_api
159
+ def health_metrics
160
+ components.health_metrics
161
+ end
160
162
 
161
163
  def logger
162
164
  # avoid initializing components if they didn't already exist
@@ -35,7 +35,9 @@ module Datadog
35
35
  end
36
36
  end
37
37
  rescue StandardError => e
38
- Datadog.logger.error("Error while parsing cgroup. Cause: #{e.message} Location: #{Array(e.backtrace).first}")
38
+ Datadog.logger.error(
39
+ "Error while parsing cgroup. Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
40
+ )
39
41
  end
40
42
  end
41
43
  end
@@ -81,7 +81,8 @@ module Datadog
81
81
  end
82
82
  rescue StandardError => e
83
83
  Datadog.logger.error(
84
- "Error while parsing container info. Cause: #{e.message} Location: #{Array(e.backtrace).first}"
84
+ "Error while parsing container info. Cause: #{e.class.name} #{e.message} " \
85
+ "Location: #{Array(e.backtrace).first}"
85
86
  )
86
87
  end
87
88
  end
@@ -24,10 +24,34 @@ module Datadog
24
24
  var && ENV.key?(var) ? ENV[var].to_f : default
25
25
  end
26
26
 
27
- def env_to_list(var, default = [])
27
+ # Parses comma- or space-separated lists.
28
+ #
29
+ # If a comma is present, then the list is considered comma-separated.
30
+ # Otherwise, it is considered space-separated.
31
+ #
32
+ # After the entries are separated, commas and whitespaces that are
33
+ # either trailing or leading are trimmed.
34
+ #
35
+ # Empty entries, after trimmed, are also removed from the result.
36
+ def env_to_list(var, default = [], comma_separated_only:)
28
37
  var = decode_array(var)
29
38
  if var && ENV.key?(var)
30
- ENV[var].split(',').map(&:strip)
39
+ value = ENV[var]
40
+
41
+ values = if value.include?(',') || comma_separated_only
42
+ value.split(',')
43
+ else
44
+ value.split(' ') # rubocop:disable Style/RedundantArgument
45
+ end
46
+
47
+ values.map! do |v|
48
+ v.gsub!(/\A[\s,]*|[\s,]*\Z/, '')
49
+
50
+ v.empty? ? nil : v
51
+ end
52
+
53
+ values.compact!
54
+ values
31
55
  else
32
56
  default
33
57
  end
@@ -0,0 +1,11 @@
1
+ module Datadog
2
+ module Core
3
+ module Logging
4
+ module Ext
5
+ # The technology from which the log originated.
6
+ # @see https://docs.datadoghq.com/api/latest/logs/#send-logs
7
+ DD_SOURCE = 'ruby'.freeze
8
+ end
9
+ end
10
+ end
11
+ end
@@ -96,7 +96,9 @@ module Datadog
96
96
 
97
97
  statsd.count(stat, value, metric_options(options))
98
98
  rescue StandardError => e
99
- Datadog.logger.error("Failed to send count stat. Cause: #{e.message} Source: #{Array(e.backtrace).first}")
99
+ Datadog.logger.error(
100
+ "Failed to send count stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
101
+ )
100
102
  end
101
103
 
102
104
  def distribution(stat, value = nil, options = nil, &block)
@@ -107,7 +109,9 @@ module Datadog
107
109
 
108
110
  statsd.distribution(stat, value, metric_options(options))
109
111
  rescue StandardError => e
110
- Datadog.logger.error("Failed to send distribution stat. Cause: #{e.message} Source: #{Array(e.backtrace).first}")
112
+ Datadog.logger.error(
113
+ "Failed to send distribution stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
114
+ )
111
115
  end
112
116
 
113
117
  def increment(stat, options = nil)
@@ -117,7 +121,9 @@ module Datadog
117
121
 
118
122
  statsd.increment(stat, metric_options(options))
119
123
  rescue StandardError => e
120
- Datadog.logger.error("Failed to send increment stat. Cause: #{e.message} Source: #{Array(e.backtrace).first}")
124
+ Datadog.logger.error(
125
+ "Failed to send increment stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
126
+ )
121
127
  end
122
128
 
123
129
  def gauge(stat, value = nil, options = nil, &block)
@@ -128,7 +134,9 @@ module Datadog
128
134
 
129
135
  statsd.gauge(stat, value, metric_options(options))
130
136
  rescue StandardError => e
131
- Datadog.logger.error("Failed to send gauge stat. Cause: #{e.message} Source: #{Array(e.backtrace).first}")
137
+ Datadog.logger.error(
138
+ "Failed to send gauge stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
139
+ )
132
140
  end
133
141
 
134
142
  def time(stat, options = nil)
@@ -144,7 +152,9 @@ module Datadog
144
152
  distribution(stat, ((finished - start) * 1000), options)
145
153
  end
146
154
  rescue StandardError => e
147
- Datadog.logger.error("Failed to send time stat. Cause: #{e.message} Source: #{Array(e.backtrace).first}")
155
+ Datadog.logger.error(
156
+ "Failed to send time stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
157
+ )
148
158
  end
149
159
  end
150
160
 
@@ -79,7 +79,7 @@ module Datadog
79
79
  def try_flush
80
80
  yield
81
81
  rescue StandardError => e
82
- Datadog.logger.error("Error while sending runtime metric. Cause: #{e.message}")
82
+ Datadog.logger.error("Error while sending runtime metric. Cause: #{e.class.name} #{e.message}")
83
83
  end
84
84
 
85
85
  def default_metric_options
@@ -138,7 +138,9 @@ module Datadog
138
138
  # rubocop:disable Lint/RescueException
139
139
  rescue Exception => e
140
140
  @error = e
141
- Datadog.logger.debug("Worker thread error. Cause #{e.message} Location: #{Array(e.backtrace).first}")
141
+ Datadog.logger.debug(
142
+ "Worker thread error. Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
143
+ )
142
144
  raise
143
145
  end
144
146
  # rubocop:enable Lint/RescueException
@@ -1,7 +1,5 @@
1
1
  # typed: false
2
2
 
3
- require 'forwardable'
4
-
5
3
  require 'datadog/core/runtime/metrics'
6
4
 
7
5
  require 'datadog/core/worker'
@@ -13,7 +11,6 @@ module Datadog
13
11
  module Workers
14
12
  # Emits runtime metrics asynchronously on a timed loop
15
13
  class RuntimeMetrics < Worker
16
- extend Forwardable
17
14
  include Workers::Polling
18
15
 
19
16
  # In seconds
data/lib/datadog/core.rb CHANGED
@@ -59,6 +59,12 @@ require 'datadog/core/extensions'
59
59
  # We must load core extensions to make certain global APIs
60
60
  # accessible: both for Datadog features and the core itself.
61
61
  module Datadog
62
+ # Common, lower level, internal code used (or usable) by two or more
63
+ # products. It is a dependency of each product. Contrast with Datadog::Kit
64
+ # for higher-level features.
65
+ module Core
66
+ end
67
+
62
68
  extend Core::Extensions
63
69
 
64
70
  # Add shutdown hook:
@@ -0,0 +1,50 @@
1
+ # typed: ignore
2
+
3
+ module Datadog
4
+ module Kit
5
+ # This helper is used to enable core dumps for the current Ruby app. This is useful when debugging native-level
6
+ # crashes.
7
+ #
8
+ # It can be enabled simply by adding `require 'datadog/kit/enable_core_dumps'` to start of the app.
9
+ module EnableCoreDumps
10
+ def self.call
11
+ current_size, maximum_size = Process.getrlimit(:CORE)
12
+ core_pattern =
13
+ begin
14
+ File.read('/proc/sys/kernel/core_pattern').strip
15
+ rescue
16
+ '(Could not open /proc/sys/kernel/core_pattern)'
17
+ end
18
+
19
+ if maximum_size <= 0
20
+ Kernel.warn("[DDTRACE] Could not enable core dumps on crash, maximum size is #{maximum_size} (disabled).")
21
+ return
22
+ elsif maximum_size == current_size
23
+ Kernel.warn('[DDTRACE] Core dumps already enabled, nothing to do!')
24
+ return
25
+ end
26
+
27
+ begin
28
+ Process.setrlimit(:CORE, maximum_size)
29
+ rescue => e
30
+ Kernel.warn(
31
+ "[DDTRACE] Failed to enable core dumps. Cause: #{e.class.name} #{e.message} " \
32
+ "Location: #{Array(e.backtrace).first}"
33
+ )
34
+ return
35
+ end
36
+
37
+ if current_size == 0
38
+ Kernel.warn("[DDTRACE] Enabled core dumps. Maximum size: #{maximum_size} Output pattern: '#{core_pattern}'")
39
+ else
40
+ Kernel.warn(
41
+ "[DDTRACE] Raised core dump limit. Old size: #{current_size} " \
42
+ "Maximum size: #{maximum_size} Output pattern: '#{core_pattern}'"
43
+ )
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ Datadog::Kit::EnableCoreDumps.call
@@ -0,0 +1,63 @@
1
+ # typed: false
2
+
3
+ module Datadog
4
+ module Kit
5
+ # Tracking identity via traces
6
+ module Identity
7
+ # Attach user information to the trace
8
+ #
9
+ # @param trace [TraceOperation] Trace to attach data to.
10
+ # @param id [String] Mandatory. Username or client id extracted
11
+ # from the access token or Authorization header in the inbound request
12
+ # from outside the system.
13
+ # @param email [String] Email of the authenticated user associated
14
+ # to the trace.
15
+ # @param name [String] User-friendly name. To be displayed in the
16
+ # UI if set.
17
+ # @param session_id [String] Session ID of the authenticated user.
18
+ # @param role [String] Actual/assumed role the client is making
19
+ # the request under extracted from token or application security
20
+ # context.
21
+ # @param scope [String] Scopes or granted authorities the client
22
+ # currently possesses extracted from token or application security
23
+ # context. The value would come from the scope associated with an OAuth
24
+ # 2.0 Access Token or an attribute value in a SAML 2.0 Assertion.
25
+ # @param others [Hash<String || Symbol, String>] Additional free-form
26
+ # user information to attach to the trace.
27
+ #
28
+ # rubocop:disable Metrics/CyclomaticComplexity
29
+ # rubocop:disable Metrics/PerceivedComplexity
30
+ def self.set_user(trace, id:, email: nil, name: nil, session_id: nil, role: nil, scope: nil, **others)
31
+ raise ArgumentError, 'missing required key: :id' if id.nil?
32
+
33
+ # enforce types
34
+
35
+ raise TypeError, 'id must be a String' unless id.is_a?(String)
36
+ raise TypeError, 'email must be a String' unless email.nil? || email.is_a?(String)
37
+ raise TypeError, 'name must be a String' unless name.nil? || name.is_a?(String)
38
+ raise TypeError, 'session_id must be a String' unless session_id.nil? || session_id.is_a?(String)
39
+ raise TypeError, 'role must be a String' unless role.nil? || role.is_a?(String)
40
+ raise TypeError, 'scope must be a String' unless scope.nil? || scope.is_a?(String)
41
+
42
+ others.each do |k, v|
43
+ raise TypeError, "#{k.inspect} must be a String" unless v.nil? || v.is_a?(String)
44
+ end
45
+
46
+ # set tags once data is known consistent
47
+
48
+ trace.set_tag('usr.id', id)
49
+ trace.set_tag('usr.email', email) unless email.nil?
50
+ trace.set_tag('usr.name', name) unless name.nil?
51
+ trace.set_tag('usr.session_id', session_id) unless session_id.nil?
52
+ trace.set_tag('usr.role', role) unless role.nil?
53
+ trace.set_tag('usr.scope', scope) unless scope.nil?
54
+
55
+ others.each do |k, v|
56
+ trace.set_tag("usr.#{k}", v) unless v.nil?
57
+ end
58
+ end
59
+ # rubocop:enable Metrics/PerceivedComplexity
60
+ # rubocop:enable Metrics/CyclomaticComplexity
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,11 @@
1
+ # typed: false
2
+
3
+ module Datadog
4
+ # Datadog::Kit holds public-facing APIs for higher level user-facing
5
+ # features, these features not belonging to a specific product. Contrary to
6
+ # Datadog::Core, Kit depends on products.
7
+ module Kit
8
+ end
9
+ end
10
+
11
+ require 'datadog/kit/identity'
@@ -10,8 +10,6 @@ module Datadog
10
10
  # OpenTracing adapter for Datadog::Tracer
11
11
  # @public_api
12
12
  class Tracer < ::OpenTracing::Tracer
13
- extend Forwardable
14
-
15
13
  # (see Datadog::Tracer)
16
14
  # @return [Datadog::Tracer]
17
15
  attr_reader \