datadog 2.2.0 → 2.4.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 (196) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +87 -2
  3. data/ext/datadog_profiling_loader/datadog_profiling_loader.c +9 -1
  4. data/ext/datadog_profiling_loader/extconf.rb +14 -26
  5. data/ext/datadog_profiling_native_extension/clock_id.h +1 -0
  6. data/ext/datadog_profiling_native_extension/clock_id_from_pthread.c +1 -2
  7. data/ext/datadog_profiling_native_extension/clock_id_noop.c +1 -2
  8. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +257 -69
  9. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +53 -28
  10. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h +34 -4
  11. data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +4 -0
  12. data/ext/datadog_profiling_native_extension/collectors_stack.c +136 -81
  13. data/ext/datadog_profiling_native_extension/collectors_stack.h +2 -2
  14. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +661 -48
  15. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +10 -1
  16. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +83 -0
  17. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +53 -0
  18. data/ext/datadog_profiling_native_extension/extconf.rb +91 -69
  19. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.c +50 -0
  20. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.h +75 -0
  21. data/ext/datadog_profiling_native_extension/heap_recorder.c +54 -12
  22. data/ext/datadog_profiling_native_extension/heap_recorder.h +3 -1
  23. data/ext/datadog_profiling_native_extension/helpers.h +6 -17
  24. data/ext/datadog_profiling_native_extension/http_transport.c +41 -9
  25. data/ext/datadog_profiling_native_extension/libdatadog_helpers.c +0 -86
  26. data/ext/datadog_profiling_native_extension/libdatadog_helpers.h +2 -23
  27. data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +61 -172
  28. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +116 -139
  29. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +20 -11
  30. data/ext/datadog_profiling_native_extension/profiling.c +1 -3
  31. data/ext/datadog_profiling_native_extension/ruby_helpers.c +0 -33
  32. data/ext/datadog_profiling_native_extension/ruby_helpers.h +1 -26
  33. data/ext/datadog_profiling_native_extension/setup_signal_handler.h +1 -0
  34. data/ext/datadog_profiling_native_extension/stack_recorder.c +14 -2
  35. data/ext/datadog_profiling_native_extension/stack_recorder.h +2 -0
  36. data/ext/datadog_profiling_native_extension/time_helpers.c +0 -15
  37. data/ext/datadog_profiling_native_extension/time_helpers.h +36 -6
  38. data/ext/{datadog_profiling_native_extension → libdatadog_api}/crashtracker.c +37 -22
  39. data/ext/libdatadog_api/datadog_ruby_common.c +83 -0
  40. data/ext/libdatadog_api/datadog_ruby_common.h +53 -0
  41. data/ext/libdatadog_api/extconf.rb +108 -0
  42. data/ext/libdatadog_api/macos_development.md +26 -0
  43. data/ext/libdatadog_extconf_helpers.rb +130 -0
  44. data/lib/datadog/appsec/assets/waf_rules/recommended.json +2184 -108
  45. data/lib/datadog/appsec/assets/waf_rules/strict.json +1430 -2
  46. data/lib/datadog/appsec/component.rb +29 -8
  47. data/lib/datadog/appsec/configuration/settings.rb +2 -2
  48. data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +1 -0
  49. data/lib/datadog/appsec/contrib/devise/patcher/rememberable_patch.rb +21 -0
  50. data/lib/datadog/appsec/contrib/devise/patcher.rb +12 -2
  51. data/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +35 -0
  52. data/lib/datadog/appsec/contrib/graphql/gateway/multiplex.rb +109 -0
  53. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +71 -0
  54. data/lib/datadog/appsec/contrib/graphql/integration.rb +54 -0
  55. data/lib/datadog/appsec/contrib/graphql/patcher.rb +37 -0
  56. data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +59 -0
  57. data/lib/datadog/appsec/contrib/rack/gateway/request.rb +3 -6
  58. data/lib/datadog/appsec/event.rb +1 -1
  59. data/lib/datadog/appsec/processor/actions.rb +1 -1
  60. data/lib/datadog/appsec/processor/rule_loader.rb +3 -1
  61. data/lib/datadog/appsec/processor/rule_merger.rb +33 -15
  62. data/lib/datadog/appsec/processor.rb +36 -37
  63. data/lib/datadog/appsec/rate_limiter.rb +25 -40
  64. data/lib/datadog/appsec/remote.rb +7 -3
  65. data/lib/datadog/appsec/response.rb +15 -1
  66. data/lib/datadog/appsec.rb +3 -2
  67. data/lib/datadog/core/configuration/components.rb +18 -15
  68. data/lib/datadog/core/configuration/settings.rb +135 -9
  69. data/lib/datadog/core/crashtracking/agent_base_url.rb +21 -0
  70. data/lib/datadog/core/crashtracking/component.rb +111 -0
  71. data/lib/datadog/core/crashtracking/tag_builder.rb +39 -0
  72. data/lib/datadog/core/diagnostics/environment_logger.rb +8 -11
  73. data/lib/datadog/core/environment/execution.rb +5 -5
  74. data/lib/datadog/core/metrics/client.rb +7 -0
  75. data/lib/datadog/core/rate_limiter.rb +183 -0
  76. data/lib/datadog/core/remote/client/capabilities.rb +4 -3
  77. data/lib/datadog/core/remote/component.rb +4 -2
  78. data/lib/datadog/core/remote/negotiation.rb +4 -4
  79. data/lib/datadog/core/remote/tie.rb +2 -0
  80. data/lib/datadog/core/runtime/metrics.rb +1 -1
  81. data/lib/datadog/core/telemetry/component.rb +51 -2
  82. data/lib/datadog/core/telemetry/emitter.rb +9 -11
  83. data/lib/datadog/core/telemetry/event.rb +37 -1
  84. data/lib/datadog/core/telemetry/ext.rb +1 -0
  85. data/lib/datadog/core/telemetry/http/adapters/net.rb +10 -12
  86. data/lib/datadog/core/telemetry/http/ext.rb +3 -0
  87. data/lib/datadog/core/telemetry/http/transport.rb +38 -9
  88. data/lib/datadog/core/telemetry/logger.rb +51 -0
  89. data/lib/datadog/core/telemetry/logging.rb +71 -0
  90. data/lib/datadog/core/telemetry/request.rb +13 -1
  91. data/lib/datadog/core/utils/at_fork_monkey_patch.rb +102 -0
  92. data/lib/datadog/core/utils/time.rb +12 -0
  93. data/lib/datadog/di/code_tracker.rb +168 -0
  94. data/lib/datadog/di/configuration/settings.rb +163 -0
  95. data/lib/datadog/di/configuration.rb +11 -0
  96. data/lib/datadog/di/error.rb +31 -0
  97. data/lib/datadog/di/extensions.rb +16 -0
  98. data/lib/datadog/di/probe.rb +133 -0
  99. data/lib/datadog/di/probe_builder.rb +41 -0
  100. data/lib/datadog/di/redactor.rb +188 -0
  101. data/lib/datadog/di/serializer.rb +193 -0
  102. data/lib/datadog/di.rb +14 -0
  103. data/lib/datadog/kit/appsec/events.rb +2 -4
  104. data/lib/datadog/opentelemetry/sdk/propagator.rb +2 -0
  105. data/lib/datadog/opentelemetry/sdk/span_processor.rb +10 -0
  106. data/lib/datadog/opentelemetry/sdk/trace/span.rb +23 -0
  107. data/lib/datadog/profiling/collectors/code_provenance.rb +7 -7
  108. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +28 -26
  109. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +11 -13
  110. data/lib/datadog/profiling/collectors/info.rb +15 -6
  111. data/lib/datadog/profiling/collectors/thread_context.rb +30 -2
  112. data/lib/datadog/profiling/component.rb +89 -95
  113. data/lib/datadog/profiling/exporter.rb +3 -3
  114. data/lib/datadog/profiling/ext/dir_monkey_patches.rb +3 -3
  115. data/lib/datadog/profiling/ext.rb +21 -21
  116. data/lib/datadog/profiling/flush.rb +1 -1
  117. data/lib/datadog/profiling/http_transport.rb +14 -7
  118. data/lib/datadog/profiling/load_native_extension.rb +5 -5
  119. data/lib/datadog/profiling/preload.rb +1 -1
  120. data/lib/datadog/profiling/profiler.rb +5 -8
  121. data/lib/datadog/profiling/scheduler.rb +33 -25
  122. data/lib/datadog/profiling/stack_recorder.rb +3 -0
  123. data/lib/datadog/profiling/tag_builder.rb +2 -2
  124. data/lib/datadog/profiling/tasks/exec.rb +5 -5
  125. data/lib/datadog/profiling/tasks/setup.rb +16 -35
  126. data/lib/datadog/profiling.rb +4 -5
  127. data/lib/datadog/single_step_instrument.rb +12 -0
  128. data/lib/datadog/tracing/contrib/action_cable/instrumentation.rb +8 -12
  129. data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +5 -0
  130. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +78 -0
  131. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/patcher.rb +33 -0
  132. data/lib/datadog/tracing/contrib/action_pack/patcher.rb +2 -0
  133. data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +4 -0
  134. data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +3 -1
  135. data/lib/datadog/tracing/contrib/active_record/events/sql.rb +4 -1
  136. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +5 -1
  137. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +5 -0
  138. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +6 -1
  139. data/lib/datadog/tracing/contrib/ext.rb +14 -0
  140. data/lib/datadog/tracing/contrib/faraday/middleware.rb +9 -0
  141. data/lib/datadog/tracing/contrib/grape/endpoint.rb +19 -0
  142. data/lib/datadog/tracing/contrib/graphql/patcher.rb +9 -12
  143. data/lib/datadog/tracing/contrib/graphql/trace_patcher.rb +3 -3
  144. data/lib/datadog/tracing/contrib/graphql/tracing_patcher.rb +3 -3
  145. data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +14 -10
  146. data/lib/datadog/tracing/contrib/graphql/unified_trace_patcher.rb +10 -4
  147. data/lib/datadog/tracing/contrib/http/instrumentation.rb +18 -15
  148. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +6 -5
  149. data/lib/datadog/tracing/contrib/httpclient/patcher.rb +1 -14
  150. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +5 -0
  151. data/lib/datadog/tracing/contrib/httprb/patcher.rb +1 -14
  152. data/lib/datadog/tracing/contrib/lograge/patcher.rb +15 -0
  153. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +2 -0
  154. data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +5 -0
  155. data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +17 -13
  156. data/lib/datadog/tracing/contrib/opensearch/patcher.rb +13 -6
  157. data/lib/datadog/tracing/contrib/patcher.rb +2 -1
  158. data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +5 -0
  159. data/lib/datadog/tracing/contrib/pg/instrumentation.rb +4 -1
  160. data/lib/datadog/tracing/contrib/presto/patcher.rb +1 -13
  161. data/lib/datadog/tracing/contrib/propagation/sql_comment/ext.rb +28 -0
  162. data/lib/datadog/tracing/contrib/propagation/sql_comment/mode.rb +5 -1
  163. data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +22 -10
  164. data/lib/datadog/tracing/contrib/rack/middlewares.rb +27 -0
  165. data/lib/datadog/tracing/contrib/redis/tags.rb +4 -0
  166. data/lib/datadog/tracing/contrib/sinatra/tracer.rb +4 -0
  167. data/lib/datadog/tracing/contrib/stripe/request.rb +3 -2
  168. data/lib/datadog/tracing/contrib/trilogy/configuration/settings.rb +5 -0
  169. data/lib/datadog/tracing/contrib/trilogy/instrumentation.rb +4 -1
  170. data/lib/datadog/tracing/diagnostics/environment_logger.rb +14 -16
  171. data/lib/datadog/tracing/distributed/propagation.rb +7 -0
  172. data/lib/datadog/tracing/metadata/errors.rb +9 -1
  173. data/lib/datadog/tracing/metadata/ext.rb +6 -0
  174. data/lib/datadog/tracing/pipeline/span_filter.rb +2 -2
  175. data/lib/datadog/tracing/remote.rb +5 -2
  176. data/lib/datadog/tracing/sampling/matcher.rb +6 -1
  177. data/lib/datadog/tracing/sampling/rate_sampler.rb +1 -1
  178. data/lib/datadog/tracing/sampling/rule.rb +2 -0
  179. data/lib/datadog/tracing/sampling/rule_sampler.rb +9 -5
  180. data/lib/datadog/tracing/sampling/span/ext.rb +1 -1
  181. data/lib/datadog/tracing/sampling/span/rule.rb +2 -2
  182. data/lib/datadog/tracing/span.rb +9 -2
  183. data/lib/datadog/tracing/span_event.rb +41 -0
  184. data/lib/datadog/tracing/span_operation.rb +6 -2
  185. data/lib/datadog/tracing/trace_operation.rb +26 -2
  186. data/lib/datadog/tracing/tracer.rb +14 -12
  187. data/lib/datadog/tracing/transport/http/client.rb +1 -0
  188. data/lib/datadog/tracing/transport/io/client.rb +1 -0
  189. data/lib/datadog/tracing/transport/serializable_trace.rb +3 -0
  190. data/lib/datadog/tracing/workers/trace_writer.rb +1 -1
  191. data/lib/datadog/tracing/workers.rb +1 -1
  192. data/lib/datadog/version.rb +1 -1
  193. metadata +46 -11
  194. data/lib/datadog/profiling/crashtracker.rb +0 -91
  195. data/lib/datadog/profiling/ext/forking.rb +0 -98
  196. data/lib/datadog/tracing/sampling/rate_limiter.rb +0 -185
@@ -8,34 +8,30 @@ module Datadog
8
8
 
9
9
  private
10
10
 
11
- attr_reader :worker, :scheduler, :optional_crashtracker
11
+ attr_reader :worker, :scheduler
12
12
 
13
13
  public
14
14
 
15
- def initialize(worker:, scheduler:, optional_crashtracker:)
15
+ def initialize(worker:, scheduler:)
16
16
  @worker = worker
17
17
  @scheduler = scheduler
18
- @optional_crashtracker = optional_crashtracker
19
18
  end
20
19
 
21
20
  def start
22
21
  after_fork! do
23
- optional_crashtracker.reset_after_fork if optional_crashtracker
24
22
  worker.reset_after_fork
25
23
  scheduler.reset_after_fork
26
24
  end
27
25
 
28
- optional_crashtracker.start if optional_crashtracker
29
26
  worker.start(on_failure_proc: proc { component_failed(:worker) })
30
27
  scheduler.start(on_failure_proc: proc { component_failed(:scheduler) })
31
28
  end
32
29
 
33
30
  def shutdown!
34
- Datadog.logger.debug('Shutting down profiler')
31
+ Datadog.logger.debug("Shutting down profiler")
35
32
 
36
33
  stop_worker
37
34
  stop_scheduler
38
- optional_crashtracker.stop if optional_crashtracker
39
35
  end
40
36
 
41
37
  private
@@ -52,13 +48,14 @@ module Datadog
52
48
  def component_failed(failed_component)
53
49
  Datadog.logger.warn(
54
50
  "Detected issue with profiler (#{failed_component} component), stopping profiling. " \
55
- 'See previous log messages for details.'
51
+ "See previous log messages for details."
56
52
  )
57
53
 
58
54
  # We explicitly not stop the crash tracker in this situation, under the assumption that, if a component failed,
59
55
  # we're operating in a degraded state and crash tracking may still be helpful.
60
56
 
61
57
  if failed_component == :worker
58
+ scheduler.mark_profiler_failed
62
59
  stop_scheduler
63
60
  elsif failed_component == :scheduler
64
61
  stop_worker
@@ -1,9 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../core/utils/time'
3
+ require_relative "../core/utils/time"
4
4
 
5
- require_relative '../core/worker'
6
- require_relative '../core/workers/polling'
5
+ require_relative "../core/worker"
6
+ require_relative "../core/workers/polling"
7
+ require_relative "../core/telemetry/logger"
7
8
 
8
9
  module Datadog
9
10
  module Profiling
@@ -22,7 +23,8 @@ module Datadog
22
23
 
23
24
  attr_reader \
24
25
  :exporter,
25
- :transport
26
+ :transport,
27
+ :profiler_failed
26
28
 
27
29
  public
28
30
 
@@ -34,6 +36,7 @@ module Datadog
34
36
  )
35
37
  @exporter = exporter
36
38
  @transport = transport
39
+ @profiler_failed = false
37
40
 
38
41
  # Workers::Async::Thread settings
39
42
  self.fork_policy = fork_policy
@@ -50,25 +53,23 @@ module Datadog
50
53
  end
51
54
 
52
55
  def perform(on_failure_proc)
53
- begin
54
- # A profiling flush may be called while the VM is shutting down, to report the last profile. When we do so,
55
- # we impose a strict timeout. This means this last profile may or may not be sent, depending on if the flush can
56
- # successfully finish in the strict timeout.
57
- # This can be somewhat confusing (why did it not get reported?), so let's at least log what happened.
58
- interrupted = true
59
-
60
- flush_and_wait
61
- interrupted = false
62
- rescue Exception => e # rubocop:disable Lint/RescueException
63
- Datadog.logger.warn(
64
- 'Profiling::Scheduler thread error. ' \
65
- "Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
66
- )
67
- on_failure_proc&.call
68
- raise
69
- ensure
70
- Datadog.logger.debug('#flush was interrupted or failed before it could complete') if interrupted
71
- end
56
+ # A profiling flush may be called while the VM is shutting down, to report the last profile. When we do so,
57
+ # we impose a strict timeout. This means this last profile may or may not be sent, depending on if the flush can
58
+ # successfully finish in the strict timeout.
59
+ # This can be somewhat confusing (why did it not get reported?), so let's at least log what happened.
60
+ interrupted = true
61
+
62
+ flush_and_wait
63
+ interrupted = false
64
+ rescue Exception => e # rubocop:disable Lint/RescueException
65
+ Datadog.logger.warn(
66
+ "Profiling::Scheduler thread error. " \
67
+ "Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
68
+ )
69
+ on_failure_proc&.call
70
+ raise
71
+ ensure
72
+ Datadog.logger.debug("#flush was interrupted or failed before it could complete") if interrupted
72
73
  end
73
74
 
74
75
  # Configure Workers::IntervalLoop to not report immediately when scheduler starts
@@ -80,8 +81,14 @@ module Datadog
80
81
  true
81
82
  end
82
83
 
84
+ # This is called by the Profiler class whenever an issue happened in the profiler. This makes sure that even
85
+ # if there is data to be flushed, we don't try to flush it.
86
+ def mark_profiler_failed
87
+ @profiler_failed = true
88
+ end
89
+
83
90
  def work_pending?
84
- exporter.can_flush?
91
+ !profiler_failed && exporter.can_flush?
85
92
  end
86
93
 
87
94
  def reset_after_fork
@@ -124,10 +131,11 @@ module Datadog
124
131
 
125
132
  begin
126
133
  transport.export(flush)
127
- rescue StandardError => e
134
+ rescue => e
128
135
  Datadog.logger.error(
129
136
  "Unable to report profile. Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
130
137
  )
138
+ Datadog::Core::Telemetry::Logger.report(e, description: "Unable to report profile")
131
139
  end
132
140
 
133
141
  true
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../core/telemetry/logger"
4
+
3
5
  module Datadog
4
6
  module Profiling
5
7
  # Stores stack samples in a native libdatadog data structure and expose Ruby-level serialization APIs
@@ -42,6 +44,7 @@ module Datadog
42
44
  error_message = result
43
45
 
44
46
  Datadog.logger.error("Failed to serialize profiling data: #{error_message}")
47
+ Datadog::Core::Telemetry::Logger.error("Failed to serialize profiling data")
45
48
 
46
49
  nil
47
50
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../core/utils'
4
- require_relative '../core/environment/git'
3
+ require_relative "../core/utils"
4
+ require_relative "../core/environment/git"
5
5
 
6
6
  module Datadog
7
7
  module Profiling
@@ -18,16 +18,16 @@ module Datadog
18
18
 
19
19
  def rubyopts
20
20
  [
21
- '-rdatadog/profiling/preload'
21
+ "-rdatadog/profiling/preload"
22
22
  ]
23
23
  end
24
24
 
25
25
  private
26
26
 
27
27
  def set_rubyopt!
28
- existing_rubyopt = ENV['RUBYOPT']
28
+ existing_rubyopt = ENV["RUBYOPT"]
29
29
 
30
- ENV['RUBYOPT'] = existing_rubyopt ? "#{existing_rubyopt} #{rubyopts.join(' ')}" : rubyopts.join(' ')
30
+ ENV["RUBYOPT"] = existing_rubyopt ? "#{existing_rubyopt} #{rubyopts.join(" ")}" : rubyopts.join(" ")
31
31
  end
32
32
 
33
33
  # If there's an error here, rather than throwing a cryptic stack trace, let's instead have clearer messages, and
@@ -38,10 +38,10 @@ module Datadog
38
38
  def exec_with_error_handling(args)
39
39
  Kernel.exec(*args)
40
40
  rescue Errno::ENOENT => e
41
- Kernel.warn "ddprofrb exec failed: #{e.class.name} #{e.message} (command was '#{args.join(' ')}')"
41
+ Kernel.warn "ddprofrb exec failed: #{e.class.name} #{e.message} (command was '#{args.join(" ")}')"
42
42
  Kernel.exit 127
43
43
  rescue Errno::EACCES, Errno::ENOEXEC => e
44
- Kernel.warn "ddprofrb exec failed: #{e.class.name} #{e.message} (command was '#{args.join(' ')}')"
44
+ Kernel.warn "ddprofrb exec failed: #{e.class.name} #{e.message} (command was '#{args.join(" ")}')"
45
45
  Kernel.exit 126
46
46
  end
47
47
  end
@@ -1,56 +1,37 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../../core/utils/only_once'
4
- require_relative '../ext/forking'
3
+ require_relative "../../core/utils/only_once"
4
+ require_relative "../../core/utils/at_fork_monkey_patch"
5
5
 
6
6
  module Datadog
7
7
  module Profiling
8
8
  module Tasks
9
- # Takes care of loading our extensions/monkey patches to handle fork() and validating if CPU-time profiling is usable
9
+ # Takes care of restarting the profiler when the process forks
10
10
  class Setup
11
11
  ACTIVATE_EXTENSIONS_ONLY_ONCE = Core::Utils::OnlyOnce.new
12
12
 
13
13
  def run
14
14
  ACTIVATE_EXTENSIONS_ONLY_ONCE.run do
15
- begin
16
- activate_forking_extensions
17
- setup_at_fork_hooks
18
- rescue StandardError, ScriptError => e
19
- Datadog.logger.warn do
20
- "Profiler extensions unavailable. Cause: #{e.class.name} #{e.message} " \
21
- "Location: #{Array(e.backtrace).first}"
22
- end
15
+ Datadog::Core::Utils::AtForkMonkeyPatch.apply!
16
+ setup_at_fork_hooks
17
+ rescue StandardError, ScriptError => e
18
+ Datadog.logger.warn do
19
+ "Profiler extensions unavailable. Cause: #{e.class.name} #{e.message} " \
20
+ "Location: #{Array(e.backtrace).first}"
23
21
  end
24
22
  end
25
23
  end
26
24
 
27
25
  private
28
26
 
29
- def activate_forking_extensions
30
- if Ext::Forking.supported?
31
- Ext::Forking.apply!
32
- elsif Datadog.configuration.profiling.enabled
33
- Datadog.logger.debug('Profiler forking extensions skipped; forking not supported.')
34
- end
35
- rescue StandardError, ScriptError => e
36
- Datadog.logger.warn do
37
- "Profiler forking extensions unavailable. Cause: #{e.class.name} #{e.message} " \
38
- "Location: #{Array(e.backtrace).first}"
39
- end
40
- end
41
-
42
27
  def setup_at_fork_hooks
43
- if Process.respond_to?(:at_fork)
44
- Process.at_fork(:child) do
45
- begin
46
- # Restart profiler, if enabled
47
- Profiling.start_if_enabled
48
- rescue StandardError => e
49
- Datadog.logger.warn do
50
- "Error during post-fork hooks. Cause: #{e.class.name} #{e.message} " \
51
- "Location: #{Array(e.backtrace).first}"
52
- end
53
- end
28
+ Datadog::Core::Utils::AtForkMonkeyPatch.at_fork(:child) do
29
+ # Restart profiler, if enabled
30
+ Profiling.start_if_enabled
31
+ rescue => e
32
+ Datadog.logger.warn do
33
+ "Error during post-fork hooks. Cause: #{e.class.name} #{e.message} " \
34
+ "Location: #{Array(e.backtrace).first}"
54
35
  end
55
36
  end
56
37
  end
@@ -30,7 +30,7 @@ module Datadog
30
30
  profiler = Datadog.send(:components).profiler
31
31
  # ...but we still try to start it BECAUSE if the process forks, the profiler will exist but may
32
32
  # not yet have been started in the fork
33
- profiler.start if profiler
33
+ profiler&.start
34
34
  !!profiler
35
35
  end
36
36
 
@@ -47,6 +47,7 @@ module Datadog
47
47
  # (This is similar to some OS-based time representations.)
48
48
  #
49
49
  # Note 2: All fibers in the same thread will share the same counter values.
50
+ # Note 3: This counter is not accurate when using the M:N scheduler.
50
51
  #
51
52
  # Only available when the profiler is running, and allocation-related features are not disabled via configuration.
52
53
  #
@@ -62,7 +63,7 @@ module Datadog
62
63
  def self.enabled?
63
64
  profiler = Datadog.send(:components).profiler
64
65
  # Use .send(...) to avoid exposing the attr_reader as an API to the outside
65
- !!(profiler.send(:scheduler).running? if profiler)
66
+ !!profiler&.send(:scheduler)&.running?
66
67
  end
67
68
 
68
69
  def self.wait_until_running(timeout_seconds: 5)
@@ -97,7 +98,7 @@ module Datadog
97
98
 
98
99
  contents = file_api.read(skipped_reason_file).strip
99
100
  contents unless contents.empty?
100
- rescue StandardError
101
+ rescue
101
102
  # Do nothing
102
103
  end
103
104
  end
@@ -135,7 +136,6 @@ module Datadog
135
136
  private_class_method def self.load_profiling
136
137
  return false unless supported?
137
138
 
138
- require_relative 'profiling/ext/forking'
139
139
  require_relative 'profiling/ext/dir_monkey_patches'
140
140
  require_relative 'profiling/collectors/info'
141
141
  require_relative 'profiling/collectors/code_provenance'
@@ -144,7 +144,6 @@ module Datadog
144
144
  require_relative 'profiling/collectors/idle_sampling_helper'
145
145
  require_relative 'profiling/collectors/stack'
146
146
  require_relative 'profiling/collectors/thread_context'
147
- require_relative 'profiling/crashtracker'
148
147
  require_relative 'profiling/stack_recorder'
149
148
  require_relative 'profiling/exporter'
150
149
  require_relative 'profiling/flush'
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Entrypoint file for single step instrumentation.
5
+ #
6
+ # This file's path is private. Do not reference this file.
7
+ #
8
+ begin
9
+ require_relative 'auto_instrument'
10
+ rescue StandardError, LoadError => e
11
+ warn "Single step instrumentation failed: #{e.class}:#{e.message}\n\tSource:\n\t#{Array(e.backtrace).join("\n\t")}"
12
+ end
@@ -14,21 +14,17 @@ module Datadog
14
14
  module ActionCableConnection
15
15
  def on_open
16
16
  Tracing.trace(Ext::SPAN_ON_OPEN) do |span, trace|
17
- begin
18
- span.resource = "#{self.class}#on_open"
19
- span.type = Tracing::Metadata::Ext::AppTypes::TYPE_WEB
17
+ span.resource = "#{self.class}#on_open"
18
+ span.type = Tracing::Metadata::Ext::AppTypes::TYPE_WEB
20
19
 
21
- span.set_tag(Ext::TAG_ACTION, 'on_open')
22
- span.set_tag(Ext::TAG_CONNECTION, self.class.to_s)
20
+ span.set_tag(Ext::TAG_ACTION, 'on_open')
21
+ span.set_tag(Ext::TAG_CONNECTION, self.class.to_s)
23
22
 
24
- span.set_tag(Tracing::Metadata::Ext::TAG_COMPONENT, Ext::TAG_COMPONENT)
25
- span.set_tag(Tracing::Metadata::Ext::TAG_OPERATION, Ext::TAG_OPERATION_ON_OPEN)
23
+ span.set_tag(Tracing::Metadata::Ext::TAG_COMPONENT, Ext::TAG_COMPONENT)
24
+ span.set_tag(Tracing::Metadata::Ext::TAG_OPERATION, Ext::TAG_OPERATION_ON_OPEN)
26
25
 
27
- # Set the resource name of the trace
28
- trace.resource = span.resource
29
- rescue StandardError => e
30
- Datadog.logger.error("Error preparing span for ActionCable::Connection: #{e}")
31
- end
26
+ # Set the resource name of the trace
27
+ trace.resource = span.resource
32
28
 
33
29
  super
34
30
  end
@@ -7,6 +7,7 @@ require_relative '../ext'
7
7
  require_relative '../utils'
8
8
  require_relative '../../rack/middlewares'
9
9
  require_relative '../../analytics'
10
+ require_relative '../../../../core/telemetry/logger'
10
11
 
11
12
  module Datadog
12
13
  module Tracing
@@ -43,6 +44,7 @@ module Datadog
43
44
  span.set_tag(Tracing::Metadata::Ext::TAG_OPERATION, Ext::TAG_OPERATION_CONTROLLER)
44
45
  rescue StandardError => e
45
46
  Datadog.logger.error(e.message)
47
+ Datadog::Core::Telemetry::Logger.report(e)
46
48
  end
47
49
 
48
50
  def finish_processing(payload)
@@ -81,10 +83,13 @@ module Datadog
81
83
  end
82
84
  rescue StandardError => e
83
85
  Datadog.logger.error(e.message)
86
+ Datadog::Core::Telemetry::Logger.report(e)
84
87
  end
85
88
 
86
89
  # Instrumentation for ActionController::Metal
87
90
  module Metal
91
+ # TODO: Refactor this method to avoid using async API that splits the logic
92
+ # into two different methods (`start_processing` and `finish_processing`)
88
93
  def process_action(*args)
89
94
  # mutable payload with a tracing context that is used in two different
90
95
  # signals; it propagates the request span so that it can be finished
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../metadata/ext'
4
+
5
+ module Datadog
6
+ module Tracing
7
+ module Contrib
8
+ module ActionPack
9
+ module ActionDispatch
10
+ # Instrumentation for ActionDispatch components
11
+ module Instrumentation
12
+ module_function
13
+
14
+ def set_http_route_tags(route_spec, script_name)
15
+ return unless Tracing.enabled?
16
+
17
+ return unless route_spec
18
+
19
+ request_trace = Tracing.active_trace
20
+ return unless request_trace
21
+
22
+ request_trace.set_tag(Tracing::Metadata::Ext::HTTP::TAG_ROUTE, route_spec.to_s.gsub(/\(.:format\)\z/, ''))
23
+
24
+ if script_name && !script_name.empty?
25
+ request_trace.set_tag(Tracing::Metadata::Ext::HTTP::TAG_ROUTE_PATH, script_name)
26
+ end
27
+ end
28
+
29
+ def dispatcher_route?(route)
30
+ return true if route.dispatcher?
31
+
32
+ # in Rails 4 there is no #rack_app method on the app
33
+ return true if route.app.respond_to?(:rack_app) && !route.app.rack_app.nil?
34
+
35
+ false
36
+ end
37
+
38
+ # Instrumentation for ActionDispatch::Journey components
39
+ module Journey
40
+ # Instrumentation for ActionDispatch::Journey::Router for Rails versions older than 7.1
41
+ module Router
42
+ def find_routes(req)
43
+ result = super
44
+
45
+ # result is an array of [match, parameters, route] tuples
46
+ routes = result.map(&:last)
47
+
48
+ routes.each do |route|
49
+ if Instrumentation.dispatcher_route?(route)
50
+ Instrumentation.set_http_route_tags(route.path.spec, req.env['SCRIPT_NAME'])
51
+ break
52
+ end
53
+ end
54
+
55
+ result
56
+ end
57
+ end
58
+
59
+ # Since Rails 7.1 `Router#find_routes` makes the route computation lazy
60
+ # https://github.com/rails/rails/commit/35b280fcc2d5d474f9f2be3aca3ae7aa6bba66eb
61
+ module LazyRouter
62
+ def find_routes(req)
63
+ super do |match, parameters, route|
64
+ if Instrumentation.dispatcher_route?(route)
65
+ Instrumentation.set_http_route_tags(route.path.spec, req.env['SCRIPT_NAME'])
66
+ end
67
+
68
+ yield [match, parameters, route]
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../patcher'
4
+ require_relative 'instrumentation'
5
+
6
+ module Datadog
7
+ module Tracing
8
+ module Contrib
9
+ module ActionPack
10
+ module ActionDispatch
11
+ # Patcher for ActionController components
12
+ module Patcher
13
+ include Contrib::Patcher
14
+
15
+ module_function
16
+
17
+ def target_version
18
+ Integration.version
19
+ end
20
+
21
+ def patch
22
+ if ::ActionPack.gem_version >= Gem::Version.new('7.1')
23
+ ::ActionDispatch::Journey::Router.prepend(ActionDispatch::Instrumentation::Journey::LazyRouter)
24
+ else
25
+ ::ActionDispatch::Journey::Router.prepend(ActionDispatch::Instrumentation::Journey::Router)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative '../patcher'
4
4
  require_relative 'action_controller/patcher'
5
+ require_relative 'action_dispatch/patcher'
5
6
 
6
7
  module Datadog
7
8
  module Tracing
@@ -19,6 +20,7 @@ module Datadog
19
20
 
20
21
  def patch
21
22
  ActionController::Patcher.patch
23
+ ActionDispatch::Patcher.patch
22
24
  end
23
25
  end
24
26
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative '../../configuration/resolver'
4
4
  require_relative 'makara_resolver'
5
+ require_relative '../../../../core/telemetry/logger'
5
6
 
6
7
  module Datadog
7
8
  module Tracing
@@ -72,10 +73,12 @@ module Datadog
72
73
  #
73
74
  # `db_config` input may contain sensitive information such as passwords,
74
75
  # hence provide a succinct summary for the error logging.
76
+ #
75
77
  Datadog.logger.error(
76
78
  'Failed to resolve ActiveRecord database configuration. '\
77
79
  "Cause: #{e.class.name} Source: #{Array(e.backtrace).first}"
78
80
  )
81
+ Core::Telemetry::Logger.report(e, description: 'Failed to resolve ActiveRecord database configuration')
79
82
 
80
83
  nil
81
84
  end
@@ -95,6 +98,7 @@ module Datadog
95
98
  "Failed to resolve key #{matcher.inspect}. " \
96
99
  "Cause: #{e.class.name} Source: #{Array(e.backtrace).first}"
97
100
  )
101
+ Core::Telemetry::Logger.report(e, description: 'Failed to resolve key')
98
102
 
99
103
  nil
100
104
  end
@@ -4,6 +4,7 @@ require_relative '../../../metadata/ext'
4
4
  require_relative '../../analytics'
5
5
  require_relative '../ext'
6
6
  require_relative '../event'
7
+ require_relative '../../../../core/telemetry/logger'
7
8
 
8
9
  module Datadog
9
10
  module Tracing
@@ -48,7 +49,8 @@ module Datadog
48
49
  span.set_tag(Ext::TAG_INSTANTIATION_CLASS_NAME, payload.fetch(:class_name))
49
50
  span.set_tag(Ext::TAG_INSTANTIATION_RECORD_COUNT, payload.fetch(:record_count))
50
51
  rescue StandardError => e
51
- Datadog.logger.debug(e.message)
52
+ Datadog.logger.error(e.message)
53
+ Datadog::Core::Telemetry::Logger.report(e)
52
54
  end
53
55
  end
54
56
  end
@@ -6,6 +6,7 @@ require_relative '../event'
6
6
  require_relative '../ext'
7
7
  require_relative '../../analytics'
8
8
  require_relative '../../utils/database'
9
+ require_relative '../../../../core/telemetry/logger'
9
10
 
10
11
  module Datadog
11
12
  module Tracing
@@ -62,12 +63,14 @@ module Datadog
62
63
  cached = payload[:cached] || (payload[:name] == PAYLOAD_CACHE)
63
64
 
64
65
  span.set_tag(Ext::TAG_DB_VENDOR, adapter_name)
66
+ span.set_tag(Contrib::Ext::DB::TAG_INSTANCE, config[:database])
65
67
  span.set_tag(Ext::TAG_DB_NAME, config[:database])
66
68
  span.set_tag(Ext::TAG_DB_CACHED, cached) if cached
67
69
  span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_HOST, config[:host]) if config[:host]
68
70
  span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_PORT, config[:port]) if config[:port]
69
71
  rescue StandardError => e
70
- Datadog.logger.debug(e.message)
72
+ Datadog.logger.error(e.message)
73
+ Datadog::Core::Telemetry::Logger.report(e)
71
74
  end
72
75
  end
73
76
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative '../../ext'
4
4
  require_relative '../event'
5
+ require_relative '../../../../../core/telemetry/logger'
5
6
 
6
7
  module Datadog
7
8
  module Tracing
@@ -64,7 +65,7 @@ module Datadog
64
65
  key = payload[:key]
65
66
  store = payload[:store]
66
67
 
67
- mapping = MAPPING[event]
68
+ mapping = MAPPING.fetch(event)
68
69
 
69
70
  span.service = configuration[:cache_service]
70
71
  span.resource = mapping[:resource]
@@ -81,6 +82,9 @@ module Datadog
81
82
  span.set_tag('EVENT', event)
82
83
 
83
84
  set_cache_key(span, key, mapping[:multi_key])
85
+ rescue StandardError => e
86
+ Datadog.logger.error(e.message)
87
+ Datadog::Core::Telemetry::Logger.report(e)
84
88
  end
85
89
 
86
90
  def set_cache_key(span, key, multi_key)
@@ -29,6 +29,7 @@ module Datadog
29
29
  private
30
30
 
31
31
  # rubocop:disable Metrics/AbcSize
32
+ # rubocop:disable Metrics/MethodLength
32
33
  def annotate!(span, context)
33
34
  span.service = configuration[:service_name]
34
35
  span.type = Tracing::Metadata::Ext::HTTP::TYPE_OUTBOUND
@@ -76,7 +77,11 @@ module Datadog
76
77
  span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_STATUS_CODE, context.safely(:status_code))
77
78
 
78
79
  Contrib::SpanAttributeSchema.set_peer_service!(span, Ext::PEER_SERVICE_SOURCES)
80
+ rescue StandardError => e
81
+ Datadog.logger.error(e.message)
82
+ Datadog::Core::Telemetry::Logger.report(e)
79
83
  end
84
+ # rubocop:enable Metrics/MethodLength
80
85
  # rubocop:enable Metrics/AbcSize
81
86
 
82
87
  def configuration