datadog 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
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