datadog 2.2.0 → 2.3.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 (113) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +51 -2
  3. data/ext/datadog_profiling_loader/extconf.rb +15 -15
  4. data/ext/datadog_profiling_native_extension/clock_id.h +1 -0
  5. data/ext/datadog_profiling_native_extension/clock_id_from_pthread.c +1 -2
  6. data/ext/datadog_profiling_native_extension/clock_id_noop.c +1 -2
  7. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +113 -43
  8. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +49 -26
  9. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h +34 -4
  10. data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +4 -0
  11. data/ext/datadog_profiling_native_extension/collectors_stack.c +49 -37
  12. data/ext/datadog_profiling_native_extension/collectors_stack.h +2 -2
  13. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +81 -19
  14. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +1 -0
  15. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +110 -0
  16. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +57 -0
  17. data/ext/datadog_profiling_native_extension/extconf.rb +65 -60
  18. data/ext/datadog_profiling_native_extension/heap_recorder.c +34 -6
  19. data/ext/datadog_profiling_native_extension/heap_recorder.h +3 -1
  20. data/ext/datadog_profiling_native_extension/helpers.h +6 -17
  21. data/ext/datadog_profiling_native_extension/http_transport.c +3 -3
  22. data/ext/datadog_profiling_native_extension/libdatadog_helpers.c +0 -86
  23. data/ext/datadog_profiling_native_extension/libdatadog_helpers.h +2 -23
  24. data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +61 -172
  25. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +64 -138
  26. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +17 -11
  27. data/ext/datadog_profiling_native_extension/profiling.c +0 -2
  28. data/ext/datadog_profiling_native_extension/ruby_helpers.c +0 -33
  29. data/ext/datadog_profiling_native_extension/ruby_helpers.h +1 -26
  30. data/ext/datadog_profiling_native_extension/setup_signal_handler.h +1 -0
  31. data/ext/datadog_profiling_native_extension/stack_recorder.c +14 -2
  32. data/ext/datadog_profiling_native_extension/stack_recorder.h +1 -0
  33. data/ext/datadog_profiling_native_extension/time_helpers.c +0 -15
  34. data/ext/datadog_profiling_native_extension/time_helpers.h +36 -6
  35. data/ext/{datadog_profiling_native_extension → libdatadog_api}/crashtracker.c +19 -6
  36. data/ext/libdatadog_api/datadog_ruby_common.c +110 -0
  37. data/ext/libdatadog_api/datadog_ruby_common.h +57 -0
  38. data/ext/libdatadog_api/extconf.rb +108 -0
  39. data/ext/libdatadog_api/macos_development.md +26 -0
  40. data/ext/libdatadog_extconf_helpers.rb +130 -0
  41. data/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +49 -0
  42. data/lib/datadog/appsec/contrib/graphql/gateway/multiplex.rb +73 -0
  43. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +68 -0
  44. data/lib/datadog/appsec/contrib/graphql/integration.rb +41 -0
  45. data/lib/datadog/appsec/contrib/graphql/patcher.rb +37 -0
  46. data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +59 -0
  47. data/lib/datadog/appsec/contrib/rack/gateway/request.rb +1 -1
  48. data/lib/datadog/appsec/processor/actions.rb +1 -1
  49. data/lib/datadog/appsec/response.rb +15 -1
  50. data/lib/datadog/appsec.rb +1 -0
  51. data/lib/datadog/core/configuration/components.rb +14 -12
  52. data/lib/datadog/core/configuration/settings.rb +54 -7
  53. data/lib/datadog/core/crashtracking/agent_base_url.rb +21 -0
  54. data/lib/datadog/core/crashtracking/component.rb +111 -0
  55. data/lib/datadog/core/crashtracking/tag_builder.rb +39 -0
  56. data/lib/datadog/core/diagnostics/environment_logger.rb +8 -11
  57. data/lib/datadog/core/telemetry/component.rb +49 -2
  58. data/lib/datadog/core/telemetry/emitter.rb +9 -11
  59. data/lib/datadog/core/telemetry/event.rb +32 -1
  60. data/lib/datadog/core/telemetry/ext.rb +1 -0
  61. data/lib/datadog/core/telemetry/http/adapters/net.rb +10 -12
  62. data/lib/datadog/core/telemetry/http/ext.rb +3 -0
  63. data/lib/datadog/core/telemetry/http/transport.rb +38 -9
  64. data/lib/datadog/core/telemetry/logging.rb +35 -0
  65. data/lib/datadog/core/utils/at_fork_monkey_patch.rb +102 -0
  66. data/lib/datadog/kit/appsec/events.rb +2 -4
  67. data/lib/datadog/opentelemetry/sdk/span_processor.rb +10 -0
  68. data/lib/datadog/opentelemetry/sdk/trace/span.rb +23 -0
  69. data/lib/datadog/profiling/collectors/code_provenance.rb +7 -7
  70. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +17 -17
  71. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +11 -13
  72. data/lib/datadog/profiling/collectors/info.rb +3 -3
  73. data/lib/datadog/profiling/collectors/thread_context.rb +4 -2
  74. data/lib/datadog/profiling/component.rb +69 -91
  75. data/lib/datadog/profiling/exporter.rb +3 -3
  76. data/lib/datadog/profiling/ext/dir_monkey_patches.rb +3 -3
  77. data/lib/datadog/profiling/ext.rb +21 -21
  78. data/lib/datadog/profiling/flush.rb +1 -1
  79. data/lib/datadog/profiling/http_transport.rb +8 -6
  80. data/lib/datadog/profiling/load_native_extension.rb +5 -5
  81. data/lib/datadog/profiling/preload.rb +1 -1
  82. data/lib/datadog/profiling/profiler.rb +5 -8
  83. data/lib/datadog/profiling/scheduler.rb +31 -25
  84. data/lib/datadog/profiling/tag_builder.rb +2 -2
  85. data/lib/datadog/profiling/tasks/exec.rb +5 -5
  86. data/lib/datadog/profiling/tasks/setup.rb +16 -35
  87. data/lib/datadog/profiling.rb +4 -5
  88. data/lib/datadog/tracing/contrib/active_record/events/sql.rb +1 -0
  89. data/lib/datadog/tracing/contrib/ext.rb +14 -0
  90. data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +1 -1
  91. data/lib/datadog/tracing/contrib/graphql/unified_trace_patcher.rb +4 -1
  92. data/lib/datadog/tracing/contrib/lograge/patcher.rb +16 -0
  93. data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +5 -0
  94. data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +17 -13
  95. data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +5 -0
  96. data/lib/datadog/tracing/contrib/pg/instrumentation.rb +4 -1
  97. data/lib/datadog/tracing/contrib/propagation/sql_comment/ext.rb +28 -0
  98. data/lib/datadog/tracing/contrib/propagation/sql_comment/mode.rb +5 -1
  99. data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +22 -10
  100. data/lib/datadog/tracing/contrib/trilogy/configuration/settings.rb +5 -0
  101. data/lib/datadog/tracing/contrib/trilogy/instrumentation.rb +4 -1
  102. data/lib/datadog/tracing/diagnostics/environment_logger.rb +14 -16
  103. data/lib/datadog/tracing/metadata/errors.rb +9 -1
  104. data/lib/datadog/tracing/metadata/ext.rb +4 -0
  105. data/lib/datadog/tracing/pipeline/span_filter.rb +2 -2
  106. data/lib/datadog/tracing/span.rb +9 -2
  107. data/lib/datadog/tracing/span_event.rb +41 -0
  108. data/lib/datadog/tracing/span_operation.rb +6 -2
  109. data/lib/datadog/tracing/transport/serializable_trace.rb +3 -0
  110. data/lib/datadog/version.rb +1 -1
  111. metadata +28 -10
  112. data/lib/datadog/profiling/crashtracker.rb +0 -91
  113. data/lib/datadog/profiling/ext/forking.rb +0 -98
@@ -27,7 +27,7 @@ module Datadog
27
27
  end
28
28
  end
29
29
 
30
- if RUBY_VERSION.start_with?('2.')
30
+ if RUBY_VERSION.start_with?("2.")
31
31
  # Monkey patches for Dir.singleton_class (Ruby 2 version). See DirMonkeyPatches above for more details.
32
32
  module DirClassMonkeyPatches
33
33
  def [](*args, &block)
@@ -260,7 +260,7 @@ module Datadog
260
260
  end
261
261
  end
262
262
 
263
- if RUBY_VERSION.start_with?('2.')
263
+ if RUBY_VERSION.start_with?("2.")
264
264
  # Monkey patches for Dir (Ruby 2 version). See DirMonkeyPatches above for more details.
265
265
  module DirInstanceMonkeyPatches
266
266
  # See note on methods that yield above.
@@ -286,7 +286,7 @@ module Datadog
286
286
  end
287
287
  end
288
288
 
289
- unless RUBY_VERSION.start_with?('2.5.') # This is Ruby 2.6+
289
+ unless RUBY_VERSION.start_with?("2.5.") # This is Ruby 2.6+
290
290
  # See note on methods that yield above.
291
291
  def each_child(*args, &block)
292
292
  if block
@@ -3,31 +3,31 @@
3
3
  module Datadog
4
4
  module Profiling
5
5
  module Ext
6
- ENV_ENABLED = 'DD_PROFILING_ENABLED'
7
- ENV_UPLOAD_TIMEOUT = 'DD_PROFILING_UPLOAD_TIMEOUT'
8
- ENV_MAX_FRAMES = 'DD_PROFILING_MAX_FRAMES'
9
- ENV_AGENTLESS = 'DD_PROFILING_AGENTLESS'
10
- ENV_ENDPOINT_COLLECTION_ENABLED = 'DD_PROFILING_ENDPOINT_COLLECTION_ENABLED'
6
+ ENV_ENABLED = "DD_PROFILING_ENABLED"
7
+ ENV_UPLOAD_TIMEOUT = "DD_PROFILING_UPLOAD_TIMEOUT"
8
+ ENV_MAX_FRAMES = "DD_PROFILING_MAX_FRAMES"
9
+ ENV_AGENTLESS = "DD_PROFILING_AGENTLESS"
10
+ ENV_ENDPOINT_COLLECTION_ENABLED = "DD_PROFILING_ENDPOINT_COLLECTION_ENABLED"
11
11
 
12
12
  module Transport
13
13
  module HTTP
14
- FORM_FIELD_TAG_ENV = 'env'
15
- FORM_FIELD_TAG_HOST = 'host'
16
- FORM_FIELD_TAG_LANGUAGE = 'language'
17
- FORM_FIELD_TAG_PID = 'process_id'
18
- FORM_FIELD_TAG_PROFILER_VERSION = 'profiler_version'
19
- FORM_FIELD_TAG_RUNTIME = 'runtime'
20
- FORM_FIELD_TAG_RUNTIME_ENGINE = 'runtime_engine'
21
- FORM_FIELD_TAG_RUNTIME_ID = 'runtime-id'
22
- FORM_FIELD_TAG_RUNTIME_PLATFORM = 'runtime_platform'
23
- FORM_FIELD_TAG_RUNTIME_VERSION = 'runtime_version'
24
- FORM_FIELD_TAG_SERVICE = 'service'
25
- FORM_FIELD_TAG_VERSION = 'version'
26
- TAG_GIT_REPOSITORY_URL = 'git.repository_url'
27
- TAG_GIT_COMMIT_SHA = 'git.commit.sha'
14
+ FORM_FIELD_TAG_ENV = "env"
15
+ FORM_FIELD_TAG_HOST = "host"
16
+ FORM_FIELD_TAG_LANGUAGE = "language"
17
+ FORM_FIELD_TAG_PID = "process_id"
18
+ FORM_FIELD_TAG_PROFILER_VERSION = "profiler_version"
19
+ FORM_FIELD_TAG_RUNTIME = "runtime"
20
+ FORM_FIELD_TAG_RUNTIME_ENGINE = "runtime_engine"
21
+ FORM_FIELD_TAG_RUNTIME_ID = "runtime-id"
22
+ FORM_FIELD_TAG_RUNTIME_PLATFORM = "runtime_platform"
23
+ FORM_FIELD_TAG_RUNTIME_VERSION = "runtime_version"
24
+ FORM_FIELD_TAG_SERVICE = "service"
25
+ FORM_FIELD_TAG_VERSION = "version"
26
+ TAG_GIT_REPOSITORY_URL = "git.repository_url"
27
+ TAG_GIT_COMMIT_SHA = "git.commit.sha"
28
28
 
29
- PPROF_DEFAULT_FILENAME = 'rubyprofile.pprof'
30
- CODE_PROVENANCE_FILENAME = 'code-provenance.json'
29
+ PPROF_DEFAULT_FILENAME = "rubyprofile.pprof"
30
+ CODE_PROVENANCE_FILENAME = "code-provenance.json"
31
31
  end
32
32
  end
33
33
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'json'
3
+ require "json"
4
4
 
5
5
  module Datadog
6
6
  module Profiling
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../core/transport/ext'
3
+ require_relative "../core/transport/ext"
4
4
 
5
5
  module Datadog
6
6
  module Profiling
@@ -53,7 +53,7 @@ module Datadog
53
53
 
54
54
  if status == :ok
55
55
  if (200..299).cover?(result)
56
- Datadog.logger.debug('Successfully reported profiling data')
56
+ Datadog.logger.debug("Successfully reported profiling data")
57
57
  true
58
58
  else
59
59
  Datadog.logger.error(
@@ -73,7 +73,7 @@ module Datadog
73
73
  def base_url_from(agent_settings)
74
74
  case agent_settings.adapter
75
75
  when Datadog::Core::Configuration::Ext::Agent::HTTP::ADAPTER
76
- "#{agent_settings.ssl ? 'https' : 'http'}://#{agent_settings.hostname}:#{agent_settings.port}/"
76
+ "#{agent_settings.ssl ? "https" : "http"}://#{agent_settings.hostname}:#{agent_settings.port}/"
77
77
  when Datadog::Core::Configuration::Ext::Agent::UnixSocket::ADAPTER
78
78
  "unix://#{agent_settings.uds_path}"
79
79
  else
@@ -82,12 +82,14 @@ module Datadog
82
82
  end
83
83
 
84
84
  def validate_agent_settings(agent_settings)
85
- supported_adapters = [Datadog::Core::Configuration::Ext::Agent::UnixSocket::ADAPTER,
86
- Datadog::Core::Configuration::Ext::Agent::HTTP::ADAPTER]
85
+ supported_adapters = [
86
+ Datadog::Core::Configuration::Ext::Agent::UnixSocket::ADAPTER,
87
+ Datadog::Core::Configuration::Ext::Agent::HTTP::ADAPTER
88
+ ]
87
89
  unless supported_adapters.include?(agent_settings.adapter)
88
90
  raise ArgumentError,
89
91
  "Unsupported transport configuration for profiling: Adapter #{agent_settings.adapter} " \
90
- ' is not supported'
92
+ " is not supported"
91
93
  end
92
94
  end
93
95
 
@@ -15,26 +15,26 @@ begin
15
15
  require "datadog_profiling_loader.#{RUBY_VERSION}_#{RUBY_PLATFORM}"
16
16
  rescue LoadError => e
17
17
  raise LoadError,
18
- 'Failed to load the profiling loader extension. To fix this, please remove and then reinstall datadog ' \
18
+ "Failed to load the profiling loader extension. To fix this, please remove and then reinstall datadog " \
19
19
  "(Details: #{e.message})"
20
20
  end
21
21
 
22
22
  extension_name = "datadog_profiling_native_extension.#{RUBY_VERSION}_#{RUBY_PLATFORM}"
23
- file_name = "#{extension_name}.#{RbConfig::CONFIG['DLEXT']}"
23
+ file_name = "#{extension_name}.#{RbConfig::CONFIG["DLEXT"]}"
24
24
  full_file_path = "#{__dir__}/../../#{file_name}"
25
25
 
26
26
  unless File.exist?(full_file_path)
27
- extension_dir = Gem.loaded_specs['datadog'].extension_dir
27
+ extension_dir = Gem.loaded_specs["datadog"].extension_dir
28
28
  candidate_path = "#{extension_dir}/#{file_name}"
29
29
  if File.exist?(candidate_path)
30
30
  full_file_path = candidate_path
31
- else # rubocop:disable Style/EmptyElse
31
+ else
32
32
  # We found none of the files. This is unexpected. Let's go ahead anyway, the error is going to be reported further
33
33
  # down anyway.
34
34
  end
35
35
  end
36
36
 
37
- init_function_name = "Init_#{extension_name.split('.').first}"
37
+ init_function_name = "Init_#{extension_name.split(".").first}"
38
38
 
39
39
  status, result = Datadog::Profiling::Loader._native_load(full_file_path, init_function_name)
40
40
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../../datadog'
3
+ require_relative "../../datadog"
4
4
 
5
5
  Datadog::Profiling.start_if_enabled
@@ -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,9 @@
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
7
 
8
8
  module Datadog
9
9
  module Profiling
@@ -22,7 +22,8 @@ module Datadog
22
22
 
23
23
  attr_reader \
24
24
  :exporter,
25
- :transport
25
+ :transport,
26
+ :profiler_failed
26
27
 
27
28
  public
28
29
 
@@ -34,6 +35,7 @@ module Datadog
34
35
  )
35
36
  @exporter = exporter
36
37
  @transport = transport
38
+ @profiler_failed = false
37
39
 
38
40
  # Workers::Async::Thread settings
39
41
  self.fork_policy = fork_policy
@@ -50,25 +52,23 @@ module Datadog
50
52
  end
51
53
 
52
54
  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
55
+ # A profiling flush may be called while the VM is shutting down, to report the last profile. When we do so,
56
+ # we impose a strict timeout. This means this last profile may or may not be sent, depending on if the flush can
57
+ # successfully finish in the strict timeout.
58
+ # This can be somewhat confusing (why did it not get reported?), so let's at least log what happened.
59
+ interrupted = true
60
+
61
+ flush_and_wait
62
+ interrupted = false
63
+ rescue Exception => e # rubocop:disable Lint/RescueException
64
+ Datadog.logger.warn(
65
+ "Profiling::Scheduler thread error. " \
66
+ "Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
67
+ )
68
+ on_failure_proc&.call
69
+ raise
70
+ ensure
71
+ Datadog.logger.debug("#flush was interrupted or failed before it could complete") if interrupted
72
72
  end
73
73
 
74
74
  # Configure Workers::IntervalLoop to not report immediately when scheduler starts
@@ -80,8 +80,14 @@ module Datadog
80
80
  true
81
81
  end
82
82
 
83
+ # This is called by the Profiler class whenever an issue happened in the profiler. This makes sure that even
84
+ # if there is data to be flushed, we don't try to flush it.
85
+ def mark_profiler_failed
86
+ @profiler_failed = true
87
+ end
88
+
83
89
  def work_pending?
84
- exporter.can_flush?
90
+ !profiler_failed && exporter.can_flush?
85
91
  end
86
92
 
87
93
  def reset_after_fork
@@ -124,7 +130,7 @@ module Datadog
124
130
 
125
131
  begin
126
132
  transport.export(flush)
127
- rescue StandardError => e
133
+ rescue => e
128
134
  Datadog.logger.error(
129
135
  "Unable to report profile. Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
130
136
  )
@@ -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'
@@ -62,6 +62,7 @@ module Datadog
62
62
  cached = payload[:cached] || (payload[:name] == PAYLOAD_CACHE)
63
63
 
64
64
  span.set_tag(Ext::TAG_DB_VENDOR, adapter_name)
65
+ span.set_tag(Contrib::Ext::DB::TAG_INSTANCE, config[:database])
65
66
  span.set_tag(Ext::TAG_DB_NAME, config[:database])
66
67
  span.set_tag(Ext::TAG_DB_CACHED, cached) if cached
67
68
  span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_HOST, config[:host]) if config[:host]
@@ -7,7 +7,21 @@ module Datadog
7
7
  module Ext
8
8
  # @public_api
9
9
  module DB
10
+ # Name of the database. This is *not* the database hostname.
11
+ #
12
+ # For databases which support such a concept, the default schema/database/namespace
13
+ # as configured in the connection string.
14
+ #
15
+ # If the tracer is already tracking changes to the default schema/database throughout the lifetime of
16
+ # the session (i.e. the client executes USE {NEW_SCHEMA} and now the default schema has changed from what
17
+ # was set upon connection initialization), then ideally this attribute reflects the “current” value.
18
+ # If the tracer is not already tracking changes then just leaving it to the default value set upon
19
+ # initialization is OK.
20
+ #
21
+ # This is the equivalent of OTel’s `db.namespace`
22
+ # @see https://opentelemetry.io/docs/specs/semconv/database/database-spans/#common-attributes
10
23
  TAG_INSTANCE = 'db.instance'
24
+
11
25
  TAG_USER = 'db.user'
12
26
  TAG_SYSTEM = 'db.system'
13
27
  TAG_STATEMENT = 'db.statement'
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'graphql/tracing'
3
+ require 'graphql'
4
4
 
5
5
  module Datadog
6
6
  module Tracing
@@ -1,5 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ if Gem.loaded_specs['graphql'] && Gem.loaded_specs['graphql'].version >= Gem::Version.new('2.0.19')
4
+ require_relative 'unified_trace'
5
+ end
6
+
3
7
  module Datadog
4
8
  module Tracing
5
9
  module Contrib
@@ -9,7 +13,6 @@ module Datadog
9
13
  module_function
10
14
 
11
15
  def patch!(schemas, options)
12
- require_relative 'unified_trace'
13
16
  if schemas.empty?
14
17
  ::GraphQL::Schema.trace_with(UnifiedTrace, **options)
15
18
  else
@@ -20,6 +20,22 @@ module Datadog
20
20
 
21
21
  # patch applies our patch
22
22
  def patch
23
+ # ActiveSupport::TaggedLogging is the default Rails logger since Rails 5
24
+ if defined?(::ActiveSupport::TaggedLogging::Formatter) &&
25
+ ::Lograge::LogSubscribers::ActionController
26
+ .logger&.formatter.is_a?(::ActiveSupport::TaggedLogging::Formatter)
27
+
28
+ Datadog.logger.error(
29
+ 'Lograge and ActiveSupport::TaggedLogging (the default Rails log formatter) are not compatible: ' \
30
+ 'Lograge does not account for Rails log tags, creating polluted logs and breaking log formatting. ' \
31
+ 'Traces and Logs correlation may not work. ' \
32
+ 'Either: 1. Disable tagged logging in your Rails configuration ' \
33
+ '`config.logger = ActiveSupport::Logger.new(STDOUT); ' \
34
+ 'config.active_job.logger = ActiveSupport::Logger.new(STDOUT)` ' \
35
+ 'or 2. Use the `semantic_logger` gem instead of `lograge`.'
36
+ )
37
+ end
38
+
23
39
  ::Lograge::LogSubscribers::Base.include(Instrumentation)
24
40
  end
25
41
  end
@@ -48,6 +48,11 @@ module Datadog
48
48
  o.default Contrib::Propagation::SqlComment::Ext::DISABLED
49
49
  end
50
50
 
51
+ option :append_comment do |o|
52
+ o.type :bool
53
+ o.default false
54
+ end
55
+
51
56
  option :peer_service do |o|
52
57
  o.type :string, nilable: true
53
58
  o.env Ext::ENV_PEER_SERVICE
@@ -50,21 +50,14 @@ module Datadog
50
50
  # Set analytics sample rate
51
51
  Contrib::Analytics.set_sample_rate(span, analytics_sample_rate) if analytics_enabled?
52
52
 
53
+ span.set_tag(Contrib::Ext::DB::TAG_INSTANCE, query_options[:database])
53
54
  span.set_tag(Ext::TAG_DB_NAME, query_options[:database])
54
55
  span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_HOST, query_options[:host])
55
56
  span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_PORT, query_options[:port])
56
57
 
57
58
  Contrib::SpanAttributeSchema.set_peer_service!(span, Ext::PEER_SERVICE_SOURCES)
58
59
 
59
- propagation_mode = Contrib::Propagation::SqlComment::Mode.new(comment_propagation)
60
-
61
- Contrib::Propagation::SqlComment.annotate!(span, propagation_mode)
62
- sql = Contrib::Propagation::SqlComment.prepend_comment(
63
- sql,
64
- span,
65
- trace_op,
66
- propagation_mode
67
- )
60
+ sql = inject_propagation(span, sql, trace_op)
68
61
 
69
62
  super(sql, options)
70
63
  end
@@ -72,6 +65,21 @@ module Datadog
72
65
 
73
66
  private
74
67
 
68
+ def inject_propagation(span, sql, trace_op)
69
+ propagation_mode = Contrib::Propagation::SqlComment::Mode.new(
70
+ datadog_configuration[:comment_propagation],
71
+ datadog_configuration[:append_comment]
72
+ )
73
+
74
+ Contrib::Propagation::SqlComment.annotate!(span, propagation_mode)
75
+ Contrib::Propagation::SqlComment.prepend_comment(
76
+ sql,
77
+ span,
78
+ trace_op,
79
+ propagation_mode
80
+ )
81
+ end
82
+
75
83
  def datadog_configuration
76
84
  Datadog.configuration.tracing[:mysql2]
77
85
  end
@@ -83,10 +91,6 @@ module Datadog
83
91
  def analytics_sample_rate
84
92
  datadog_configuration[:analytics_sample_rate]
85
93
  end
86
-
87
- def comment_propagation
88
- datadog_configuration[:comment_propagation]
89
- end
90
94
  end
91
95
  end
92
96
  end