ddtrace 0.35.0 → 0.38.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.
- checksums.yaml +4 -4
- data/.circleci/config.yml +3 -1
- data/.gitignore +2 -0
- data/.gitlab-ci.yml +26 -0
- data/.rubocop.yml +4 -0
- data/Appraisals +23 -6
- data/CHANGELOG.md +116 -1
- data/Rakefile +43 -12
- data/ddtrace.gemspec +5 -0
- data/docker-compose.yml +37 -2
- data/docs/GettingStarted.md +63 -34
- data/lib/ddtrace.rb +2 -0
- data/lib/ddtrace/configuration/base.rb +1 -1
- data/lib/ddtrace/configuration/components.rb +2 -2
- data/lib/ddtrace/configuration/options.rb +1 -1
- data/lib/ddtrace/configuration/pin_setup.rb +3 -2
- data/lib/ddtrace/configuration/settings.rb +18 -0
- data/lib/ddtrace/contrib/active_support/cache/redis.rb +1 -1
- data/lib/ddtrace/contrib/active_support/notifications/event.rb +3 -1
- data/lib/ddtrace/contrib/active_support/notifications/subscription.rb +1 -1
- data/lib/ddtrace/contrib/concurrent_ruby/context_composite_executor_service.rb +9 -3
- data/lib/ddtrace/contrib/configuration/settings.rb +19 -1
- data/lib/ddtrace/contrib/dalli/patcher.rb +1 -5
- data/lib/ddtrace/contrib/elasticsearch/patcher.rb +1 -2
- data/lib/ddtrace/contrib/extensions.rb +38 -4
- data/lib/ddtrace/contrib/faraday/middleware.rb +5 -3
- data/lib/ddtrace/contrib/faraday/patcher.rb +4 -5
- data/lib/ddtrace/contrib/grape/patcher.rb +1 -1
- data/lib/ddtrace/contrib/graphql/patcher.rb +6 -3
- data/lib/ddtrace/contrib/grpc/datadog_interceptor.rb +1 -1
- data/lib/ddtrace/contrib/grpc/datadog_interceptor/client.rb +1 -3
- data/lib/ddtrace/contrib/grpc/patcher.rb +1 -5
- data/lib/ddtrace/contrib/http/circuit_breaker.rb +8 -32
- data/lib/ddtrace/contrib/http/instrumentation.rb +13 -8
- data/lib/ddtrace/contrib/httprb/configuration/settings.rb +27 -0
- data/lib/ddtrace/contrib/httprb/ext.rb +14 -0
- data/lib/ddtrace/contrib/httprb/instrumentation.rb +163 -0
- data/lib/ddtrace/contrib/httprb/integration.rb +43 -0
- data/lib/ddtrace/contrib/httprb/patcher.rb +35 -0
- data/lib/ddtrace/contrib/kafka/configuration/settings.rb +25 -0
- data/lib/ddtrace/contrib/kafka/consumer_event.rb +14 -0
- data/lib/ddtrace/contrib/kafka/consumer_group_event.rb +14 -0
- data/lib/ddtrace/contrib/kafka/event.rb +51 -0
- data/lib/ddtrace/contrib/kafka/events.rb +44 -0
- data/lib/ddtrace/contrib/kafka/events/connection/request.rb +34 -0
- data/lib/ddtrace/contrib/kafka/events/consumer/process_batch.rb +41 -0
- data/lib/ddtrace/contrib/kafka/events/consumer/process_message.rb +39 -0
- data/lib/ddtrace/contrib/kafka/events/consumer_group/heartbeat.rb +39 -0
- data/lib/ddtrace/contrib/kafka/events/consumer_group/join_group.rb +29 -0
- data/lib/ddtrace/contrib/kafka/events/consumer_group/leave_group.rb +29 -0
- data/lib/ddtrace/contrib/kafka/events/consumer_group/sync_group.rb +29 -0
- data/lib/ddtrace/contrib/kafka/events/produce_operation/send_messages.rb +32 -0
- data/lib/ddtrace/contrib/kafka/events/producer/deliver_messages.rb +35 -0
- data/lib/ddtrace/contrib/kafka/ext.rb +38 -0
- data/lib/ddtrace/contrib/kafka/integration.rb +39 -0
- data/lib/ddtrace/contrib/kafka/patcher.rb +26 -0
- data/lib/ddtrace/contrib/mongodb/instrumentation.rb +1 -2
- data/lib/ddtrace/contrib/mysql2/instrumentation.rb +1 -1
- data/lib/ddtrace/contrib/patcher.rb +14 -8
- data/lib/ddtrace/contrib/rack/middlewares.rb +15 -12
- data/lib/ddtrace/contrib/rails/configuration/settings.rb +13 -11
- data/lib/ddtrace/contrib/rails/framework.rb +52 -46
- data/lib/ddtrace/contrib/rails/integration.rb +1 -1
- data/lib/ddtrace/contrib/redis/patcher.rb +1 -1
- data/lib/ddtrace/contrib/rest_client/request_patch.rb +2 -2
- data/lib/ddtrace/contrib/sequel/database.rb +1 -1
- data/lib/ddtrace/contrib/sidekiq/ext.rb +1 -0
- data/lib/ddtrace/contrib/sidekiq/patcher.rb +8 -1
- data/lib/ddtrace/contrib/sidekiq/server_tracer.rb +1 -0
- data/lib/ddtrace/contrib/sucker_punch/patcher.rb +1 -1
- data/lib/ddtrace/diagnostics/environment_logger.rb +278 -0
- data/lib/ddtrace/environment.rb +5 -1
- data/lib/ddtrace/ext/diagnostics.rb +2 -0
- data/lib/ddtrace/ext/environment.rb +2 -0
- data/lib/ddtrace/pin.rb +39 -15
- data/lib/ddtrace/pipeline/span_filter.rb +15 -15
- data/lib/ddtrace/sampler.rb +2 -0
- data/lib/ddtrace/span.rb +10 -0
- data/lib/ddtrace/tracer.rb +15 -8
- data/lib/ddtrace/transport/http/adapters/net.rb +8 -0
- data/lib/ddtrace/transport/http/adapters/test.rb +4 -0
- data/lib/ddtrace/transport/http/adapters/unix_socket.rb +4 -0
- data/lib/ddtrace/transport/response.rb +11 -0
- data/lib/ddtrace/version.rb +1 -1
- data/lib/ddtrace/workers/trace_writer.rb +3 -0
- data/lib/ddtrace/writer.rb +33 -12
- metadata +98 -3
|
@@ -49,14 +49,13 @@ module Datadog
|
|
|
49
49
|
module InstanceMethods
|
|
50
50
|
def datadog_pin
|
|
51
51
|
@datadog_pin ||= begin
|
|
52
|
-
tracer = Datadog.configuration[:mongo][:tracer]
|
|
53
52
|
service = Datadog.configuration[:mongo][:service_name]
|
|
54
53
|
|
|
55
54
|
Datadog::Pin.new(
|
|
56
55
|
service,
|
|
57
56
|
app: Datadog::Contrib::MongoDB::Ext::APP,
|
|
58
57
|
app_type: Datadog::Ext::AppTypes::DB,
|
|
59
|
-
tracer: tracer
|
|
58
|
+
tracer: -> { Datadog.configuration[:mongo][:tracer] }
|
|
60
59
|
)
|
|
61
60
|
end
|
|
62
61
|
end
|
|
@@ -31,18 +31,24 @@ module Datadog
|
|
|
31
31
|
Datadog.health_metrics.instrumentation_patched(1, tags: default_tags)
|
|
32
32
|
end
|
|
33
33
|
rescue StandardError => e
|
|
34
|
-
|
|
35
|
-
Datadog.logger.error("Failed to apply #{patch_name} patch. Cause: #{e} Location: #{e.backtrace.first}")
|
|
36
|
-
|
|
37
|
-
# Emit a metric
|
|
38
|
-
tags = default_tags
|
|
39
|
-
tags << "error:#{e.class.name}"
|
|
40
|
-
|
|
41
|
-
Datadog.health_metrics.error_instrumentation_patch(1, tags: tags)
|
|
34
|
+
on_patch_error(e)
|
|
42
35
|
end
|
|
43
36
|
end
|
|
44
37
|
end
|
|
45
38
|
|
|
39
|
+
# Processes patching errors. This default implementation logs the error and reports relevant metrics.
|
|
40
|
+
# @param e [Exception]
|
|
41
|
+
def on_patch_error(e)
|
|
42
|
+
# Log the error
|
|
43
|
+
Datadog.logger.error("Failed to apply #{patch_name} patch. Cause: #{e} Location: #{e.backtrace.first}")
|
|
44
|
+
|
|
45
|
+
# Emit a metric
|
|
46
|
+
tags = default_tags
|
|
47
|
+
tags << "error:#{e.class.name}"
|
|
48
|
+
|
|
49
|
+
Datadog.health_metrics.error_instrumentation_patch(1, tags: tags)
|
|
50
|
+
end
|
|
51
|
+
|
|
46
52
|
private
|
|
47
53
|
|
|
48
54
|
def default_tags
|
|
@@ -98,23 +98,26 @@ module Datadog
|
|
|
98
98
|
request_span.set_error(e) unless request_span.nil?
|
|
99
99
|
raise e
|
|
100
100
|
ensure
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
101
|
+
if request_span
|
|
102
|
+
# Rack is a really low level interface and it doesn't provide any
|
|
103
|
+
# advanced functionality like routers. Because of that, we assume that
|
|
104
|
+
# the underlying framework or application has more knowledge about
|
|
105
|
+
# the result for this request; `resource` and `tags` are expected to
|
|
106
|
+
# be set in another level but if they're missing, reasonable defaults
|
|
107
|
+
# are used.
|
|
108
|
+
set_request_tags!(request_span, env, status, headers, response, original_env || env)
|
|
109
|
+
|
|
110
|
+
# ensure the request_span is finished and the context reset;
|
|
111
|
+
# this assumes that the Rack middleware creates a root span
|
|
112
|
+
request_span.finish
|
|
113
|
+
end
|
|
114
|
+
|
|
112
115
|
frontend_span.finish unless frontend_span.nil?
|
|
113
116
|
|
|
114
117
|
# TODO: Remove this once we change how context propagation works. This
|
|
115
118
|
# ensures we clean thread-local variables on each HTTP request avoiding
|
|
116
119
|
# memory leaks.
|
|
117
|
-
tracer.provider.context = Datadog::Context.new
|
|
120
|
+
tracer.provider.context = Datadog::Context.new if tracer
|
|
118
121
|
end
|
|
119
122
|
|
|
120
123
|
def resource_name_for(env, status)
|
|
@@ -6,6 +6,19 @@ module Datadog
|
|
|
6
6
|
module Configuration
|
|
7
7
|
# Custom settings for the Rails integration
|
|
8
8
|
class Settings < Contrib::Configuration::Settings
|
|
9
|
+
def initialize(options = {})
|
|
10
|
+
super(options)
|
|
11
|
+
|
|
12
|
+
# NOTE: Eager load these
|
|
13
|
+
# Rails integration is responsible for orchestrating other integrations.
|
|
14
|
+
# When using environment variables, settings will not be automatically
|
|
15
|
+
# filled because nothing explicitly calls them. They must though, so
|
|
16
|
+
# integrations like ActionPack can receive the value as it should.
|
|
17
|
+
# Trigger these manually to force an eager load and propagate them.
|
|
18
|
+
analytics_enabled
|
|
19
|
+
analytics_sample_rate
|
|
20
|
+
end
|
|
21
|
+
|
|
9
22
|
option :analytics_enabled do |o|
|
|
10
23
|
o.default { env_to_bool(Ext::ENV_ANALYTICS_ENABLED, nil) }
|
|
11
24
|
o.lazy
|
|
@@ -63,17 +76,6 @@ module Datadog
|
|
|
63
76
|
Datadog.configuration[:action_view][:template_base_path] = value
|
|
64
77
|
end
|
|
65
78
|
end
|
|
66
|
-
|
|
67
|
-
option :tracer do |o|
|
|
68
|
-
o.delegate_to { Datadog.tracer }
|
|
69
|
-
o.on_set do |value|
|
|
70
|
-
Datadog.configuration[:action_cable][:tracer] = value
|
|
71
|
-
Datadog.configuration[:active_record][:tracer] = value
|
|
72
|
-
Datadog.configuration[:active_support][:tracer] = value
|
|
73
|
-
Datadog.configuration[:action_pack][:tracer] = value
|
|
74
|
-
Datadog.configuration[:action_view][:tracer] = value
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
79
|
end
|
|
78
80
|
end
|
|
79
81
|
end
|
|
@@ -19,32 +19,40 @@ module Datadog
|
|
|
19
19
|
# - handle configuration entries which are specific to Datadog tracing
|
|
20
20
|
# - instrument parts of the framework when needed
|
|
21
21
|
module Framework
|
|
22
|
-
# configure
|
|
22
|
+
# After the Rails application finishes initializing, we configure the Rails
|
|
23
|
+
# integration and all its sub-components with the application information
|
|
24
|
+
# available.
|
|
25
|
+
# We do this after the initialization because not all the information we
|
|
26
|
+
# require is available before then.
|
|
23
27
|
def self.setup
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
28
|
+
# NOTE: #configure has the side effect of rebuilding trace components.
|
|
29
|
+
# During a typical Rails application lifecycle, we will see trace
|
|
30
|
+
# components initialized twice because of this. This is necessary
|
|
31
|
+
# because key configuration is not available until after the Rails
|
|
32
|
+
# application has fully loaded, and some of this configuration is
|
|
33
|
+
# used to reconfigure tracer components with Rails-sourced defaults.
|
|
34
|
+
# This is a trade-off we take to get nice defaults.
|
|
35
|
+
Datadog.configure do |datadog_config|
|
|
36
|
+
rails_config = config_with_defaults(datadog_config)
|
|
37
|
+
|
|
38
|
+
# By default, default service would be guessed from the script
|
|
39
|
+
# being executed, but here we know better, get it from Rails config.
|
|
40
|
+
# Don't set this if service has been explicitly provided by the user.
|
|
41
|
+
datadog_config.service ||= rails_config[:service_name]
|
|
42
|
+
|
|
43
|
+
activate_rack!(datadog_config, rails_config)
|
|
44
|
+
activate_action_cable!(datadog_config, rails_config)
|
|
45
|
+
activate_active_support!(datadog_config, rails_config)
|
|
46
|
+
activate_action_pack!(datadog_config, rails_config)
|
|
47
|
+
activate_action_view!(datadog_config, rails_config)
|
|
48
|
+
activate_active_record!(datadog_config, rails_config)
|
|
41
49
|
end
|
|
42
50
|
end
|
|
43
51
|
|
|
44
|
-
def self.config_with_defaults
|
|
52
|
+
def self.config_with_defaults(datadog_config)
|
|
45
53
|
# We set defaults here instead of in the patcher because we need to wait
|
|
46
54
|
# for the Rails application to be fully initialized.
|
|
47
|
-
|
|
55
|
+
datadog_config[:rails].tap do |config|
|
|
48
56
|
config[:service_name] ||= (Datadog.configuration.service || Utils.app_name)
|
|
49
57
|
config[:database_service] ||= "#{config[:service_name]}-#{Contrib::ActiveRecord::Utils.adapter_name}"
|
|
50
58
|
config[:controller_service] ||= config[:service_name]
|
|
@@ -52,64 +60,62 @@ module Datadog
|
|
|
52
60
|
end
|
|
53
61
|
end
|
|
54
62
|
|
|
55
|
-
def self.activate_rack!(
|
|
56
|
-
|
|
63
|
+
def self.activate_rack!(datadog_config, rails_config)
|
|
64
|
+
datadog_config.use(
|
|
57
65
|
:rack,
|
|
58
|
-
tracer: config[:tracer],
|
|
59
66
|
application: ::Rails.application,
|
|
60
|
-
service_name:
|
|
61
|
-
middleware_names:
|
|
62
|
-
distributed_tracing:
|
|
67
|
+
service_name: rails_config[:service_name],
|
|
68
|
+
middleware_names: rails_config[:middleware_names],
|
|
69
|
+
distributed_tracing: rails_config[:distributed_tracing]
|
|
63
70
|
)
|
|
64
71
|
end
|
|
65
72
|
|
|
66
|
-
def self.activate_active_support!(
|
|
73
|
+
def self.activate_active_support!(datadog_config, rails_config)
|
|
67
74
|
return unless defined?(::ActiveSupport)
|
|
68
75
|
|
|
69
|
-
|
|
76
|
+
datadog_config.use(
|
|
70
77
|
:active_support,
|
|
71
|
-
cache_service:
|
|
72
|
-
tracer: config[:tracer]
|
|
78
|
+
cache_service: rails_config[:cache_service]
|
|
73
79
|
)
|
|
74
80
|
end
|
|
75
81
|
|
|
76
|
-
def self.activate_action_cable!(
|
|
82
|
+
def self.activate_action_cable!(datadog_config, rails_config)
|
|
77
83
|
return unless defined?(::ActionCable)
|
|
78
84
|
|
|
79
|
-
|
|
85
|
+
datadog_config.use(
|
|
80
86
|
:action_cable,
|
|
81
|
-
service_name: "#{
|
|
82
|
-
tracer: config[:tracer]
|
|
87
|
+
service_name: "#{rails_config[:service_name]}-#{Contrib::ActionCable::Ext::SERVICE_NAME}"
|
|
83
88
|
)
|
|
84
89
|
end
|
|
85
90
|
|
|
86
|
-
def self.activate_action_pack!(
|
|
91
|
+
def self.activate_action_pack!(datadog_config, rails_config)
|
|
87
92
|
return unless defined?(::ActionPack)
|
|
88
93
|
|
|
89
|
-
|
|
94
|
+
# TODO: This is configuring ActionPack but not patching. It will queue ActionPack
|
|
95
|
+
# for patching, but patching won't take place until Datadog.configure completes.
|
|
96
|
+
# Should we manually patch here?
|
|
97
|
+
|
|
98
|
+
datadog_config.use(
|
|
90
99
|
:action_pack,
|
|
91
|
-
service_name:
|
|
92
|
-
tracer: config[:tracer]
|
|
100
|
+
service_name: rails_config[:service_name]
|
|
93
101
|
)
|
|
94
102
|
end
|
|
95
103
|
|
|
96
|
-
def self.activate_action_view!(
|
|
104
|
+
def self.activate_action_view!(datadog_config, rails_config)
|
|
97
105
|
return unless defined?(::ActionView)
|
|
98
106
|
|
|
99
|
-
|
|
107
|
+
datadog_config.use(
|
|
100
108
|
:action_view,
|
|
101
|
-
service_name:
|
|
102
|
-
tracer: config[:tracer]
|
|
109
|
+
service_name: rails_config[:service_name]
|
|
103
110
|
)
|
|
104
111
|
end
|
|
105
112
|
|
|
106
|
-
def self.activate_active_record!(
|
|
113
|
+
def self.activate_active_record!(datadog_config, rails_config)
|
|
107
114
|
return unless defined?(::ActiveRecord)
|
|
108
115
|
|
|
109
|
-
|
|
116
|
+
datadog_config.use(
|
|
110
117
|
:active_record,
|
|
111
|
-
service_name:
|
|
112
|
-
tracer: config[:tracer]
|
|
118
|
+
service_name: rails_config[:database_service]
|
|
113
119
|
)
|
|
114
120
|
end
|
|
115
121
|
end
|
|
@@ -62,11 +62,11 @@ module Datadog
|
|
|
62
62
|
# rubocop:disable Lint/RescueException
|
|
63
63
|
rescue Exception => e
|
|
64
64
|
# rubocop:enable Lint/RescueException
|
|
65
|
-
span.set_error(e)
|
|
65
|
+
span.set_error(e) if span
|
|
66
66
|
|
|
67
67
|
raise e
|
|
68
68
|
ensure
|
|
69
|
-
span.finish
|
|
69
|
+
span.finish if span
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
private
|
|
@@ -36,7 +36,7 @@ module Datadog
|
|
|
36
36
|
Datadog.configuration[:sequel][:service_name] || adapter_name,
|
|
37
37
|
app: Ext::APP,
|
|
38
38
|
app_type: Datadog::Ext::AppTypes::DB,
|
|
39
|
-
tracer: Datadog.configuration[:sequel][:tracer]
|
|
39
|
+
tracer: -> { Datadog.configuration[:sequel][:tracer] }
|
|
40
40
|
)
|
|
41
41
|
end
|
|
42
42
|
|
|
@@ -15,6 +15,7 @@ module Datadog
|
|
|
15
15
|
TAG_JOB_ID = 'sidekiq.job.id'.freeze
|
|
16
16
|
TAG_JOB_QUEUE = 'sidekiq.job.queue'.freeze
|
|
17
17
|
TAG_JOB_RETRY = 'sidekiq.job.retry'.freeze
|
|
18
|
+
TAG_JOB_RETRY_COUNT = 'sidekiq.job.retry_count'.freeze
|
|
18
19
|
TAG_JOB_WRAPPER = 'sidekiq.job.wrapper'.freeze
|
|
19
20
|
TAG_JOB_ARGS = 'sidekiq.job.args'.freeze
|
|
20
21
|
end
|
|
@@ -15,14 +15,21 @@ module Datadog
|
|
|
15
15
|
|
|
16
16
|
def patch
|
|
17
17
|
require 'ddtrace/contrib/sidekiq/client_tracer'
|
|
18
|
+
require 'ddtrace/contrib/sidekiq/server_tracer'
|
|
19
|
+
|
|
18
20
|
::Sidekiq.configure_client do |config|
|
|
19
21
|
config.client_middleware do |chain|
|
|
20
22
|
chain.add(Sidekiq::ClientTracer)
|
|
21
23
|
end
|
|
22
24
|
end
|
|
23
25
|
|
|
24
|
-
require 'ddtrace/contrib/sidekiq/server_tracer'
|
|
25
26
|
::Sidekiq.configure_server do |config|
|
|
27
|
+
# If a job enqueues another job, make sure it has the same client
|
|
28
|
+
# middleware.
|
|
29
|
+
config.client_middleware do |chain|
|
|
30
|
+
chain.add(Sidekiq::ClientTracer)
|
|
31
|
+
end
|
|
32
|
+
|
|
26
33
|
config.server_middleware do |chain|
|
|
27
34
|
chain.add(Sidekiq::ServerTracer)
|
|
28
35
|
end
|
|
@@ -31,6 +31,7 @@ module Datadog
|
|
|
31
31
|
|
|
32
32
|
span.set_tag(Ext::TAG_JOB_ID, job['jid'])
|
|
33
33
|
span.set_tag(Ext::TAG_JOB_RETRY, job['retry'])
|
|
34
|
+
span.set_tag(Ext::TAG_JOB_RETRY_COUNT, job['retry_count'])
|
|
34
35
|
span.set_tag(Ext::TAG_JOB_QUEUE, job['queue'])
|
|
35
36
|
span.set_tag(Ext::TAG_JOB_WRAPPER, job['class']) if job['wrapped']
|
|
36
37
|
span.set_tag(Ext::TAG_JOB_DELAY, 1000.0 * (Time.now.utc.to_f - job['enqueued_at'].to_f))
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
require 'date'
|
|
2
|
+
require 'json'
|
|
3
|
+
require 'rbconfig'
|
|
4
|
+
|
|
5
|
+
module Datadog
|
|
6
|
+
module Diagnostics
|
|
7
|
+
# A holistic collection of the environment in which ddtrace is running.
|
|
8
|
+
# This logger should allow for easy reporting by users to Datadog support.
|
|
9
|
+
#
|
|
10
|
+
# rubocop:disable Style/DoubleNegation
|
|
11
|
+
module EnvironmentLogger
|
|
12
|
+
class << self
|
|
13
|
+
# Outputs environment information to {Datadog.logger}.
|
|
14
|
+
# Executes only for the lifetime of the program.
|
|
15
|
+
def log!(transport_responses)
|
|
16
|
+
return if @executed || !log?
|
|
17
|
+
@executed = true
|
|
18
|
+
|
|
19
|
+
data = EnvironmentCollector.new.collect!(transport_responses)
|
|
20
|
+
data.reject! { |_, v| v.nil? } # Remove empty values from hash output
|
|
21
|
+
|
|
22
|
+
log_environment!(data.to_json)
|
|
23
|
+
log_error!('Agent Error'.freeze, data[:agent_error]) if data[:agent_error]
|
|
24
|
+
rescue => e
|
|
25
|
+
Datadog.logger.warn("Failed to collect environment information: #{e} location: #{e.backtrace.first}")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def log_environment!(line)
|
|
31
|
+
Datadog.logger.warn("DATADOG TRACER CONFIGURATION - #{line}")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def log_error!(type, error)
|
|
35
|
+
Datadog.logger.warn("DATADOG TRACER DIAGNOSTIC - #{type}: #{error}")
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Are we logging the environment data?
|
|
39
|
+
def log?
|
|
40
|
+
startup_logs_enabled = Datadog.configuration.diagnostics.startup_logs.enabled
|
|
41
|
+
if startup_logs_enabled.nil?
|
|
42
|
+
!repl? # Suppress logs if we running in a REPL
|
|
43
|
+
else
|
|
44
|
+
startup_logs_enabled
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
REPL_PROGRAM_NAMES = %w[irb pry].freeze
|
|
49
|
+
|
|
50
|
+
def repl?
|
|
51
|
+
REPL_PROGRAM_NAMES.include?($PROGRAM_NAME)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Collects environment information for diagnostic logging
|
|
57
|
+
class EnvironmentCollector
|
|
58
|
+
# @return [String] current time in ISO8601 format
|
|
59
|
+
def date
|
|
60
|
+
DateTime.now.iso8601
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Best portable guess of OS information.
|
|
64
|
+
# @return [String] platform string
|
|
65
|
+
def os_name
|
|
66
|
+
RbConfig::CONFIG['host'.freeze]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# @return [String] ddtrace version
|
|
70
|
+
def version
|
|
71
|
+
VERSION::STRING
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# @return [String] "ruby"
|
|
75
|
+
def lang
|
|
76
|
+
Ext::Runtime::LANG
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Supported Ruby language version.
|
|
80
|
+
# Will be distinct from VM version for non-MRI environments.
|
|
81
|
+
# @return [String]
|
|
82
|
+
def lang_version
|
|
83
|
+
Ext::Runtime::LANG_VERSION
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# @return [String] configured application environment
|
|
87
|
+
def env
|
|
88
|
+
Datadog.configuration.env
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# @return [Boolean, nil]
|
|
92
|
+
def enabled
|
|
93
|
+
Datadog.configuration.tracer.enabled
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# @return [String] configured application service name
|
|
97
|
+
def service
|
|
98
|
+
Datadog.configuration.service
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# @return [String] configured application version
|
|
102
|
+
def dd_version
|
|
103
|
+
Datadog.configuration.version
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# @return [String] target agent URL for trace flushing
|
|
107
|
+
def agent_url
|
|
108
|
+
# Retrieve the effect agent URL, regardless of how it was configured
|
|
109
|
+
transport = Datadog.tracer.writer.transport
|
|
110
|
+
adapter = transport.client.api.adapter
|
|
111
|
+
adapter.url
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Error returned by Datadog agent during a tracer flush attempt
|
|
115
|
+
# @return [String] concatenated list of transport errors
|
|
116
|
+
def agent_error(transport_responses)
|
|
117
|
+
error_responses = transport_responses.reject(&:ok?)
|
|
118
|
+
|
|
119
|
+
return nil if error_responses.empty?
|
|
120
|
+
|
|
121
|
+
error_responses.map(&:inspect).join(','.freeze)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# @return [Boolean, nil] debug mode enabled in configuration
|
|
125
|
+
def debug
|
|
126
|
+
!!Datadog.configuration.diagnostics.debug
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# @return [Boolean, nil] analytics enabled in configuration
|
|
130
|
+
def analytics_enabled
|
|
131
|
+
!!Datadog.configuration.analytics.enabled
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# @return [Numeric, nil] tracer sample rate configured
|
|
135
|
+
def sample_rate
|
|
136
|
+
sampler = Datadog.configuration.tracer.sampler
|
|
137
|
+
return nil unless sampler
|
|
138
|
+
|
|
139
|
+
sampler.sample_rate(nil) rescue nil
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# DEV: We currently only support SimpleRule instances.
|
|
143
|
+
# DEV: These are the most commonly used rules.
|
|
144
|
+
# DEV: We should expand support for other rules in the future,
|
|
145
|
+
# DEV: although it is tricky to serialize arbitrary rules.
|
|
146
|
+
#
|
|
147
|
+
# @return [Hash, nil] sample rules configured
|
|
148
|
+
def sampling_rules
|
|
149
|
+
sampler = Datadog.configuration.tracer.sampler
|
|
150
|
+
return nil unless sampler.is_a?(Datadog::PrioritySampler) &&
|
|
151
|
+
sampler.priority_sampler.is_a?(Datadog::Sampling::RuleSampler)
|
|
152
|
+
|
|
153
|
+
sampler.priority_sampler.rules.map do |rule|
|
|
154
|
+
next unless rule.is_a?(Datadog::Sampling::SimpleRule)
|
|
155
|
+
|
|
156
|
+
{
|
|
157
|
+
name: rule.matcher.name,
|
|
158
|
+
service: rule.matcher.service,
|
|
159
|
+
sample_rate: rule.sampler.sample_rate(nil)
|
|
160
|
+
}
|
|
161
|
+
end.compact
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# @return [Hash, nil] concatenated list of global tracer tags configured
|
|
165
|
+
def tags
|
|
166
|
+
tags = Datadog.configuration.tags
|
|
167
|
+
return nil if tags.empty?
|
|
168
|
+
hash_serializer(tags)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# @return [Boolean, nil] runtime metrics enabled in configuration
|
|
172
|
+
def runtime_metrics_enabled
|
|
173
|
+
Datadog.configuration.runtime_metrics.enabled
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Concatenated list of integrations activated, with their gem version.
|
|
177
|
+
# Example: "rails@6.0.3,rack@2.2.3"
|
|
178
|
+
#
|
|
179
|
+
# @return [String, nil]
|
|
180
|
+
def integrations_loaded
|
|
181
|
+
integrations = instrumented_integrations
|
|
182
|
+
return if integrations.empty?
|
|
183
|
+
|
|
184
|
+
integrations.map { |name, integration| "#{name}@#{integration.class.version}" }.join(','.freeze)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# Ruby VM name and version.
|
|
188
|
+
# Examples: "ruby-2.7.1", "jruby-9.2.11.1", "truffleruby-20.1.0"
|
|
189
|
+
# @return [String, nil]
|
|
190
|
+
def vm
|
|
191
|
+
# RUBY_ENGINE_VERSION returns the VM version, which
|
|
192
|
+
# will differ from RUBY_VERSION for non-mri VMs.
|
|
193
|
+
if defined?(RUBY_ENGINE_VERSION)
|
|
194
|
+
"#{RUBY_ENGINE}-#{RUBY_ENGINE_VERSION}"
|
|
195
|
+
else
|
|
196
|
+
# Ruby < 2.3 doesn't support RUBY_ENGINE_VERSION
|
|
197
|
+
"#{RUBY_ENGINE}-#{RUBY_VERSION}"
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
# @return [Boolean, nil] partial flushing enabled in configuration
|
|
202
|
+
def partial_flushing_enabled
|
|
203
|
+
!!Datadog.configuration.tracer.partial_flush.enabled
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# @return [Boolean, nil] priority sampling enabled in configuration
|
|
207
|
+
def priority_sampling_enabled
|
|
208
|
+
!!Datadog.configuration.tracer.priority_sampling
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# @return [Boolean, nil] health metrics enabled in configuration
|
|
212
|
+
def health_metrics_enabled
|
|
213
|
+
!!Datadog.configuration.diagnostics.health_metrics.enabled
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
# TODO: Populate when profiling is implemented
|
|
217
|
+
# def profiling_enabled
|
|
218
|
+
# end
|
|
219
|
+
|
|
220
|
+
# TODO: Populate when automatic log correlation is implemented
|
|
221
|
+
# def logs_correlation_enabled
|
|
222
|
+
# end
|
|
223
|
+
|
|
224
|
+
# @return [Hash] environment information available at call time
|
|
225
|
+
def collect!(transport_responses)
|
|
226
|
+
{
|
|
227
|
+
date: date,
|
|
228
|
+
os_name: os_name,
|
|
229
|
+
version: version,
|
|
230
|
+
lang: lang,
|
|
231
|
+
lang_version: lang_version,
|
|
232
|
+
env: env,
|
|
233
|
+
enabled: enabled,
|
|
234
|
+
service: service,
|
|
235
|
+
dd_version: dd_version,
|
|
236
|
+
agent_url: agent_url,
|
|
237
|
+
agent_error: agent_error(transport_responses),
|
|
238
|
+
debug: debug,
|
|
239
|
+
analytics_enabled: analytics_enabled,
|
|
240
|
+
sample_rate: sample_rate,
|
|
241
|
+
sampling_rules: sampling_rules,
|
|
242
|
+
tags: tags,
|
|
243
|
+
runtime_metrics_enabled: runtime_metrics_enabled,
|
|
244
|
+
integrations_loaded: integrations_loaded,
|
|
245
|
+
vm: vm,
|
|
246
|
+
partial_flushing_enabled: partial_flushing_enabled,
|
|
247
|
+
priority_sampling_enabled: priority_sampling_enabled,
|
|
248
|
+
health_metrics_enabled: health_metrics_enabled,
|
|
249
|
+
**instrumented_integrations_settings
|
|
250
|
+
}
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
private
|
|
254
|
+
|
|
255
|
+
def instrumented_integrations
|
|
256
|
+
Datadog.configuration.instrumented_integrations
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
# Capture all active integration settings into "integrationName_settingName: value" entries.
|
|
260
|
+
def instrumented_integrations_settings
|
|
261
|
+
Hash[instrumented_integrations.flat_map do |name, integration|
|
|
262
|
+
integration.configuration.to_h.flat_map do |setting, value|
|
|
263
|
+
next [] if setting == :tracer # Skip internal Ruby objects
|
|
264
|
+
|
|
265
|
+
# Convert value to a string to avoid custom #to_json
|
|
266
|
+
# handlers possibly causing errors.
|
|
267
|
+
[[:"integration_#{name}_#{setting}", value.to_s]]
|
|
268
|
+
end
|
|
269
|
+
end]
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# Outputs "k1:v1,k2:v2,..."
|
|
273
|
+
def hash_serializer(h)
|
|
274
|
+
h.map { |k, v| "#{k}:#{v}" }.join(','.freeze)
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
end
|