datadog 2.30.0 → 2.32.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 (219) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +44 -1
  3. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +17 -7
  4. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +11 -4
  5. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +6 -0
  6. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +18 -0
  7. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +10 -0
  8. data/ext/datadog_profiling_native_extension/extconf.rb +7 -4
  9. data/ext/datadog_profiling_native_extension/http_transport.c +10 -5
  10. data/ext/libdatadog_api/crashtracker.c +5 -8
  11. data/ext/libdatadog_api/datadog_ruby_common.c +18 -0
  12. data/ext/libdatadog_api/datadog_ruby_common.h +10 -0
  13. data/ext/libdatadog_api/di.c +127 -0
  14. data/ext/libdatadog_api/extconf.rb +9 -4
  15. data/ext/libdatadog_api/init.c +5 -2
  16. data/ext/libdatadog_extconf_helpers.rb +46 -1
  17. data/lib/datadog/ai_guard/component.rb +2 -0
  18. data/lib/datadog/ai_guard/configuration.rb +105 -2
  19. data/lib/datadog/ai_guard/contrib/ruby_llm/chat_instrumentation.rb +41 -3
  20. data/lib/datadog/ai_guard/evaluation/content_builder.rb +31 -0
  21. data/lib/datadog/ai_guard/evaluation/content_part.rb +36 -0
  22. data/lib/datadog/ai_guard/evaluation/no_op_result.rb +3 -1
  23. data/lib/datadog/ai_guard/evaluation/request.rb +14 -9
  24. data/lib/datadog/ai_guard/evaluation/result.rb +3 -1
  25. data/lib/datadog/ai_guard/evaluation.rb +37 -7
  26. data/lib/datadog/ai_guard/ext.rb +1 -0
  27. data/lib/datadog/ai_guard.rb +26 -8
  28. data/lib/datadog/appsec/autoload.rb +1 -1
  29. data/lib/datadog/appsec/component.rb +11 -7
  30. data/lib/datadog/appsec/configuration.rb +414 -1
  31. data/lib/datadog/appsec/contrib/devise/patches/signin_tracking_patch.rb +2 -1
  32. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +6 -7
  33. data/lib/datadog/appsec/instrumentation/gateway.rb +0 -13
  34. data/lib/datadog/appsec/metrics/telemetry.rb +13 -1
  35. data/lib/datadog/appsec/monitor/gateway/watcher.rb +2 -0
  36. data/lib/datadog/appsec/security_engine/runner.rb +1 -1
  37. data/lib/datadog/appsec/trace_keeper.rb +18 -6
  38. data/lib/datadog/appsec/utils/http/media_type.rb +1 -2
  39. data/lib/datadog/appsec/utils/http/url_encoded.rb +3 -3
  40. data/lib/datadog/appsec.rb +5 -9
  41. data/lib/datadog/core/configuration/base.rb +17 -5
  42. data/lib/datadog/core/configuration/components.rb +22 -9
  43. data/lib/datadog/core/configuration/config_helper.rb +9 -0
  44. data/lib/datadog/core/configuration/option.rb +30 -5
  45. data/lib/datadog/core/configuration/option_definition.rb +38 -12
  46. data/lib/datadog/core/configuration/options.rb +40 -6
  47. data/lib/datadog/core/configuration/settings.rb +18 -0
  48. data/lib/datadog/core/configuration/supported_configurations.rb +3 -0
  49. data/lib/datadog/core/configuration.rb +1 -1
  50. data/lib/datadog/core/contrib/rails/railtie.rb +32 -0
  51. data/lib/datadog/core/contrib/rails/utils.rb +7 -3
  52. data/lib/datadog/core/crashtracking/component.rb +3 -3
  53. data/lib/datadog/core/diagnostics/environment_logger.rb +3 -1
  54. data/lib/datadog/core/environment/container.rb +2 -2
  55. data/lib/datadog/core/environment/ext.rb +1 -0
  56. data/lib/datadog/core/environment/identity.rb +25 -3
  57. data/lib/datadog/core/environment/process.rb +12 -0
  58. data/lib/datadog/core/feature_flags.rb +1 -1
  59. data/lib/datadog/core/metrics/client.rb +5 -5
  60. data/lib/datadog/core/remote/client.rb +1 -1
  61. data/lib/datadog/core/remote/component.rb +38 -21
  62. data/lib/datadog/core/runtime/metrics.rb +1 -1
  63. data/lib/datadog/core/telemetry/component.rb +3 -0
  64. data/lib/datadog/core/telemetry/emitter.rb +1 -1
  65. data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +2 -3
  66. data/lib/datadog/core/telemetry/event/app_extended_heartbeat.rb +32 -0
  67. data/lib/datadog/core/telemetry/event/app_started.rb +151 -169
  68. data/lib/datadog/core/telemetry/event.rb +1 -7
  69. data/lib/datadog/core/telemetry/ext.rb +1 -0
  70. data/lib/datadog/core/telemetry/transport/http/telemetry.rb +5 -0
  71. data/lib/datadog/core/telemetry/worker.rb +20 -0
  72. data/lib/datadog/core/transport/http.rb +2 -0
  73. data/lib/datadog/core/utils/only_once.rb +1 -1
  74. data/lib/datadog/core/utils/spawn_monkey_patch.rb +36 -0
  75. data/lib/datadog/core/utils.rb +1 -1
  76. data/lib/datadog/core/workers/async.rb +1 -1
  77. data/lib/datadog/core.rb +1 -2
  78. data/lib/datadog/data_streams/configuration.rb +40 -1
  79. data/lib/datadog/data_streams/pathway_context.rb +1 -1
  80. data/lib/datadog/data_streams/processor.rb +1 -1
  81. data/lib/datadog/data_streams.rb +1 -1
  82. data/lib/datadog/di/base.rb +8 -5
  83. data/lib/datadog/di/boot.rb +2 -4
  84. data/lib/datadog/di/code_tracker.rb +179 -1
  85. data/lib/datadog/di/component.rb +5 -1
  86. data/lib/datadog/di/configuration.rb +235 -2
  87. data/lib/datadog/di/instrumenter.rb +55 -29
  88. data/lib/datadog/di/probe_builder.rb +1 -1
  89. data/lib/datadog/di/probe_file_loader.rb +2 -2
  90. data/lib/datadog/di/probe_manager.rb +6 -6
  91. data/lib/datadog/di/probe_notification_builder.rb +110 -2
  92. data/lib/datadog/di/probe_notifier_worker.rb +2 -2
  93. data/lib/datadog/di/remote.rb +6 -6
  94. data/lib/datadog/di/transport/input.rb +3 -3
  95. data/lib/datadog/di.rb +81 -0
  96. data/lib/datadog/error_tracking/configuration.rb +55 -2
  97. data/lib/datadog/kit/enable_core_dumps.rb +1 -1
  98. data/lib/datadog/open_feature/component.rb +18 -1
  99. data/lib/datadog/open_feature/evaluation_engine.rb +2 -2
  100. data/lib/datadog/open_feature/hooks/flag_eval_hook.rb +49 -0
  101. data/lib/datadog/open_feature/metrics/flag_eval_metrics.rb +149 -0
  102. data/lib/datadog/open_feature/provider.rb +19 -1
  103. data/lib/datadog/open_feature/remote.rb +1 -1
  104. data/lib/datadog/open_feature/transport.rb +1 -1
  105. data/lib/datadog/opentelemetry/configuration/settings.rb +2 -0
  106. data/lib/datadog/opentelemetry/metrics.rb +3 -3
  107. data/lib/datadog/opentelemetry/sdk/configurator.rb +1 -1
  108. data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +1 -1
  109. data/lib/datadog/profiling/collectors/code_provenance.rb +36 -11
  110. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +31 -2
  111. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +8 -2
  112. data/lib/datadog/profiling/collectors/info.rb +16 -3
  113. data/lib/datadog/profiling/component.rb +12 -4
  114. data/lib/datadog/profiling/exporter.rb +37 -12
  115. data/lib/datadog/profiling/ext.rb +0 -2
  116. data/lib/datadog/profiling/flush.rb +21 -12
  117. data/lib/datadog/profiling/http_transport.rb +12 -1
  118. data/lib/datadog/profiling/load_native_extension.rb +2 -2
  119. data/lib/datadog/profiling/profiler.rb +13 -5
  120. data/lib/datadog/profiling/scheduler.rb +2 -2
  121. data/lib/datadog/profiling/tasks/exec.rb +8 -3
  122. data/lib/datadog/profiling/tasks/help.rb +1 -0
  123. data/lib/datadog/profiling/tasks/setup.rb +2 -2
  124. data/lib/datadog/profiling.rb +1 -2
  125. data/lib/datadog/single_step_instrument.rb +1 -1
  126. data/lib/datadog/symbol_database/configuration.rb +65 -0
  127. data/lib/datadog/symbol_database/extractor.rb +915 -0
  128. data/lib/datadog/symbol_database/file_hash.rb +46 -0
  129. data/lib/datadog/symbol_database/logger.rb +43 -0
  130. data/lib/datadog/symbol_database/scope.rb +98 -0
  131. data/lib/datadog/symbol_database/service_version.rb +57 -0
  132. data/lib/datadog/symbol_database/symbol.rb +66 -0
  133. data/lib/datadog/symbol_database/transport/http/endpoint.rb +28 -0
  134. data/lib/datadog/symbol_database/transport/http.rb +45 -0
  135. data/lib/datadog/symbol_database/transport.rb +54 -0
  136. data/lib/datadog/symbol_database/uploader.rb +166 -0
  137. data/lib/datadog/symbol_database.rb +49 -0
  138. data/lib/datadog/tracing/buffer.rb +3 -3
  139. data/lib/datadog/tracing/component.rb +11 -0
  140. data/lib/datadog/tracing/configuration/settings.rb +2 -1
  141. data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +5 -3
  142. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +20 -0
  143. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/patcher.rb +3 -1
  144. data/lib/datadog/tracing/contrib/action_view/events/render_template.rb +1 -1
  145. data/lib/datadog/tracing/contrib/active_job/events/discard.rb +1 -1
  146. data/lib/datadog/tracing/contrib/active_job/events/enqueue.rb +1 -1
  147. data/lib/datadog/tracing/contrib/active_job/events/enqueue_at.rb +1 -1
  148. data/lib/datadog/tracing/contrib/active_job/events/enqueue_retry.rb +1 -1
  149. data/lib/datadog/tracing/contrib/active_job/events/perform.rb +1 -1
  150. data/lib/datadog/tracing/contrib/active_job/events/retry_stopped.rb +1 -1
  151. data/lib/datadog/tracing/contrib/active_model_serializers/events/render.rb +1 -1
  152. data/lib/datadog/tracing/contrib/active_model_serializers/events/serialize.rb +1 -1
  153. data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +2 -2
  154. data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +1 -1
  155. data/lib/datadog/tracing/contrib/active_record/events/sql.rb +1 -1
  156. data/lib/datadog/tracing/contrib/active_record/utils.rb +1 -1
  157. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +1 -1
  158. data/lib/datadog/tracing/contrib/active_support/notifications/subscription.rb +2 -2
  159. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +1 -1
  160. data/lib/datadog/tracing/contrib/component.rb +1 -1
  161. data/lib/datadog/tracing/contrib/configurable.rb +18 -3
  162. data/lib/datadog/tracing/contrib/configuration/resolver.rb +7 -4
  163. data/lib/datadog/tracing/contrib/dalli/quantize.rb +1 -1
  164. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +1 -1
  165. data/lib/datadog/tracing/contrib/excon/middleware.rb +2 -2
  166. data/lib/datadog/tracing/contrib/extensions.rb +9 -0
  167. data/lib/datadog/tracing/contrib/faraday/middleware.rb +2 -2
  168. data/lib/datadog/tracing/contrib/grape/endpoint.rb +5 -5
  169. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +2 -2
  170. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +2 -2
  171. data/lib/datadog/tracing/contrib/http/instrumentation.rb +3 -3
  172. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +6 -2
  173. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +3 -3
  174. data/lib/datadog/tracing/contrib/kafka/instrumentation/consumer.rb +2 -2
  175. data/lib/datadog/tracing/contrib/kafka/instrumentation/producer.rb +2 -2
  176. data/lib/datadog/tracing/contrib/karafka/patcher.rb +1 -1
  177. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +3 -3
  178. data/lib/datadog/tracing/contrib/opensearch/patcher.rb +1 -1
  179. data/lib/datadog/tracing/contrib/presto/instrumentation.rb +3 -3
  180. data/lib/datadog/tracing/contrib/rack/patcher.rb +1 -1
  181. data/lib/datadog/tracing/contrib/rack/request_queue.rb +1 -1
  182. data/lib/datadog/tracing/contrib/rails/log_injection.rb +1 -1
  183. data/lib/datadog/tracing/contrib/rails/patcher.rb +0 -1
  184. data/lib/datadog/tracing/contrib/rails/runner.rb +1 -1
  185. data/lib/datadog/tracing/contrib/rake/instrumentation.rb +2 -2
  186. data/lib/datadog/tracing/contrib/redis/quantize.rb +1 -1
  187. data/lib/datadog/tracing/contrib/redis/tags.rb +1 -1
  188. data/lib/datadog/tracing/contrib/sidekiq/utils.rb +1 -1
  189. data/lib/datadog/tracing/contrib/status_range_matcher.rb +4 -0
  190. data/lib/datadog/tracing/contrib/stripe/request.rb +1 -1
  191. data/lib/datadog/tracing/contrib.rb +8 -0
  192. data/lib/datadog/tracing/diagnostics/environment_logger.rb +3 -1
  193. data/lib/datadog/tracing/distributed/baggage.rb +59 -5
  194. data/lib/datadog/tracing/distributed/datadog.rb +13 -11
  195. data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +1 -1
  196. data/lib/datadog/tracing/distributed/propagation.rb +2 -2
  197. data/lib/datadog/tracing/distributed/trace_context.rb +74 -32
  198. data/lib/datadog/tracing/event.rb +1 -1
  199. data/lib/datadog/tracing/metadata/tagging.rb +2 -2
  200. data/lib/datadog/tracing/pipeline.rb +1 -1
  201. data/lib/datadog/tracing/remote.rb +1 -1
  202. data/lib/datadog/tracing/sampling/ext.rb +2 -0
  203. data/lib/datadog/tracing/sampling/priority_sampler.rb +13 -0
  204. data/lib/datadog/tracing/sampling/rule.rb +1 -1
  205. data/lib/datadog/tracing/sampling/rule_sampler.rb +54 -25
  206. data/lib/datadog/tracing/sampling/span/rule_parser.rb +2 -2
  207. data/lib/datadog/tracing/span_operation.rb +4 -4
  208. data/lib/datadog/tracing/trace_operation.rb +53 -9
  209. data/lib/datadog/tracing/tracer.rb +29 -4
  210. data/lib/datadog/tracing/transport/io/client.rb +1 -1
  211. data/lib/datadog/tracing/transport/trace_formatter.rb +1 -1
  212. data/lib/datadog/tracing/workers.rb +2 -1
  213. data/lib/datadog/version.rb +1 -1
  214. metadata +27 -12
  215. data/lib/datadog/ai_guard/configuration/settings.rb +0 -113
  216. data/lib/datadog/appsec/configuration/settings.rb +0 -423
  217. data/lib/datadog/data_streams/configuration/settings.rb +0 -49
  218. data/lib/datadog/di/configuration/settings.rb +0 -243
  219. data/lib/datadog/error_tracking/configuration/settings.rb +0 -63
@@ -14,6 +14,9 @@ module Datadog
14
14
  #
15
15
  # This class acts both as a collector (collecting data) as well as a recorder (records/serializes it)
16
16
  class CodeProvenance
17
+ # @rbs standard_library_path: ::String
18
+ # @rbs ruby_native_filename: ::String?
19
+ # @rbs return: void
17
20
  def initialize(
18
21
  standard_library_path: RbConfig::CONFIG.fetch("rubylibdir"),
19
22
  ruby_native_filename: Datadog::Profiling::Collectors::Stack._native_ruby_native_filename
@@ -35,6 +38,9 @@ module Datadog
35
38
  )
36
39
  end
37
40
 
41
+ # @rbs loaded_files: ::Array[::String]
42
+ # @rbs loaded_specs: ::Array[::Gem::BasicSpecification]
43
+ # @rbs return: self
38
44
  def refresh(loaded_files: $LOADED_FEATURES, loaded_specs: Gem.loaded_specs.values)
39
45
  record_loaded_specs(loaded_specs)
40
46
  record_loaded_files(loaded_files)
@@ -42,19 +48,20 @@ module Datadog
42
48
  self
43
49
  end
44
50
 
51
+ #: () -> ::String
45
52
  def generate_json
46
53
  JSON.generate(v1: seen_libraries.to_a)
47
54
  end
48
55
 
49
56
  private
50
57
 
51
- attr_reader \
52
- :libraries_by_name,
53
- :libraries_by_path,
54
- :seen_files,
55
- :seen_libraries,
56
- :executable_paths
58
+ attr_reader :libraries_by_name #: ::Hash[::String, Library]
59
+ attr_reader :libraries_by_path #: ::Hash[::String, Library]
60
+ attr_reader :seen_files #: ::Set[::String]
61
+ attr_reader :seen_libraries #: ::Set[Library]
62
+ attr_reader :executable_paths #: ::Array[::String]
57
63
 
64
+ #: (Library) -> void
58
65
  def record_library(library)
59
66
  libraries_by_name[library.name] = library
60
67
  libraries_by_path[library.path] = library
@@ -71,10 +78,12 @@ module Datadog
71
78
  #
72
79
  # Alternatively/in the future we could instead use a trie to match paths, but I doubt for the data sizes we're
73
80
  # looking at that a trie is that much faster than using Ruby's built-in native collections.
81
+ #: () -> void
74
82
  def sort_libraries_by_longest_path_first
75
83
  @libraries_by_path = @libraries_by_path.sort.reverse!.to_h
76
84
  end
77
85
 
86
+ #: (::Array[::Gem::BasicSpecification]) -> void
78
87
  def record_loaded_specs(loaded_specs)
79
88
  recorded_library = false
80
89
 
@@ -103,6 +112,7 @@ module Datadog
103
112
  sort_libraries_by_longest_path_first if recorded_library
104
113
  end
105
114
 
115
+ #: (::Array[::String]) -> void
106
116
  def record_loaded_files(loaded_files)
107
117
  loaded_files.each do |file_path|
108
118
  next if seen_files.include?(file_path)
@@ -125,6 +135,7 @@ module Datadog
125
135
  # bundler complaints here impacting the application. (Bundler tends to go "something is wrong, raise!" which
126
136
  # I think makes a lot of sense given how bundler is intended to be used, but for this our kind of "ask a few
127
137
  # questions usage" it's not what we want.)
138
+ #: () -> ::String?
128
139
  def bundler_bin_path
129
140
  return unless defined?(Bundler)
130
141
 
@@ -135,7 +146,7 @@ module Datadog
135
146
  rescue Exception => e # rubocop:disable Lint/RescueException
136
147
  Datadog.logger.debug(
137
148
  "CodeProvenance#bundler_bin_path failed. " \
138
- "Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
149
+ "Cause: #{e.class}: #{e.message} Location: #{Array(e.backtrace).first}"
139
150
  )
140
151
  nil
141
152
  end
@@ -149,8 +160,21 @@ module Datadog
149
160
  # Thus, this class was setup to match the JSON output. Take this into consideration if you are adding new
150
161
  # fields. (Also, we have a spec for this)
151
162
  class Library
152
- attr_reader :kind, :name, :version
153
-
163
+ # @rbs @kind: ::String
164
+ # @rbs @name: ::String
165
+ # @rbs @version: ::String
166
+ # @rbs @paths: ::Array[::String]
167
+
168
+ attr_reader :kind #: ::String
169
+ attr_reader :name #: ::String
170
+ attr_reader :version #: ::String
171
+
172
+ # @rbs kind: ::String
173
+ # @rbs name: ::String
174
+ # @rbs version: ::String | ::Gem::Version
175
+ # @rbs path: ::String
176
+ # @rbs extra_paths: ::Array[::String?]
177
+ # @rbs return: void
154
178
  def initialize(kind:, name:, version:, path:, extra_paths:)
155
179
  extra_paths = Array(extra_paths).compact.reject(&:empty?).map { |p| p.dup.freeze }
156
180
  @kind = kind.freeze
@@ -160,11 +184,12 @@ module Datadog
160
184
  freeze
161
185
  end
162
186
 
187
+ #: (?::JSON::State?) -> ::String
163
188
  def to_json(arg = nil)
164
- # Steep: https://github.com/ruby/rbs/pull/2691 (remove after RBS 4.0 release)
165
- {kind: @kind, name: @name, version: @version, paths: @paths}.to_json(arg) # steep:ignore ArgumentTypeMismatch
189
+ {kind: @kind, name: @name, version: @version, paths: @paths}.to_json(arg)
166
190
  end
167
191
 
192
+ #: () -> ::String
168
193
  def path
169
194
  @paths.first
170
195
  end
@@ -9,12 +9,32 @@ module Datadog
9
9
  #
10
10
  # Methods prefixed with _native_ are implemented in `collectors_cpu_and_wall_time_worker.c`
11
11
  class CpuAndWallTimeWorker
12
+ # @rbs @worker_thread: untyped
13
+ # @rbs @start_stop_mutex: ::Thread::Mutex
14
+ # @rbs @failure_exception: ::Exception?
15
+ # @rbs @idle_sampling_helper: IdleSamplingHelper
16
+ # @rbs @wait_until_running_mutex: ::Thread::Mutex
17
+ # @rbs @wait_until_running_condition: ::Thread::ConditionVariable
18
+
12
19
  private
13
20
 
14
- attr_accessor :failure_exception
21
+ attr_accessor :failure_exception #: ::Exception?
15
22
 
16
23
  public
17
24
 
25
+ # @rbs gc_profiling_enabled: bool
26
+ # @rbs no_signals_workaround_enabled: bool
27
+ # @rbs thread_context_collector: Datadog::Profiling::Collectors::ThreadContext
28
+ # @rbs dynamic_sampling_rate_overhead_target_percentage: Float
29
+ # @rbs cpu_sampling_interval_ms: ::Integer
30
+ # @rbs idle_sampling_helper: Datadog::Profiling::Collectors::IdleSamplingHelper
31
+ # @rbs dynamic_sampling_rate_enabled: bool
32
+ # @rbs allocation_profiling_enabled: bool
33
+ # @rbs allocation_counting_enabled: bool
34
+ # @rbs gvl_profiling_enabled: bool
35
+ # @rbs sighandler_sampling_enabled: bool
36
+ # @rbs skip_idle_samples_for_testing: false
37
+ # @rbs return: void
18
38
  def initialize(
19
39
  gc_profiling_enabled:,
20
40
  no_signals_workaround_enabled:,
@@ -67,6 +87,8 @@ module Datadog
67
87
  @wait_until_running_condition = ConditionVariable.new
68
88
  end
69
89
 
90
+ # @rbs on_failure_proc: (^(?log_failure: bool) -> void)?
91
+ # @rbs return: bool?
70
92
  def start(on_failure_proc: nil)
71
93
  @start_stop_mutex.synchronize do
72
94
  return if @worker_thread&.alive?
@@ -93,7 +115,7 @@ module Datadog
93
115
  operation_name = self.class._native_failure_exception_during_operation(self).inspect
94
116
  Datadog.logger.warn(
95
117
  "CpuAndWallTimeWorker thread error. " \
96
- "Operation: #{operation_name} Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
118
+ "Operation: #{operation_name} Cause: #{e.class}: #{e.message} Location: #{Array(e.backtrace).first}"
97
119
  )
98
120
  on_failure_proc&.call
99
121
  Datadog::Core::Telemetry::Logger.report(e, description: "CpuAndWallTimeWorker thread error: #{operation_name}")
@@ -105,6 +127,7 @@ module Datadog
105
127
  true
106
128
  end
107
129
 
130
+ #: () -> void
108
131
  def stop
109
132
  @start_stop_mutex.synchronize do
110
133
  Datadog.logger.debug("Requesting CpuAndWallTimeWorker thread shut down")
@@ -121,14 +144,17 @@ module Datadog
121
144
  end
122
145
  end
123
146
 
147
+ #: () -> true
124
148
  def reset_after_fork
125
149
  self.class._native_reset_after_fork(self)
126
150
  end
127
151
 
152
+ #: () -> ::Hash[::Symbol, untyped]
128
153
  def stats
129
154
  self.class._native_stats(self)
130
155
  end
131
156
 
157
+ #: () -> ::Hash[::Symbol, untyped]
132
158
  def stats_and_reset_not_thread_safe
133
159
  stats = self.stats
134
160
  self.class._native_stats_reset_not_thread_safe(self)
@@ -136,6 +162,8 @@ module Datadog
136
162
  end
137
163
 
138
164
  # Useful for testing, to e.g. make sure the profiler is running before we start running some code we want to observe
165
+ # @rbs timeout_seconds: ::Integer?
166
+ # @rbs return: true
139
167
  def wait_until_running(timeout_seconds: 5)
140
168
  @wait_until_running_mutex.synchronize do
141
169
  return true if self.class._native_is_running?(self)
@@ -152,6 +180,7 @@ module Datadog
152
180
 
153
181
  private
154
182
 
183
+ #: () -> void
155
184
  def signal_running
156
185
  @wait_until_running_mutex.synchronize { @wait_until_running_condition.broadcast }
157
186
  end
@@ -8,17 +8,22 @@ module Datadog
8
8
  #
9
9
  # Methods prefixed with _native_ are implemented in `collectors_idle_sampling_helper.c`
10
10
  class IdleSamplingHelper
11
+ # @rbs @worker_thread: untyped
12
+ # @rbs @start_stop_mutex: ::Thread::Mutex
13
+
11
14
  private
12
15
 
13
- attr_accessor :failure_exception
16
+ attr_accessor :failure_exception #: ::Exception?
14
17
 
15
18
  public
16
19
 
20
+ #: () -> void
17
21
  def initialize
18
22
  @worker_thread = nil
19
23
  @start_stop_mutex = Mutex.new
20
24
  end
21
25
 
26
+ #: () -> (nil | true)
22
27
  def start
23
28
  @start_stop_mutex.synchronize do
24
29
  return if @worker_thread&.alive?
@@ -39,7 +44,7 @@ module Datadog
39
44
  @failure_exception = e
40
45
  Datadog.logger.warn(
41
46
  "IdleSamplingHelper thread error. " \
42
- "Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
47
+ "Cause: #{e.class}: #{e.message} Location: #{Array(e.backtrace).first}"
43
48
  )
44
49
  Datadog::Core::Telemetry::Logger.report(e, description: "IdleSamplingHelper thread error")
45
50
  end
@@ -50,6 +55,7 @@ module Datadog
50
55
  true
51
56
  end
52
57
 
58
+ #: () -> void
53
59
  def stop
54
60
  @start_stop_mutex.synchronize do
55
61
  Datadog.logger.debug("Requesting IdleSamplingHelper thread shut down")
@@ -14,11 +14,18 @@ module Datadog
14
14
  # could be seen as overkill for this case but it allows us to centralize information
15
15
  # gathering and easily support more flexible/dynamic info collection in the future.
16
16
  class Info
17
+ # @rbs @info: ::Hash[::Symbol, ::Hash[::Symbol, untyped]]
18
+ # @rbs @platform_info: ::Hash[::Symbol, untyped]
19
+ # @rbs @runtime_info: ::Hash[::Symbol, untyped]
20
+ # @rbs @application_info: ::Hash[::Symbol, untyped]
21
+ # @rbs @profiler_info: ::Hash[::Symbol, untyped]?
22
+ # @rbs @gc_tuning_info: ::Hash[::Symbol, ::String]
23
+
24
+ #: (untyped) -> void
17
25
  def initialize(settings)
18
26
  @profiler_info = nil
19
27
 
20
- # Steep: https://github.com/soutaro/steep/issues/363
21
- @info = { # steep:ignore IncompatibleAssignment
28
+ @info = {
22
29
  platform: collect_platform_info,
23
30
  runtime: collect_runtime_info,
24
31
  application: collect_application_info(settings),
@@ -26,7 +33,7 @@ module Datadog
26
33
  }.freeze
27
34
  end
28
35
 
29
- attr_reader :info
36
+ attr_reader :info #: ::Hash[::Symbol, ::Hash[::Symbol, untyped]]
30
37
 
31
38
  private
32
39
 
@@ -69,6 +76,7 @@ module Datadog
69
76
  # gets initialized before a user has a chance to configure the library.
70
77
  START_TIME = Time.now.utc.freeze
71
78
 
79
+ #: () -> ::Hash[::Symbol, untyped]
72
80
  def collect_platform_info
73
81
  @platform_info ||= {
74
82
  container_id: Datadog::Core::Environment::Container.container_id,
@@ -79,6 +87,7 @@ module Datadog
79
87
  }.freeze
80
88
  end
81
89
 
90
+ #: () -> ::Hash[::Symbol, untyped]
82
91
  def collect_runtime_info
83
92
  @runtime_info ||= {
84
93
  engine: Datadog::Core::Environment::Identity.lang_engine,
@@ -88,6 +97,7 @@ module Datadog
88
97
  }.freeze
89
98
  end
90
99
 
100
+ #: (untyped) -> ::Hash[::Symbol, untyped]
91
101
  def collect_application_info(settings)
92
102
  @application_info ||= {
93
103
  start_time: START_TIME.iso8601,
@@ -97,6 +107,7 @@ module Datadog
97
107
  }.freeze
98
108
  end
99
109
 
110
+ #: (untyped) -> ::Hash[::Symbol, untyped]
100
111
  def collect_profiler_info(settings)
101
112
  @profiler_info ||= begin
102
113
  lib_datadog_gem = ::Gem.loaded_specs["libdatadog"]
@@ -123,6 +134,7 @@ module Datadog
123
134
  # instances without proper serialization.
124
135
  # This method navigates a settings object recursively, converting
125
136
  # it into more basic types that are trivially convertible to JSON.
137
+ #: (untyped) -> untyped
126
138
  def collect_settings_recursively(v)
127
139
  v = v.options_hash if v.respond_to?(:options_hash)
128
140
 
@@ -143,6 +155,7 @@ module Datadog
143
155
  end
144
156
  end
145
157
 
158
+ #: () -> ::Hash[::Symbol, ::String]
146
159
  def collect_gc_tuning_info
147
160
  return @gc_tuning_info if defined?(@gc_tuning_info)
148
161
 
@@ -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
  # Responsible for wiring up the Profiler for execution
@@ -8,8 +10,6 @@ module Datadog
8
10
  # * Profiling in the trace viewer, as well as scoping a profile down to a span
9
11
  # * Endpoint aggregation in the profiler UX, including normalization (resource per endpoint call)
10
12
  def self.build_profiler_component(settings:, agent_settings:, optional_tracer:, logger:) # rubocop:disable Metrics/MethodLength
11
- return [nil, {profiling_enabled: false}] unless settings.profiling.enabled
12
-
13
13
  # Workaround for weird dependency direction: the Core::Configuration::Components class currently has a
14
14
  # dependency on individual products, in this case the Profiler.
15
15
  # (Note "currently": in the future we want to change this so core classes don't depend on specific products)
@@ -29,7 +29,7 @@ module Datadog
29
29
  # no-op if profiling is already loaded).
30
30
  require_relative "../profiling"
31
31
 
32
- return [nil, {profiling_enabled: false}] unless Profiling.supported?
32
+ return [nil, {profiling_enabled: false}] unless settings.profiling.enabled && Profiling.supported?
33
33
 
34
34
  # Activate forking extensions
35
35
  Profiling::Tasks::Setup.new.run
@@ -90,6 +90,14 @@ module Datadog
90
90
  end
91
91
 
92
92
  [profiler, {profiling_enabled: true}]
93
+ rescue Exception => e # rubocop:disable Lint/RescueException
94
+ logger.warn do
95
+ "Failed to initialize profiling: #{e.class}: #{e.message} " \
96
+ "Location: #{Array(e.backtrace).first}"
97
+ end
98
+ Datadog::Core::Telemetry::Logger.report(e, description: "Failed to initialize profiling")
99
+
100
+ [nil, {profiling_enabled: false}]
93
101
  end
94
102
 
95
103
  private_class_method def self.build_thread_context_collector(settings, recorder, optional_tracer, timeline_enabled)
@@ -368,7 +376,7 @@ module Datadog
368
376
  rescue StandardError, LoadError => e
369
377
  logger.warn(
370
378
  "Failed to probe `mysql2` gem information. " \
371
- "Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
379
+ "Cause: #{e.class}: #{e.message} Location: #{Array(e.backtrace).first}"
372
380
  )
373
381
 
374
382
  true
@@ -13,24 +13,35 @@ module Datadog
13
13
  # recorders, so I've decided to make it specific until we actually need to support more recorders.
14
14
  #
15
15
  class Exporter
16
+ # @rbs @worker: Datadog::Profiling::Collectors::CpuAndWallTimeWorker
17
+
16
18
  # Profiles with duration less than this will not be reported
17
19
  PROFILE_DURATION_THRESHOLD_SECONDS = 1
18
20
 
19
21
  private
20
22
 
21
- attr_reader \
22
- :pprof_recorder,
23
- :code_provenance_collector, # The code provenance collector acts both as collector and as a recorder
24
- :minimum_duration_seconds,
25
- :time_provider,
26
- :last_flush_finish_at,
27
- :created_at,
28
- :internal_metadata,
29
- :info_json,
30
- :sequence_tracker
23
+ attr_reader :pprof_recorder #: Datadog::Profiling::StackRecorder
24
+ # The code provenance collector acts both as collector and as a recorder
25
+ attr_reader :code_provenance_collector #: Datadog::Profiling::Collectors::CodeProvenance?
26
+ attr_reader :minimum_duration_seconds #: ::Integer
27
+ attr_reader :time_provider #: singleton(::Time)
28
+ attr_reader :last_flush_finish_at #: ::Time?
29
+ attr_reader :created_at #: ::Time
30
+ attr_reader :internal_metadata #: ::Hash[::Symbol, untyped]
31
+ attr_reader :info_json #: ::String
32
+ attr_reader :sequence_tracker #: singleton(Datadog::Profiling::SequenceTracker)
31
33
 
32
34
  public
33
35
 
36
+ # @rbs pprof_recorder: Datadog::Profiling::StackRecorder
37
+ # @rbs worker: Datadog::Profiling::Collectors::CpuAndWallTimeWorker
38
+ # @rbs info_collector: Datadog::Profiling::Collectors::Info
39
+ # @rbs code_provenance_collector: Datadog::Profiling::Collectors::CodeProvenance?
40
+ # @rbs internal_metadata: ::Hash[::Symbol, untyped]
41
+ # @rbs minimum_duration_seconds: ::Integer
42
+ # @rbs time_provider: singleton(::Time)
43
+ # @rbs sequence_tracker: singleton(Datadog::Profiling::SequenceTracker)
44
+ # @rbs return: void
34
45
  def initialize(
35
46
  pprof_recorder:,
36
47
  worker:,
@@ -55,6 +66,7 @@ module Datadog
55
66
  @sequence_tracker = sequence_tracker
56
67
  end
57
68
 
69
+ #: () -> Datadog::Profiling::Flush?
58
70
  def flush
59
71
  worker_stats = @worker.stats_and_reset_not_thread_safe
60
72
  serialization_result = pprof_recorder.serialize
@@ -68,7 +80,17 @@ module Datadog
68
80
  return
69
81
  end
70
82
 
71
- uncompressed_code_provenance = code_provenance_collector.refresh.generate_json if code_provenance_collector
83
+ uncompressed_code_provenance =
84
+ if (collector = code_provenance_collector)
85
+ collector.refresh.generate_json
86
+ end
87
+
88
+ metrics = [] #: Array[[::String, ::Numeric]]
89
+
90
+ # The key is always there, but the value might be nil if GVL profiling is disabled.
91
+ # We delete it to avoid reporting the same data point twice.
92
+ gvl_waiting_time_ns_total = worker_stats.delete(:gvl_waiting_time_ns_total)
93
+ metrics << ["ruby_global_lock_wait_time_total", gvl_waiting_time_ns_total] if gvl_waiting_time_ns_total
72
94
 
73
95
  process_tags = Datadog.configuration.experimental_propagate_process_tags_enabled ?
74
96
  Core::Environment::Process.serialized : ''
@@ -77,8 +99,8 @@ module Datadog
77
99
  start: start,
78
100
  finish: finish,
79
101
  encoded_profile: encoded_profile,
80
- code_provenance_file_name: Datadog::Profiling::Ext::Transport::HTTP::CODE_PROVENANCE_FILENAME,
81
102
  code_provenance_data: uncompressed_code_provenance,
103
+ metrics: metrics,
82
104
  tags_as_array: Datadog::Profiling::TagBuilder.call(
83
105
  settings: Datadog.configuration,
84
106
  profile_seq: sequence_tracker.get_next,
@@ -96,10 +118,12 @@ module Datadog
96
118
  )
97
119
  end
98
120
 
121
+ #: () -> bool
99
122
  def can_flush?
100
123
  !duration_below_threshold?(last_flush_finish_at || created_at, time_provider.now.utc)
101
124
  end
102
125
 
126
+ #: () -> void
103
127
  def reset_after_fork
104
128
  @last_flush_finish_at = time_provider.now.utc
105
129
  nil
@@ -107,6 +131,7 @@ module Datadog
107
131
 
108
132
  private
109
133
 
134
+ #: (::Time, ::Time) -> bool
110
135
  def duration_below_threshold?(start, finish)
111
136
  (finish - start) < minimum_duration_seconds
112
137
  end
@@ -13,8 +13,6 @@ module Datadog
13
13
  module Transport
14
14
  module HTTP
15
15
  FORM_FIELD_TAG_PROFILER_VERSION = "profiler_version"
16
-
17
- CODE_PROVENANCE_FILENAME = "code-provenance.json"
18
16
  end
19
17
  end
20
18
  end
@@ -6,23 +6,32 @@ module Datadog
6
6
  module Profiling
7
7
  # Entity class used to represent metadata for a given profile
8
8
  class Flush
9
- attr_reader \
10
- :start,
11
- :finish,
12
- :encoded_profile,
13
- :code_provenance_file_name,
14
- :code_provenance_data,
15
- :tags_as_array,
16
- :process_tags,
17
- :internal_metadata_json,
18
- :info_json
9
+ attr_reader :start #: ::Time
10
+ attr_reader :finish #: ::Time
11
+ attr_reader :encoded_profile #: Datadog::Profiling::EncodedProfile
12
+ attr_reader :code_provenance_data #: ::String?
13
+ attr_reader :metrics #: ::String
14
+ attr_reader :tags_as_array #: Array[[::String, ::String]]
15
+ attr_reader :process_tags #: ::String
16
+ attr_reader :internal_metadata_json #: ::String
17
+ attr_reader :info_json #: ::String
19
18
 
19
+ # @rbs start: ::Time
20
+ # @rbs finish: ::Time
21
+ # @rbs encoded_profile: Datadog::Profiling::EncodedProfile
22
+ # @rbs code_provenance_data: ::String?
23
+ # @rbs metrics: Array[[::String, ::Numeric]]
24
+ # @rbs tags_as_array: Array[[::String, ::String]]
25
+ # @rbs process_tags: ::String
26
+ # @rbs internal_metadata: ::Hash[::Symbol, ::String | bool | ::Numeric]
27
+ # @rbs info_json: ::String
28
+ # @rbs return: void
20
29
  def initialize(
21
30
  start:,
22
31
  finish:,
23
32
  encoded_profile:,
24
- code_provenance_file_name:,
25
33
  code_provenance_data:,
34
+ metrics:,
26
35
  tags_as_array:,
27
36
  process_tags:,
28
37
  internal_metadata:,
@@ -31,8 +40,8 @@ module Datadog
31
40
  @start = start
32
41
  @finish = finish
33
42
  @encoded_profile = encoded_profile
34
- @code_provenance_file_name = code_provenance_file_name
35
43
  @code_provenance_data = code_provenance_data
44
+ @metrics = JSON.generate(metrics)
36
45
  @tags_as_array = tags_as_array
37
46
  @process_tags = process_tags
38
47
  @internal_metadata_json = JSON.generate(internal_metadata)
@@ -8,8 +8,16 @@ module Datadog
8
8
  # Used to report profiling data to Datadog.
9
9
  # Methods prefixed with _native_ are implemented in `http_transport.c`
10
10
  class HttpTransport
11
- attr_reader :exporter_configuration
11
+ # @rbs @exporter_configuration: exporter_configuration_array
12
12
 
13
+ attr_reader :exporter_configuration #: exporter_configuration_array
14
+
15
+ # @rbs agent_settings: Datadog::Core::Configuration::AgentSettings
16
+ # @rbs site: ::String?
17
+ # @rbs api_key: ::String?
18
+ # @rbs upload_timeout_seconds: ::Integer
19
+ # @rbs use_system_dns: bool
20
+ # @rbs return: void
13
21
  def initialize(agent_settings:, site:, api_key:, upload_timeout_seconds:, use_system_dns:)
14
22
  timeout_milliseconds = (upload_timeout_seconds * 1_000).to_i
15
23
 
@@ -28,6 +36,7 @@ module Datadog
28
36
  raise(ArgumentError, "Failed to initialize transport: #{result}") if status == :error
29
37
  end
30
38
 
39
+ #: (Datadog::Profiling::Flush) -> bool
31
40
  def export(flush)
32
41
  status, result = self.class._native_do_export(
33
42
  exporter_configuration,
@@ -57,10 +66,12 @@ module Datadog
57
66
 
58
67
  private
59
68
 
69
+ #: (::String?, ::String?) -> bool?
60
70
  def agentless?(site, api_key)
61
71
  site && api_key && %w[1 true].include?(ENV[Profiling::Ext::ENV_AGENTLESS] || '') # rubocop:disable CustomCops/EnvUsageCop
62
72
  end
63
73
 
74
+ #: () -> ::String
64
75
  def config_without_api_key
65
76
  "#{exporter_configuration[0]}: #{exporter_configuration[3]}"
66
77
  end
@@ -4,6 +4,6 @@ begin
4
4
  require "datadog_profiling_native_extension.#{RUBY_VERSION}_#{RUBY_PLATFORM}"
5
5
  rescue LoadError => e
6
6
  raise LoadError,
7
- "Failed to load the profiling loader extension. To fix this, please remove and then reinstall datadog " \
8
- "(Details: #{e.message})"
7
+ "Failed to load the profiling native extension. To fix this, please remove and then reinstall datadog " \
8
+ "(Details: #{e.class}: #{e.message})"
9
9
  end
@@ -8,19 +8,20 @@ module Datadog
8
8
 
9
9
  private
10
10
 
11
- attr_reader :worker, :scheduler
11
+ attr_reader :worker #: Datadog::Profiling::Collectors::CpuAndWallTimeWorker
12
+ attr_reader :scheduler #: Datadog::Profiling::Scheduler
12
13
 
13
14
  public
14
15
 
16
+ # @rbs worker: Datadog::Profiling::Collectors::CpuAndWallTimeWorker
17
+ # @rbs scheduler: Datadog::Profiling::Scheduler
18
+ # @rbs return: void
15
19
  def initialize(worker:, scheduler:)
16
20
  @worker = worker
17
21
  @scheduler = scheduler
18
22
  end
19
23
 
20
- def enabled?
21
- scheduler.running?
22
- end
23
-
24
+ #: () -> void
24
25
  def start
25
26
  after_fork! do
26
27
  worker.reset_after_fork
@@ -36,6 +37,8 @@ module Datadog
36
37
  scheduler.start(on_failure_proc: proc { component_failed(:scheduler) })
37
38
  end
38
39
 
40
+ # @rbs report_last_profile: bool
41
+ # @rbs return: void
39
42
  def shutdown!(report_last_profile: true)
40
43
  Datadog.logger.debug("Shutting down profiler")
41
44
 
@@ -46,15 +49,20 @@ module Datadog
46
49
 
47
50
  private
48
51
 
52
+ #: () -> void
49
53
  def stop_worker
50
54
  worker.stop
51
55
  end
52
56
 
57
+ #: () -> void
53
58
  def stop_scheduler
54
59
  scheduler.enabled = false
55
60
  scheduler.stop(true)
56
61
  end
57
62
 
63
+ # @rbs failed_component: :worker | :scheduler | ::Symbol
64
+ # @rbs log_failure: bool
65
+ # @rbs return: void
58
66
  def component_failed(failed_component, log_failure: true)
59
67
  if log_failure
60
68
  Datadog.logger.warn(
@@ -65,7 +65,7 @@ module Datadog
65
65
  rescue Exception => e # rubocop:disable Lint/RescueException
66
66
  Datadog.logger.warn(
67
67
  "Profiling::Scheduler thread error. " \
68
- "Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
68
+ "Cause: #{e.class}: #{e.message} Location: #{Array(e.backtrace).first}"
69
69
  )
70
70
  on_failure_proc&.call
71
71
  Datadog::Core::Telemetry::Logger.report(e, description: "Profiling::Scheduler thread error")
@@ -136,7 +136,7 @@ module Datadog
136
136
  transport.export(flush)
137
137
  rescue => e
138
138
  Datadog.logger.warn(
139
- "Unable to report profile. Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
139
+ "Unable to report profile. Cause: #{e.class}: #{e.message} Location: #{Array(e.backtrace).first}"
140
140
  )
141
141
  Datadog::Core::Telemetry::Logger.report(e, description: "Unable to report profile")
142
142
  end