ddtrace 1.13.1 → 1.14.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.
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+ require 'json'
5
+ require 'rbconfig'
6
+ require_relative '../../core/diagnostics/environment_logger'
7
+
8
+ module Datadog
9
+ module Profiling
10
+ module Diagnostics
11
+ # Collects and logs Profiling diagnostic information
12
+ module EnvironmentLogger
13
+ extend Core::Diagnostics::EnvironmentLogging
14
+
15
+ def self.collect_and_log!
16
+ log_once! do
17
+ data = EnvironmentCollector.collect_config!
18
+ log_configuration!('PROFILING', data.to_json)
19
+ end
20
+ rescue => e
21
+ logger.warn("Failed to collect profiling environment information: #{e} Location: #{Array(e.backtrace).first}")
22
+ end
23
+ end
24
+
25
+ # Collects environment information for Profiling diagnostic logging
26
+ module EnvironmentCollector
27
+ def self.collect_config!(*args)
28
+ {
29
+ profiling_enabled: profiling_enabled
30
+ }
31
+ end
32
+
33
+ def self.profiling_enabled
34
+ !!Datadog.configuration.profiling.enabled
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -23,14 +23,14 @@ module Datadog
23
23
  :time_provider,
24
24
  :last_flush_finish_at,
25
25
  :created_at,
26
- :no_signals_workaround_enabled
26
+ :internal_metadata
27
27
 
28
28
  public
29
29
 
30
30
  def initialize(
31
31
  pprof_recorder:,
32
32
  code_provenance_collector:,
33
- no_signals_workaround_enabled:,
33
+ internal_metadata:,
34
34
  minimum_duration_seconds: PROFILE_DURATION_THRESHOLD_SECONDS,
35
35
  time_provider: Time
36
36
  )
@@ -40,7 +40,7 @@ module Datadog
40
40
  @time_provider = time_provider
41
41
  @last_flush_finish_at = nil
42
42
  @created_at = time_provider.now.utc
43
- @no_signals_workaround_enabled = no_signals_workaround_enabled
43
+ @internal_metadata = internal_metadata
44
44
  end
45
45
 
46
46
  def flush
@@ -64,7 +64,7 @@ module Datadog
64
64
  code_provenance_file_name: Datadog::Profiling::Ext::Transport::HTTP::CODE_PROVENANCE_FILENAME,
65
65
  code_provenance_data: uncompressed_code_provenance,
66
66
  tags_as_array: Datadog::Profiling::TagBuilder.call(settings: Datadog.configuration).to_a,
67
- no_signals_workaround_enabled: no_signals_workaround_enabled,
67
+ internal_metadata: internal_metadata,
68
68
  )
69
69
  end
70
70
 
@@ -27,7 +27,7 @@ module Datadog
27
27
  code_provenance_file_name:,
28
28
  code_provenance_data:,
29
29
  tags_as_array:,
30
- no_signals_workaround_enabled:
30
+ internal_metadata:
31
31
  )
32
32
  @start = start
33
33
  @finish = finish
@@ -36,9 +36,7 @@ module Datadog
36
36
  @code_provenance_file_name = code_provenance_file_name
37
37
  @code_provenance_data = code_provenance_data
38
38
  @tags_as_array = tags_as_array
39
- @internal_metadata_json = JSON.fast_generate(
40
- no_signals_workaround_enabled: (!!no_signals_workaround_enabled).to_s,
41
- )
39
+ @internal_metadata_json = JSON.fast_generate(internal_metadata.map { |k, v| [k, v.to_s] }.to_h)
42
40
  end
43
41
  end
44
42
  end
@@ -198,6 +198,7 @@ module Datadog
198
198
  require_relative 'profiling/collectors/old_stack'
199
199
  require_relative 'profiling/collectors/stack'
200
200
  require_relative 'profiling/collectors/thread_context'
201
+ require_relative 'profiling/diagnostics/environment_logger'
201
202
  require_relative 'profiling/stack_recorder'
202
203
  require_relative 'profiling/old_recorder'
203
204
  require_relative 'profiling/exporter'
@@ -5,6 +5,7 @@ require_relative 'flush'
5
5
  require_relative 'sync_writer'
6
6
  require_relative 'sampling/span/rule_parser'
7
7
  require_relative 'sampling/span/sampler'
8
+ require_relative 'diagnostics/environment_logger'
8
9
 
9
10
  module Datadog
10
11
  module Tracing
@@ -154,7 +155,7 @@ module Datadog
154
155
  end
155
156
 
156
157
  WRITER_RECORD_ENVIRONMENT_INFORMATION_CALLBACK = lambda do |_, responses|
157
- Core::Diagnostics::EnvironmentLogger.log!(responses)
158
+ Tracing::Diagnostics::EnvironmentLogger.collect_and_log!(responses: responses)
158
159
  end
159
160
 
160
161
  # Create new lambda for writer callback,
@@ -90,18 +90,25 @@ module Datadog
90
90
  )
91
91
  end
92
92
 
93
+ #
94
+ # `::ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver` exists from 4+ til from 6.0.x
95
+ #
96
+ # `::ActiveRecord::DatabaseConfigurations` was introduced from 6+,
97
+ # but from 6.1.x, it was refactored to encapsulates the resolving logic, hence removing the resolver
98
+ #
93
99
  def connection_resolver
94
- @resolver ||= if defined?(::ActiveRecord::Base.configurations.resolve)
95
- ::ActiveRecord::DatabaseConfigurations.new(active_record_configuration)
96
- elsif defined?(::ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver)
97
- ::ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver.new(
98
- active_record_configuration
99
- )
100
- else
101
- Contrib::ActiveRecord::Vendor::ConnectionAdapters::ConnectionSpecification::Resolver.new(
102
- active_record_configuration
103
- )
104
- end
100
+ @resolver ||=
101
+ # From 6.1+
102
+ if defined?(::ActiveRecord::Base.configurations.resolve)
103
+ ::ActiveRecord::DatabaseConfigurations.new(active_record_configuration)
104
+ # From 4+ to 6.0.x
105
+ elsif defined?(::ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver)
106
+ ::ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver.new(active_record_configuration)
107
+ else
108
+ Contrib::ActiveRecord::Vendor::ConnectionAdapters::ConnectionSpecification::Resolver.new(
109
+ active_record_configuration
110
+ )
111
+ end
105
112
  end
106
113
 
107
114
  def resolve_connection_key(key)
@@ -113,7 +113,7 @@ module Datadog
113
113
 
114
114
  # @return [Hash]
115
115
  def self.db_config(connection_pool)
116
- if ::Rails::VERSION::MAJOR >= 6 && ::Rails::VERSION::MINOR >= 1
116
+ if connection_pool.respond_to? :db_config
117
117
  connection_pool.db_config.configuration_hash
118
118
  else
119
119
  connection_pool.spec.config
@@ -24,123 +24,120 @@ module Datadog
24
24
  require 'json'
25
25
  require_relative 'quantize'
26
26
 
27
- patch_elasticsearch_transport_client
27
+ transport_module::Client.prepend(Client)
28
28
  end
29
29
 
30
30
  SELF_DEPRECATION_ONLY_ONCE = Core::Utils::OnlyOnce.new
31
31
 
32
- # rubocop:disable Metrics/MethodLength
33
- # rubocop:disable Metrics/AbcSize
34
- # rubocop:disable Metrics/CyclomaticComplexity
35
- # rubocop:disable Metrics/PerceivedComplexity
36
- def patch_elasticsearch_transport_client
37
- # rubocop:disable Metrics/BlockLength
38
- transport_module::Client.class_eval do
39
- alias_method :perform_request_without_datadog, :perform_request
40
- remove_method :perform_request
41
-
42
- def perform_request(*args)
43
- # DEV-2.0: Remove this access, as `Client#self` in this context is not exposed to the user
44
- # since `elasticsearch` v8.0.0. In contrast, `Client#transport` is always available across
45
- # all `elasticsearch` gem versions and should be used instead.
46
- service = Datadog.configuration_for(self, :service_name)
47
-
48
- if service
49
- SELF_DEPRECATION_ONLY_ONCE.run do
50
- Datadog.logger.warn(
51
- 'Providing configuration though the Elasticsearch client object is deprecated.' \
52
- 'Configure the `client#transport` object instead: ' \
53
- 'Datadog.configure_onto(client.transport, service_name: service_name, ...)'
32
+ # Patches Elasticsearch::Transport::Client module
33
+ module Client
34
+ # rubocop:disable Metrics/MethodLength
35
+ # rubocop:disable Metrics/AbcSize
36
+ def perform_request(*args)
37
+ # DEV-2.0: Remove this access, as `Client#self` in this context is not exposed to the user
38
+ # since `elasticsearch` v8.0.0. In contrast, `Client#transport` is always available across
39
+ # all `elasticsearch` gem versions and should be used instead.
40
+ service = Datadog.configuration_for(self, :service_name)
41
+
42
+ if service
43
+ SELF_DEPRECATION_ONLY_ONCE.run do
44
+ Datadog.logger.warn(
45
+ 'Providing configuration though the Elasticsearch client object is deprecated.' \
46
+ 'Configure the `client#transport` object instead: ' \
47
+ 'Datadog.configure_onto(client.transport, service_name: service_name, ...)'
48
+ )
49
+ end
50
+ end
51
+
52
+ # `Client#transport` is most convenient object both this integration and the library
53
+ # user have shared access to across all `elasticsearch` versions.
54
+ #
55
+ # `Client#self` in this context is an internal object that the library user
56
+ # does not have access to since `elasticsearch` v8.0.0.
57
+ service ||= Datadog.configuration_for(transport, :service_name) || datadog_configuration[:service_name]
58
+
59
+ method = args[0]
60
+ path = args[1]
61
+ params = args[2]
62
+ body = args[3]
63
+ full_url = URI.parse(path)
64
+ url = full_url.path
65
+ response = nil
66
+
67
+ Tracing.trace(Datadog::Tracing::Contrib::Elasticsearch::Ext::SPAN_QUERY, service: service) do |span|
68
+ begin
69
+ connection = transport.connections.first
70
+ host = connection.host[:host] if connection
71
+ port = connection.host[:port] if connection
72
+
73
+ if datadog_configuration[:peer_service]
74
+ span.set_tag(
75
+ Tracing::Metadata::Ext::TAG_PEER_SERVICE,
76
+ datadog_configuration[:peer_service]
54
77
  )
55
78
  end
56
- end
57
79
 
58
- # `Client#transport` is most convenient object both this integration and the library
59
- # user have shared access to across all `elasticsearch` versions.
60
- #
61
- # `Client#self` in this context is an internal object that the library user
62
- # does not have access to since `elasticsearch` v8.0.0.
63
- service ||= Datadog.configuration_for(transport, :service_name) || datadog_configuration[:service_name]
64
-
65
- method = args[0]
66
- path = args[1]
67
- params = args[2]
68
- body = args[3]
69
- full_url = URI.parse(path)
70
-
71
- url = full_url.path
72
- response = nil
73
-
74
- Tracing.trace(Datadog::Tracing::Contrib::Elasticsearch::Ext::SPAN_QUERY, service: service) do |span|
75
- begin
76
- connection = transport.connections.first
77
- host = connection.host[:host] if connection
78
- port = connection.host[:port] if connection
79
-
80
- if datadog_configuration[:peer_service]
81
- span.set_tag(
82
- Tracing::Metadata::Ext::TAG_PEER_SERVICE,
83
- datadog_configuration[:peer_service]
84
- )
85
- end
86
-
87
- span.span_type = Datadog::Tracing::Contrib::Elasticsearch::Ext::SPAN_TYPE_QUERY
88
-
89
- span.set_tag(Tracing::Metadata::Ext::TAG_COMPONENT, Ext::TAG_COMPONENT)
90
- span.set_tag(Tracing::Metadata::Ext::TAG_OPERATION, Ext::TAG_OPERATION_QUERY)
91
- span.set_tag(Tracing::Metadata::Ext::TAG_KIND, Tracing::Metadata::Ext::SpanKind::TAG_CLIENT)
92
-
93
- span.set_tag(Contrib::Ext::DB::TAG_SYSTEM, Ext::TAG_SYSTEM)
94
-
95
- # load JSON for the following fields unless they're already strings
96
- params = JSON.generate(params) if params && !params.is_a?(String)
97
- body = JSON.generate(body) if body && !body.is_a?(String)
98
-
99
- span.set_tag(Tracing::Metadata::Ext::TAG_PEER_HOSTNAME, host) if host
100
-
101
- # Set analytics sample rate
102
- if Contrib::Analytics.enabled?(datadog_configuration[:analytics_enabled])
103
- Contrib::Analytics.set_sample_rate(span, datadog_configuration[:analytics_sample_rate])
104
- end
105
-
106
- span.set_tag(Datadog::Tracing::Contrib::Elasticsearch::Ext::TAG_METHOD, method)
107
- span.set_tag(Datadog::Tracing::Contrib::Elasticsearch::Ext::TAG_URL, url)
108
- span.set_tag(Datadog::Tracing::Contrib::Elasticsearch::Ext::TAG_PARAMS, params) if params
109
- if body
110
- quantize_options = datadog_configuration[:quantize]
111
- quantized_body = Datadog::Tracing::Contrib::Elasticsearch::Quantize.format_body(
112
- body,
113
- quantize_options
114
- )
115
- span.set_tag(Datadog::Tracing::Contrib::Elasticsearch::Ext::TAG_BODY, quantized_body)
116
- end
117
- span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_HOST, host) if host
118
- span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_PORT, port) if port
119
-
120
- quantized_url = Datadog::Tracing::Contrib::Elasticsearch::Quantize.format_url(url)
121
- span.resource = "#{method} #{quantized_url}"
122
- Contrib::SpanAttributeSchema.set_peer_service!(span, Ext::PEER_SERVICE_SOURCES)
123
- rescue StandardError => e
124
- Datadog.logger.error(e.message)
125
- ensure
126
- # the call is still executed
127
- response = perform_request_without_datadog(*args)
128
- span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_STATUS_CODE, response.status)
80
+ span.span_type = Datadog::Tracing::Contrib::Elasticsearch::Ext::SPAN_TYPE_QUERY
81
+
82
+ span.set_tag(Tracing::Metadata::Ext::TAG_COMPONENT, Ext::TAG_COMPONENT)
83
+ span.set_tag(Tracing::Metadata::Ext::TAG_OPERATION, Ext::TAG_OPERATION_QUERY)
84
+ span.set_tag(Tracing::Metadata::Ext::TAG_KIND, Tracing::Metadata::Ext::SpanKind::TAG_CLIENT)
85
+
86
+ span.set_tag(Contrib::Ext::DB::TAG_SYSTEM, Ext::TAG_SYSTEM)
87
+
88
+ span.set_tag(Tracing::Metadata::Ext::TAG_PEER_HOSTNAME, host) if host
89
+
90
+ # Set analytics sample rate
91
+ if Contrib::Analytics.enabled?(datadog_configuration[:analytics_enabled])
92
+ Contrib::Analytics.set_sample_rate(span, datadog_configuration[:analytics_sample_rate])
129
93
  end
94
+
95
+ span.set_tag(Datadog::Tracing::Contrib::Elasticsearch::Ext::TAG_METHOD, method)
96
+ tag_params(params, span)
97
+ tag_body(body, span)
98
+ span.set_tag(Datadog::Tracing::Contrib::Elasticsearch::Ext::TAG_URL, url)
99
+ span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_HOST, host) if host
100
+ span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_PORT, port) if port
101
+
102
+ quantized_url = Datadog::Tracing::Contrib::Elasticsearch::Quantize.format_url(url)
103
+ span.resource = "#{method} #{quantized_url}"
104
+ Contrib::SpanAttributeSchema.set_peer_service!(span, Ext::PEER_SERVICE_SOURCES)
105
+ rescue StandardError => e
106
+ Datadog.logger.error(e.message)
107
+ ensure
108
+ # the call is still executed
109
+ response = super
110
+ span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_STATUS_CODE, response.status)
130
111
  end
131
- response
132
112
  end
113
+ response
114
+ end
133
115
 
134
- def datadog_configuration
135
- Datadog.configuration.tracing[:elasticsearch]
136
- end
116
+ def tag_params(params, span)
117
+ return unless params
118
+
119
+ params = JSON.generate(params) unless params.is_a?(String)
120
+ span.set_tag(Datadog::Tracing::Contrib::Elasticsearch::Ext::TAG_PARAMS, params)
121
+ end
122
+
123
+ def tag_body(body, span)
124
+ return unless body
125
+
126
+ body = JSON.generate(body) unless body.is_a?(String)
127
+ quantize_options = datadog_configuration[:quantize]
128
+ quantized_body = Datadog::Tracing::Contrib::Elasticsearch::Quantize.format_body(
129
+ body,
130
+ quantize_options
131
+ )
132
+ span.set_tag(Datadog::Tracing::Contrib::Elasticsearch::Ext::TAG_BODY, quantized_body)
133
+ end
134
+
135
+ def datadog_configuration
136
+ Datadog.configuration.tracing[:elasticsearch]
137
137
  end
138
- # rubocop:enable Metrics/BlockLength
139
138
  end
140
139
  # rubocop:enable Metrics/MethodLength
141
140
  # rubocop:enable Metrics/AbcSize
142
- # rubocop:enable Metrics/CyclomaticComplexity
143
- # rubocop:enable Metrics/PerceivedComplexity
144
141
 
145
142
  # `Elasticsearch` namespace renamed to `Elastic` in version 8.0.0 of the transport gem:
146
143
  # @see https://github.com/elastic/elastic-transport-ruby/commit/ef804cbbd284f2a82d825221f87124f8b5ff823c
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../../../core/logging/ext'
4
-
5
3
  module Datadog
6
4
  module Tracing
7
5
  module Contrib
@@ -23,21 +21,7 @@ module Datadog
23
21
  # Retrieves trace information for current thread
24
22
  correlation = Tracing.correlation
25
23
  # merge original lambda with datadog context
26
-
27
- datadog_trace_log_hash = {
28
- # Adds IDs as tags to log output
29
- dd: {
30
- # To preserve precision during JSON serialization, use strings for large numbers
31
- trace_id: correlation.trace_id.to_s,
32
- span_id: correlation.span_id.to_s,
33
- env: correlation.env.to_s,
34
- service: correlation.service.to_s,
35
- version: correlation.version.to_s
36
- },
37
- ddsource: Core::Logging::Ext::DD_SOURCE
38
- }
39
-
40
- datadog_trace_log_hash.merge(original_custom_options)
24
+ correlation.to_h.merge(original_custom_options)
41
25
  end
42
26
  end
43
27
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../../../core/logging/ext'
4
-
5
3
  module Datadog
6
4
  module Tracing
7
5
  module Contrib
@@ -23,25 +21,10 @@ module Datadog
23
21
 
24
22
  # Retrieves trace information for current thread
25
23
  correlation = Tracing.correlation
26
- # merge original lambda with datadog context
27
-
28
- datadog_trace_log_hash = {
29
- # Adds IDs as tags to log output
30
- dd: {
31
- # To preserve precision during JSON serialization, use strings for large numbers
32
- trace_id: correlation.trace_id.to_s,
33
- span_id: correlation.span_id.to_s,
34
- env: correlation.env.to_s,
35
- service: correlation.service.to_s,
36
- version: correlation.version.to_s
37
- },
38
- ddsource: Core::Logging::Ext::DD_SOURCE
39
- }
40
24
 
41
- # # if the user already has conflicting log_tags
42
- # # we want them to clobber ours, because we should allow them to override
43
- # # if needed.
44
- log.named_tags = datadog_trace_log_hash.merge(original_named_tags)
25
+ # if the user already has conflicting log_tags
26
+ # we want them to clobber ours, because we should allow them to override if needed.
27
+ log.named_tags = correlation.to_h.merge(original_named_tags)
45
28
  super(log, message, progname, &block)
46
29
  end
47
30
  end
@@ -134,18 +134,18 @@ module Datadog
134
134
  (?:"|%22)?
135
135
  )
136
136
  (?: # common keys
137
- (?:old_?|new_?)?p(?:ass)?w(?:or)?d(?:1|2)? # pw, password variants
138
- |pass(?:_?phrase)? # pass, passphrase variants
137
+ (?:old[-_]?|new_?)?p(?:ass)?w(?:or)?d(?:1|2)? # pw, password variants
138
+ |pass(?:[-_]?phrase)? # pass, passphrase variants
139
139
  |secret
140
140
  |(?: # key, key_id variants
141
- api_?
142
- |private_?
143
- |public_?
144
- |access_?
145
- |secret_?
146
- )key(?:_?id)?
141
+ api[-_]?
142
+ |private[-_]?
143
+ |public[-_]?
144
+ |access[-_]?
145
+ |secret[-_]?
146
+ )key(?:[-_]?id)?
147
147
  |token
148
- |consumer_?(?:id|key|secret)
148
+ |consumer[-_]?(?:id|key|secret)
149
149
  |sign(?:ed|ature)?
150
150
  |auth(?:entication|orization)?
151
151
  )
@@ -1,5 +1,6 @@
1
1
  require_relative 'utils'
2
2
  require_relative 'metadata/ext'
3
+ require_relative '../core/logging/ext'
3
4
 
4
5
  module Datadog
5
6
  module Tracing
@@ -14,6 +15,7 @@ module Datadog
14
15
  LOG_ATTR_SPAN_ID = 'dd.span_id'.freeze
15
16
  LOG_ATTR_TRACE_ID = 'dd.trace_id'.freeze
16
17
  LOG_ATTR_VERSION = 'dd.version'.freeze
18
+ LOG_ATTR_SOURCE = 'ddsource'.freeze
17
19
 
18
20
  attr_reader \
19
21
  :env,
@@ -58,6 +60,23 @@ module Datadog
58
60
  @version = Core::Utils::SafeDup.frozen_dup(version || Datadog.configuration.version)
59
61
  end
60
62
 
63
+ def to_h
64
+ @to_h ||= {
65
+ # Adds IDs as tags to log output
66
+ dd: {
67
+ # To preserve precision during JSON serialization, use strings for large numbers
68
+ env: env.to_s,
69
+ service: service.to_s,
70
+ version: version.to_s,
71
+ trace_id: trace_id.to_s,
72
+ span_id: span_id.to_s
73
+ },
74
+ ddsource: Core::Logging::Ext::DD_SOURCE
75
+ }
76
+ end
77
+
78
+ # This method (#to_log_format) implements an algorithm by prefixing keys for nested values
79
+ # but the algorithm makes the constants implicit. Hence, we use it for validation during test.
61
80
  def to_log_format
62
81
  @log_format ||= begin
63
82
  attributes = []
@@ -66,6 +85,7 @@ module Datadog
66
85
  attributes << "#{LOG_ATTR_VERSION}=#{version}" unless version.nil?
67
86
  attributes << "#{LOG_ATTR_TRACE_ID}=#{trace_id}"
68
87
  attributes << "#{LOG_ATTR_SPAN_ID}=#{span_id}"
88
+ attributes << "#{LOG_ATTR_SOURCE}=#{Core::Logging::Ext::DD_SOURCE}"
69
89
  attributes.join(' ')
70
90
  end
71
91
  end