datadog 2.25.0 → 2.27.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 (67) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +48 -2
  3. data/ext/datadog_profiling_native_extension/clock_id_from_pthread.c +2 -1
  4. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +100 -29
  5. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +2 -2
  6. data/ext/datadog_profiling_native_extension/collectors_gc_profiling_helper.c +3 -2
  7. data/ext/datadog_profiling_native_extension/collectors_stack.c +6 -5
  8. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +16 -12
  9. data/ext/datadog_profiling_native_extension/crashtracking_runtime_stacks.c +2 -2
  10. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +48 -1
  11. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +41 -0
  12. data/ext/datadog_profiling_native_extension/encoded_profile.c +2 -1
  13. data/ext/datadog_profiling_native_extension/heap_recorder.c +24 -24
  14. data/ext/datadog_profiling_native_extension/http_transport.c +10 -4
  15. data/ext/datadog_profiling_native_extension/libdatadog_helpers.c +3 -22
  16. data/ext/datadog_profiling_native_extension/libdatadog_helpers.h +0 -5
  17. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +9 -8
  18. data/ext/datadog_profiling_native_extension/profiling.c +20 -15
  19. data/ext/datadog_profiling_native_extension/ruby_helpers.c +55 -44
  20. data/ext/datadog_profiling_native_extension/ruby_helpers.h +17 -5
  21. data/ext/datadog_profiling_native_extension/setup_signal_handler.c +8 -2
  22. data/ext/datadog_profiling_native_extension/setup_signal_handler.h +3 -0
  23. data/ext/datadog_profiling_native_extension/stack_recorder.c +16 -16
  24. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.c +2 -1
  25. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.h +5 -2
  26. data/ext/libdatadog_api/crashtracker.c +5 -8
  27. data/ext/libdatadog_api/datadog_ruby_common.c +48 -1
  28. data/ext/libdatadog_api/datadog_ruby_common.h +41 -0
  29. data/ext/libdatadog_api/ddsketch.c +4 -8
  30. data/ext/libdatadog_api/feature_flags.c +5 -5
  31. data/ext/libdatadog_api/helpers.h +27 -0
  32. data/ext/libdatadog_api/init.c +4 -0
  33. data/ext/libdatadog_extconf_helpers.rb +1 -1
  34. data/lib/datadog/appsec/api_security/endpoint_collection/rails_collector.rb +8 -1
  35. data/lib/datadog/appsec/api_security/endpoint_collection/rails_route_serializer.rb +9 -2
  36. data/lib/datadog/appsec/component.rb +1 -1
  37. data/lib/datadog/appsec/context.rb +3 -3
  38. data/lib/datadog/appsec/contrib/excon/integration.rb +1 -1
  39. data/lib/datadog/appsec/contrib/excon/patcher.rb +1 -1
  40. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +47 -12
  41. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +32 -15
  42. data/lib/datadog/appsec/contrib/rest_client/integration.rb +1 -1
  43. data/lib/datadog/appsec/contrib/rest_client/patcher.rb +1 -1
  44. data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +50 -14
  45. data/lib/datadog/appsec/ext.rb +2 -0
  46. data/lib/datadog/appsec/metrics/collector.rb +8 -3
  47. data/lib/datadog/appsec/metrics/exporter.rb +7 -0
  48. data/lib/datadog/appsec/metrics/telemetry.rb +7 -2
  49. data/lib/datadog/appsec/metrics.rb +5 -5
  50. data/lib/datadog/appsec/remote.rb +4 -4
  51. data/lib/datadog/appsec.rb +7 -1
  52. data/lib/datadog/core/configuration/components.rb +1 -0
  53. data/lib/datadog/core/configuration/settings.rb +17 -0
  54. data/lib/datadog/core/configuration/supported_configurations.rb +1 -0
  55. data/lib/datadog/core/runtime/metrics.rb +11 -1
  56. data/lib/datadog/core/telemetry/logger.rb +2 -0
  57. data/lib/datadog/core/telemetry/logging.rb +20 -2
  58. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +3 -2
  59. data/lib/datadog/profiling/component.rb +13 -0
  60. data/lib/datadog/profiling/exporter.rb +4 -0
  61. data/lib/datadog/profiling/ext/exec_monkey_patch.rb +32 -0
  62. data/lib/datadog/profiling/flush.rb +3 -0
  63. data/lib/datadog/profiling/profiler.rb +3 -5
  64. data/lib/datadog/profiling/scheduler.rb +8 -7
  65. data/lib/datadog/profiling/tag_builder.rb +1 -0
  66. data/lib/datadog/version.rb +1 -1
  67. metadata +10 -8
@@ -14,10 +14,12 @@ module Datadog
14
14
  # read: lib/datadog/core/telemetry/logging.rb
15
15
  module Logger
16
16
  class << self
17
+ # (see Datadog::Core::Telemetry::Logging#report)
17
18
  def report(exception, level: :error, description: nil)
18
19
  instance&.report(exception, level: level, description: description)
19
20
  end
20
21
 
22
+ # (see Datadog::Core::Telemetry::Logging#error)
21
23
  def error(description)
22
24
  instance&.error(description)
23
25
  end
@@ -45,11 +45,20 @@ module Datadog
45
45
  end
46
46
  end
47
47
 
48
+ # @param exception [Exception] The exception to report
49
+ # @param level [Symbol] The log level (:error, :warn, :info, :debug)
50
+ # @param description [String, nil] A low cardinality description, without dynamic data
48
51
  def report(exception, level: :error, description: nil)
49
52
  # Anonymous exceptions to be logged as <Class:0x00007f8b1c0b3b40>
50
- message = +"#{exception.class.name || exception.class.inspect}" # standard:disable Style/RedundantInterpolation
53
+ message = +(exception.class.name || exception.class.inspect)
51
54
 
52
- message << ": #{description}" if description
55
+ telemetry_message = message_for_telemetry(exception)
56
+
57
+ if description || telemetry_message
58
+ message << ':'
59
+ message << " #{description}" if description
60
+ message << " (#{telemetry_message})" if telemetry_message
61
+ end
53
62
 
54
63
  event = Event::Log.new(
55
64
  message: message,
@@ -65,6 +74,15 @@ module Datadog
65
74
 
66
75
  log!(event)
67
76
  end
77
+
78
+ private
79
+
80
+ # A constant string representing the exception
81
+ def message_for_telemetry(exception)
82
+ return unless exception.instance_variable_defined?(:@telemetry_message)
83
+
84
+ exception.instance_variable_get(:@telemetry_message)
85
+ end
68
86
  end
69
87
  end
70
88
  end
@@ -77,12 +77,13 @@ module Datadog
77
77
  Datadog.logger.debug("CpuAndWallTimeWorker thread stopping cleanly")
78
78
  rescue Exception => e # rubocop:disable Lint/RescueException
79
79
  @failure_exception = e
80
+ operation_name = self.class._native_failure_exception_during_operation(self).inspect
80
81
  Datadog.logger.warn(
81
82
  "CpuAndWallTimeWorker thread error. " \
82
- "Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
83
+ "Operation: #{operation_name} Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
83
84
  )
84
85
  on_failure_proc&.call
85
- Datadog::Core::Telemetry::Logger.report(e, description: "CpuAndWallTimeWorker thread error")
86
+ Datadog::Core::Telemetry::Logger.report(e, description: "CpuAndWallTimeWorker thread error: #{operation_name}")
86
87
  end
87
88
  @worker_thread.name = self.class.name # Repeated from above to make sure thread gets named asap
88
89
  @worker_thread.thread_variable_set(:fork_safe, true)
@@ -82,6 +82,10 @@ module Datadog
82
82
  Datadog::Profiling::Ext::DirMonkeyPatches.apply!
83
83
  end
84
84
 
85
+ if can_apply_exec_monkey_patch?(settings)
86
+ Datadog::Profiling::Ext::ExecMonkeyPatch.apply!
87
+ end
88
+
85
89
  [profiler, {profiling_enabled: true}]
86
90
  end
87
91
 
@@ -434,6 +438,15 @@ module Datadog
434
438
  settings.profiling.advanced.dir_interruption_workaround_enabled
435
439
  end
436
440
 
441
+ private_class_method def self.can_apply_exec_monkey_patch?(settings)
442
+ return false if RUBY_VERSION < "2.7"
443
+
444
+ # This file is 2.7+ only so we only require it here once we've checked the Ruby version
445
+ require "datadog/profiling/ext/exec_monkey_patch"
446
+
447
+ settings.profiling.advanced.shutdown_on_exec_enabled
448
+ end
449
+
437
450
  private_class_method def self.enable_gvl_profiling?(settings, logger)
438
451
  return false if RUBY_VERSION < "3.2"
439
452
 
@@ -70,6 +70,9 @@ module Datadog
70
70
 
71
71
  uncompressed_code_provenance = code_provenance_collector.refresh.generate_json if code_provenance_collector
72
72
 
73
+ process_tags = Datadog.configuration.experimental_propagate_process_tags_enabled ?
74
+ Core::Environment::Process.serialized : ''
75
+
73
76
  Flush.new(
74
77
  start: start,
75
78
  finish: finish,
@@ -80,6 +83,7 @@ module Datadog
80
83
  settings: Datadog.configuration,
81
84
  profile_seq: sequence_tracker.get_next,
82
85
  ).to_a,
86
+ process_tags: process_tags,
83
87
  internal_metadata: internal_metadata.merge(
84
88
  {
85
89
  worker_stats: worker_stats,
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module Profiling
5
+ module Ext
6
+ # The profiler gathers data by sending `SIGPROF` unix signals to Ruby application threads.
7
+ #
8
+ # When using `Kernel#exec` on Linux, it can happen that a signal sent before calling `exec` arrives after
9
+ # the new process is running, causing it to fail with the `Profiling timer expired` error message.
10
+ # To avoid this, the profiler installs a monkey patch on `Kernel#exec` to stop profiling before actually
11
+ # calling `exec`.
12
+ # This monkey patch is available for Ruby 2.7+; let us know if you need it on earlier Rubies.
13
+ # For more details see https://github.com/DataDog/dd-trace-rb/issues/5101 .
14
+ module ExecMonkeyPatch
15
+ def self.apply!
16
+ ::Object.prepend(ObjectMonkeyPatch)
17
+
18
+ true
19
+ end
20
+
21
+ module ObjectMonkeyPatch
22
+ private
23
+
24
+ def exec(...)
25
+ Datadog.send(:components, allow_initialization: false)&.profiler&.shutdown!(report_last_profile: false)
26
+ super
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -13,6 +13,7 @@ module Datadog
13
13
  :code_provenance_file_name,
14
14
  :code_provenance_data,
15
15
  :tags_as_array,
16
+ :process_tags,
16
17
  :internal_metadata_json,
17
18
  :info_json
18
19
 
@@ -23,6 +24,7 @@ module Datadog
23
24
  code_provenance_file_name:,
24
25
  code_provenance_data:,
25
26
  tags_as_array:,
27
+ process_tags:,
26
28
  internal_metadata:,
27
29
  info_json:
28
30
  )
@@ -32,6 +34,7 @@ module Datadog
32
34
  @code_provenance_file_name = code_provenance_file_name
33
35
  @code_provenance_data = code_provenance_data
34
36
  @tags_as_array = tags_as_array
37
+ @process_tags = process_tags
35
38
  @internal_metadata_json = JSON.generate(internal_metadata)
36
39
  @info_json = info_json
37
40
  end
@@ -31,10 +31,11 @@ module Datadog
31
31
  scheduler.start(on_failure_proc: proc { component_failed(:scheduler) })
32
32
  end
33
33
 
34
- def shutdown!
34
+ def shutdown!(report_last_profile: true)
35
35
  Datadog.logger.debug("Shutting down profiler")
36
36
 
37
37
  stop_worker
38
+ scheduler.disable_reporting unless report_last_profile
38
39
  stop_scheduler
39
40
  end
40
41
 
@@ -57,11 +58,8 @@ module Datadog
57
58
  Datadog::Core::Telemetry::Logger
58
59
  .error("Detected issue with profiler (#{failed_component} component), stopping profiling")
59
60
 
60
- # We explicitly not stop the crash tracker in this situation, under the assumption that, if a component failed,
61
- # we're operating in a degraded state and crash tracking may still be helpful.
62
-
63
61
  if failed_component == :worker
64
- scheduler.mark_profiler_failed
62
+ scheduler.disable_reporting
65
63
  stop_scheduler
66
64
  elsif failed_component == :scheduler
67
65
  stop_worker
@@ -24,7 +24,7 @@ module Datadog
24
24
  attr_reader \
25
25
  :exporter,
26
26
  :transport,
27
- :profiler_failed
27
+ :reporting_disabled
28
28
 
29
29
  public
30
30
 
@@ -36,7 +36,7 @@ module Datadog
36
36
  )
37
37
  @exporter = exporter
38
38
  @transport = transport
39
- @profiler_failed = false
39
+ @reporting_disabled = false
40
40
  @stop_requested = false
41
41
 
42
42
  # Workers::Async::Thread settings
@@ -83,14 +83,15 @@ module Datadog
83
83
  true
84
84
  end
85
85
 
86
- # This is called by the Profiler class whenever an issue happened in the profiler. This makes sure that even
87
- # if there is data to be flushed, we don't try to flush it.
88
- def mark_profiler_failed
89
- @profiler_failed = true
86
+ # Called by the Profiler when it wants to prevent any further reporting,
87
+ # even if there is data to be flushed.
88
+ # Used when the profiler failed or we're otherwise in a hurry to shut down.
89
+ def disable_reporting
90
+ @reporting_disabled = true
90
91
  end
91
92
 
92
93
  def work_pending?
93
- !profiler_failed && exporter.can_flush? && (run_loop? || !stop_requested?)
94
+ !reporting_disabled && exporter.can_flush? && (run_loop? || !stop_requested?)
94
95
  end
95
96
 
96
97
  def reset_after_fork
@@ -50,6 +50,7 @@ module Datadog
50
50
  FORM_FIELD_TAG_PROFILER_VERSION => profiler_version,
51
51
  'profile_seq' => profile_seq.to_s,
52
52
  )
53
+
53
54
  user_tag_keys = settings.tags.keys
54
55
  hash.keep_if { |tag| user_tag_keys.include?(tag) || ALLOWED_TAGS.include?(tag) }
55
56
  Core::Utils.encode_tags(hash)
@@ -3,7 +3,7 @@
3
3
  module Datadog
4
4
  module VERSION
5
5
  MAJOR = 2
6
- MINOR = 25
6
+ MINOR = 27
7
7
  PATCH = 0
8
8
  PRE = nil
9
9
  BUILD = nil
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: datadog
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.25.0
4
+ version: 2.27.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Datadog, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-01-13 00:00:00.000000000 Z
11
+ date: 2026-01-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: msgpack
@@ -33,7 +33,7 @@ dependencies:
33
33
  version: '3.5'
34
34
  - - ">="
35
35
  - !ruby/object:Gem::Version
36
- version: 3.5.0
36
+ version: 3.5.1
37
37
  type: :runtime
38
38
  prerelease: false
39
39
  version_requirements: !ruby/object:Gem::Requirement
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: '3.5'
44
44
  - - ">="
45
45
  - !ruby/object:Gem::Version
46
- version: 3.5.0
46
+ version: 3.5.1
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: libddwaf
49
49
  requirement: !ruby/object:Gem::Requirement
@@ -64,14 +64,14 @@ dependencies:
64
64
  requirements:
65
65
  - - "~>"
66
66
  - !ruby/object:Gem::Version
67
- version: 24.0.1.1.0
67
+ version: 25.0.0.1.0
68
68
  type: :runtime
69
69
  prerelease: false
70
70
  version_requirements: !ruby/object:Gem::Requirement
71
71
  requirements:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
- version: 24.0.1.1.0
74
+ version: 25.0.0.1.0
75
75
  - !ruby/object:Gem::Dependency
76
76
  name: logger
77
77
  requirement: !ruby/object:Gem::Requirement
@@ -175,6 +175,7 @@ files:
175
175
  - ext/libdatadog_api/extconf.rb
176
176
  - ext/libdatadog_api/feature_flags.c
177
177
  - ext/libdatadog_api/feature_flags.h
178
+ - ext/libdatadog_api/helpers.h
178
179
  - ext/libdatadog_api/init.c
179
180
  - ext/libdatadog_api/library_config.c
180
181
  - ext/libdatadog_api/library_config.h
@@ -576,6 +577,7 @@ files:
576
577
  - lib/datadog/profiling/exporter.rb
577
578
  - lib/datadog/profiling/ext.rb
578
579
  - lib/datadog/profiling/ext/dir_monkey_patches.rb
580
+ - lib/datadog/profiling/ext/exec_monkey_patch.rb
579
581
  - lib/datadog/profiling/flush.rb
580
582
  - lib/datadog/profiling/http_transport.rb
581
583
  - lib/datadog/profiling/load_native_extension.rb
@@ -1090,8 +1092,8 @@ licenses:
1090
1092
  - Apache-2.0
1091
1093
  metadata:
1092
1094
  allowed_push_host: https://rubygems.org
1093
- changelog_uri: https://github.com/DataDog/dd-trace-rb/blob/v2.25.0/CHANGELOG.md
1094
- source_code_uri: https://github.com/DataDog/dd-trace-rb/tree/v2.25.0
1095
+ changelog_uri: https://github.com/DataDog/dd-trace-rb/blob/v2.27.0/CHANGELOG.md
1096
+ source_code_uri: https://github.com/DataDog/dd-trace-rb/tree/v2.27.0
1095
1097
  post_install_message:
1096
1098
  rdoc_options: []
1097
1099
  require_paths: