ddtrace 1.13.1 → 1.14.0

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