datadog 2.7.1 → 2.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +34 -1
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +47 -17
- data/ext/datadog_profiling_native_extension/extconf.rb +0 -8
- data/ext/datadog_profiling_native_extension/heap_recorder.c +11 -89
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +1 -1
- data/ext/datadog_profiling_native_extension/stack_recorder.c +0 -34
- data/ext/libdatadog_extconf_helpers.rb +1 -1
- data/lib/datadog/appsec/component.rb +1 -8
- data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +73 -0
- data/lib/datadog/appsec/contrib/active_record/integration.rb +41 -0
- data/lib/datadog/appsec/contrib/active_record/patcher.rb +53 -0
- data/lib/datadog/appsec/event.rb +1 -1
- data/lib/datadog/appsec/processor/context.rb +2 -2
- data/lib/datadog/appsec/remote.rb +1 -3
- data/lib/datadog/appsec/response.rb +7 -11
- data/lib/datadog/appsec.rb +3 -2
- data/lib/datadog/core/configuration/components.rb +17 -1
- data/lib/datadog/core/configuration/settings.rb +10 -0
- data/lib/datadog/core/configuration.rb +9 -1
- data/lib/datadog/core/remote/client/capabilities.rb +6 -0
- data/lib/datadog/core/remote/client.rb +65 -59
- data/lib/datadog/core/telemetry/component.rb +9 -3
- data/lib/datadog/core/telemetry/ext.rb +1 -0
- data/lib/datadog/di/code_tracker.rb +5 -4
- data/lib/datadog/di/component.rb +5 -1
- data/lib/datadog/di/contrib/active_record.rb +1 -0
- data/lib/datadog/di/init.rb +20 -0
- data/lib/datadog/di/instrumenter.rb +81 -11
- data/lib/datadog/di/probe.rb +11 -1
- data/lib/datadog/di/probe_builder.rb +1 -0
- data/lib/datadog/di/probe_manager.rb +4 -1
- data/lib/datadog/di/probe_notification_builder.rb +13 -7
- data/lib/datadog/di/remote.rb +124 -0
- data/lib/datadog/di/serializer.rb +14 -7
- data/lib/datadog/di/transport.rb +1 -1
- data/lib/datadog/di/utils.rb +7 -0
- data/lib/datadog/di.rb +84 -20
- data/lib/datadog/profiling/component.rb +4 -16
- data/lib/datadog/tracing/configuration/settings.rb +4 -8
- data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +16 -4
- data/lib/datadog/tracing/contrib/elasticsearch/configuration/settings.rb +4 -0
- data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +6 -1
- data/lib/datadog/version.rb +2 -2
- data/lib/datadog.rb +3 -0
- metadata +17 -13
- data/lib/datadog/appsec/processor/actions.rb +0 -49
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../patcher'
|
4
|
+
require_relative 'instrumentation'
|
5
|
+
|
6
|
+
module Datadog
|
7
|
+
module AppSec
|
8
|
+
module Contrib
|
9
|
+
module ActiveRecord
|
10
|
+
# AppSec patcher module for ActiveRecord
|
11
|
+
module Patcher
|
12
|
+
include Datadog::AppSec::Contrib::Patcher
|
13
|
+
|
14
|
+
module_function
|
15
|
+
|
16
|
+
def patched?
|
17
|
+
Patcher.instance_variable_get(:@patched)
|
18
|
+
end
|
19
|
+
|
20
|
+
def target_version
|
21
|
+
Integration.version
|
22
|
+
end
|
23
|
+
|
24
|
+
def patch
|
25
|
+
ActiveSupport.on_load :active_record do
|
26
|
+
instrumentation_module = if ::ActiveRecord.gem_version >= Gem::Version.new('7.1')
|
27
|
+
Instrumentation::InternalExecQueryAdapterPatch
|
28
|
+
else
|
29
|
+
Instrumentation::ExecQueryAdapterPatch
|
30
|
+
end
|
31
|
+
|
32
|
+
if defined?(::ActiveRecord::ConnectionAdapters::SQLite3Adapter)
|
33
|
+
::ActiveRecord::ConnectionAdapters::SQLite3Adapter.prepend(instrumentation_module)
|
34
|
+
end
|
35
|
+
|
36
|
+
if defined?(::ActiveRecord::ConnectionAdapters::Mysql2Adapter)
|
37
|
+
::ActiveRecord::ConnectionAdapters::Mysql2Adapter.prepend(instrumentation_module)
|
38
|
+
end
|
39
|
+
|
40
|
+
if defined?(::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
|
41
|
+
unless defined?(::ActiveRecord::ConnectionAdapters::JdbcAdapter)
|
42
|
+
instrumentation_module = Instrumentation::ExecuteAndClearAdapterPatch
|
43
|
+
end
|
44
|
+
|
45
|
+
::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.prepend(instrumentation_module)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/datadog/appsec/event.rb
CHANGED
@@ -142,7 +142,7 @@ module Datadog
|
|
142
142
|
scope.trace.keep! if scope.trace
|
143
143
|
|
144
144
|
if scope.service_entry_span
|
145
|
-
scope.service_entry_span.set_tag('appsec.blocked', 'true') if waf_result.actions.
|
145
|
+
scope.service_entry_span.set_tag('appsec.blocked', 'true') if waf_result.actions.key?('block_request')
|
146
146
|
scope.service_entry_span.set_tag('appsec.event', 'true')
|
147
147
|
end
|
148
148
|
|
@@ -19,7 +19,7 @@ module Datadog
|
|
19
19
|
@events = []
|
20
20
|
@run_mutex = Mutex.new
|
21
21
|
|
22
|
-
@libddwaf_debug_tag = "libddwaf:#{WAF::VERSION::STRING}"
|
22
|
+
@libddwaf_debug_tag = "libddwaf:#{WAF::VERSION::STRING} method:ddwaf_run"
|
23
23
|
end
|
24
24
|
|
25
25
|
def run(persistent_data, ephemeral_data, timeout = WAF::LibDDWAF::DDWAF_RUN_TIMEOUT)
|
@@ -79,7 +79,7 @@ module Datadog
|
|
79
79
|
@context.run(persistent_data, ephemeral_data, timeout)
|
80
80
|
rescue WAF::LibDDWAF::Error => e
|
81
81
|
Datadog.logger.debug { "#{@libddwaf_debug_tag} execution error: #{e} backtrace: #{e.backtrace&.first(3)}" }
|
82
|
-
@telemetry.report(e, description: 'libddwaf internal low-level error')
|
82
|
+
@telemetry.report(e, description: 'libddwaf-rb internal low-level error')
|
83
83
|
|
84
84
|
[:err_internal, WAF::Result.new(:err_internal, [], 0.0, false, [], [])]
|
85
85
|
end
|
@@ -67,7 +67,6 @@ module Datadog
|
|
67
67
|
data = []
|
68
68
|
overrides = []
|
69
69
|
exclusions = []
|
70
|
-
actions = []
|
71
70
|
|
72
71
|
repository.contents.each do |content|
|
73
72
|
parsed_content = parse_content(content)
|
@@ -81,7 +80,6 @@ module Datadog
|
|
81
80
|
overrides << parsed_content['rules_override'] if parsed_content['rules_override']
|
82
81
|
exclusions << parsed_content['exclusions'] if parsed_content['exclusions']
|
83
82
|
custom_rules << parsed_content['custom_rules'] if parsed_content['custom_rules']
|
84
|
-
actions.concat(parsed_content['actions']) if parsed_content['actions']
|
85
83
|
end
|
86
84
|
end
|
87
85
|
|
@@ -105,7 +103,7 @@ module Datadog
|
|
105
103
|
telemetry: telemetry
|
106
104
|
)
|
107
105
|
|
108
|
-
Datadog::AppSec.reconfigure(ruleset: ruleset,
|
106
|
+
Datadog::AppSec.reconfigure(ruleset: ruleset, telemetry: telemetry)
|
109
107
|
end
|
110
108
|
|
111
109
|
[receiver]
|
@@ -31,19 +31,16 @@ module Datadog
|
|
31
31
|
def negotiate(env, actions)
|
32
32
|
# @type var configured_response: Response?
|
33
33
|
configured_response = nil
|
34
|
-
actions.each do |
|
34
|
+
actions.each do |type, parameters|
|
35
35
|
# Need to use next to make steep happy :(
|
36
36
|
# I rather use break to stop the execution
|
37
37
|
next if configured_response
|
38
38
|
|
39
|
-
|
40
|
-
next unless action_configuration
|
41
|
-
|
42
|
-
configured_response = case action_configuration['type']
|
39
|
+
configured_response = case type
|
43
40
|
when 'block_request'
|
44
|
-
block_response(env,
|
41
|
+
block_response(env, parameters)
|
45
42
|
when 'redirect_request'
|
46
|
-
redirect_response(env,
|
43
|
+
redirect_response(env, parameters)
|
47
44
|
end
|
48
45
|
end
|
49
46
|
|
@@ -90,7 +87,7 @@ module Datadog
|
|
90
87
|
body << content(content_type)
|
91
88
|
|
92
89
|
Response.new(
|
93
|
-
status: options['status_code'] || 403,
|
90
|
+
status: options['status_code']&.to_i || 403,
|
94
91
|
headers: { 'Content-Type' => content_type },
|
95
92
|
body: body,
|
96
93
|
)
|
@@ -100,15 +97,14 @@ module Datadog
|
|
100
97
|
if options['location'] && !options['location'].empty?
|
101
98
|
content_type = content_type(env)
|
102
99
|
|
103
|
-
status = options['status_code'] >= 300 && options['status_code'] < 400 ? options['status_code'] : 303
|
104
|
-
|
105
100
|
headers = {
|
106
101
|
'Content-Type' => content_type,
|
107
102
|
'Location' => options['location']
|
108
103
|
}
|
109
104
|
|
105
|
+
status_code = options['status_code'].to_i
|
110
106
|
Response.new(
|
111
|
-
status:
|
107
|
+
status: (status_code >= 300 && status_code < 400 ? status_code : 303),
|
112
108
|
headers: headers,
|
113
109
|
body: [],
|
114
110
|
)
|
data/lib/datadog/appsec.rb
CHANGED
@@ -24,12 +24,12 @@ module Datadog
|
|
24
24
|
appsec_component.processor if appsec_component
|
25
25
|
end
|
26
26
|
|
27
|
-
def reconfigure(ruleset:,
|
27
|
+
def reconfigure(ruleset:, telemetry:)
|
28
28
|
appsec_component = components.appsec
|
29
29
|
|
30
30
|
return unless appsec_component
|
31
31
|
|
32
|
-
appsec_component.reconfigure(ruleset: ruleset,
|
32
|
+
appsec_component.reconfigure(ruleset: ruleset, telemetry: telemetry)
|
33
33
|
end
|
34
34
|
|
35
35
|
def reconfigure_lock(&block)
|
@@ -56,6 +56,7 @@ end
|
|
56
56
|
require_relative 'appsec/contrib/rack/integration'
|
57
57
|
require_relative 'appsec/contrib/sinatra/integration'
|
58
58
|
require_relative 'appsec/contrib/rails/integration'
|
59
|
+
require_relative 'appsec/contrib/active_record/integration'
|
59
60
|
require_relative 'appsec/contrib/devise/integration'
|
60
61
|
require_relative 'appsec/contrib/graphql/integration'
|
61
62
|
|
@@ -13,6 +13,7 @@ require_relative '../remote/component'
|
|
13
13
|
require_relative '../../tracing/component'
|
14
14
|
require_relative '../../profiling/component'
|
15
15
|
require_relative '../../appsec/component'
|
16
|
+
require_relative '../../di/component'
|
16
17
|
require_relative '../crashtracking/component'
|
17
18
|
|
18
19
|
module Datadog
|
@@ -83,6 +84,7 @@ module Datadog
|
|
83
84
|
:telemetry,
|
84
85
|
:tracer,
|
85
86
|
:crashtracker,
|
87
|
+
:dynamic_instrumentation,
|
86
88
|
:appsec
|
87
89
|
|
88
90
|
def initialize(settings)
|
@@ -110,12 +112,13 @@ module Datadog
|
|
110
112
|
@runtime_metrics = self.class.build_runtime_metrics_worker(settings)
|
111
113
|
@health_metrics = self.class.build_health_metrics(settings)
|
112
114
|
@appsec = Datadog::AppSec::Component.build_appsec_component(settings, telemetry: telemetry)
|
115
|
+
@dynamic_instrumentation = Datadog::DI::Component.build(settings, agent_settings, telemetry: telemetry)
|
113
116
|
|
114
117
|
self.class.configure_tracing(settings)
|
115
118
|
end
|
116
119
|
|
117
120
|
# Starts up components
|
118
|
-
def startup!(settings)
|
121
|
+
def startup!(settings, old_state: nil)
|
119
122
|
if settings.profiling.enabled
|
120
123
|
if profiler
|
121
124
|
profiler.start
|
@@ -126,6 +129,16 @@ module Datadog
|
|
126
129
|
end
|
127
130
|
end
|
128
131
|
|
132
|
+
if settings.remote.enabled && old_state&.[](:remote_started)
|
133
|
+
# The library was reconfigured and previously it already started
|
134
|
+
# the remote component (i.e., it received at least one request
|
135
|
+
# through the installed Rack middleware which started the remote).
|
136
|
+
# If the new configuration also has remote enabled, start the
|
137
|
+
# new remote right away.
|
138
|
+
# remote should always be not nil here but steep doesn't know this.
|
139
|
+
remote&.start
|
140
|
+
end
|
141
|
+
|
129
142
|
Core::Diagnostics::EnvironmentLogger.collect_and_log!(@environment_logger_extra)
|
130
143
|
end
|
131
144
|
|
@@ -136,6 +149,9 @@ module Datadog
|
|
136
149
|
# Shutdown remote configuration
|
137
150
|
remote.shutdown! if remote
|
138
151
|
|
152
|
+
# Shutdown DI after remote, since remote config triggers DI operations.
|
153
|
+
dynamic_instrumentation&.shutdown!
|
154
|
+
|
139
155
|
# Decommission AppSec
|
140
156
|
appsec.shutdown! if appsec
|
141
157
|
|
@@ -863,6 +863,16 @@ module Datadog
|
|
863
863
|
o.type :float
|
864
864
|
o.default 1.0
|
865
865
|
end
|
866
|
+
|
867
|
+
# Enable log collection for telemetry. Log collection only works when telemetry is enabled and
|
868
|
+
# logs are enabled.
|
869
|
+
# @default `DD_TELEMETRY_LOG_COLLECTION_ENABLED` environment variable, otherwise `true`.
|
870
|
+
# @return [Boolean]
|
871
|
+
option :log_collection_enabled do |o|
|
872
|
+
o.type :bool
|
873
|
+
o.env Core::Telemetry::Ext::ENV_LOG_COLLECTION
|
874
|
+
o.default true
|
875
|
+
end
|
866
876
|
end
|
867
877
|
|
868
878
|
# Remote configuration
|
@@ -258,8 +258,16 @@ module Datadog
|
|
258
258
|
def replace_components!(settings, old)
|
259
259
|
components = Components.new(settings)
|
260
260
|
|
261
|
+
# Carry over state from existing components to the new ones.
|
262
|
+
# Currently, if we already started the remote component (which
|
263
|
+
# happens after a request goes through installed Rack middleware),
|
264
|
+
# we will start the new remote component as well.
|
265
|
+
old_state = {
|
266
|
+
remote_started: old.remote&.started?,
|
267
|
+
}
|
268
|
+
|
261
269
|
old.shutdown!(components)
|
262
|
-
components.startup!(settings)
|
270
|
+
components.startup!(settings, old_state: old_state)
|
263
271
|
components
|
264
272
|
end
|
265
273
|
|
@@ -32,6 +32,12 @@ module Datadog
|
|
32
32
|
register_receivers(Datadog::AppSec::Remote.receivers(@telemetry))
|
33
33
|
end
|
34
34
|
|
35
|
+
if settings.respond_to?(:dynamic_instrumentation) && settings.dynamic_instrumentation.enabled
|
36
|
+
register_capabilities(Datadog::DI::Remote.capabilities)
|
37
|
+
register_products(Datadog::DI::Remote.products)
|
38
|
+
register_receivers(Datadog::DI::Remote.receivers(@telemetry))
|
39
|
+
end
|
40
|
+
|
35
41
|
register_capabilities(Datadog::Tracing::Remote.capabilities)
|
36
42
|
register_products(Datadog::Tracing::Remote.products)
|
37
43
|
register_receivers(Datadog::Tracing::Remote.receivers(@telemetry))
|
@@ -24,93 +24,99 @@ module Datadog
|
|
24
24
|
@dispatcher = Dispatcher.new(@capabilities.receivers)
|
25
25
|
end
|
26
26
|
|
27
|
-
# rubocop:disable Metrics/AbcSize,Metrics/PerceivedComplexity,Metrics/MethodLength,Metrics/CyclomaticComplexity
|
28
27
|
def sync
|
29
28
|
# TODO: Skip sync if no capabilities are registered
|
30
29
|
response = transport.send_config(payload)
|
31
30
|
|
32
31
|
if response.ok?
|
33
|
-
|
34
|
-
|
35
|
-
|
32
|
+
process_response(response)
|
33
|
+
elsif response.internal_error?
|
34
|
+
raise TransportError, response.to_s
|
35
|
+
end
|
36
|
+
end
|
36
37
|
|
37
|
-
|
38
|
-
end
|
38
|
+
private
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
def process_response(response)
|
41
|
+
# when response is completely empty, do nothing as in: leave as is
|
42
|
+
if response.empty?
|
43
|
+
Datadog.logger.debug { 'remote: empty response => NOOP' }
|
44
44
|
|
45
|
-
|
45
|
+
return
|
46
|
+
end
|
46
47
|
|
47
|
-
|
48
|
-
|
49
|
-
|
48
|
+
begin
|
49
|
+
paths = response.client_configs.map do |path|
|
50
|
+
Configuration::Path.parse(path)
|
50
51
|
end
|
51
52
|
|
52
|
-
|
53
|
-
|
53
|
+
targets = Configuration::TargetMap.parse(response.targets)
|
54
|
+
|
55
|
+
contents = Configuration::ContentList.parse(response.target_files)
|
56
|
+
rescue Remote::Configuration::Path::ParseError => e
|
57
|
+
raise SyncError, e.message
|
58
|
+
end
|
54
59
|
|
55
|
-
|
56
|
-
|
60
|
+
# To make sure steep does not complain
|
61
|
+
return unless paths && targets && contents
|
57
62
|
|
58
|
-
|
59
|
-
|
60
|
-
(current.paths - paths).each { |p| transaction.delete(p) }
|
63
|
+
# TODO: sometimes it can strangely be so that paths.empty?
|
64
|
+
# TODO: sometimes it can strangely be so that targets.empty?
|
61
65
|
|
62
|
-
|
63
|
-
|
64
|
-
# match target with path
|
65
|
-
target = targets[path]
|
66
|
+
apply_config(paths, targets, contents)
|
67
|
+
end
|
66
68
|
|
67
|
-
|
68
|
-
|
69
|
+
def apply_config(paths, targets, contents)
|
70
|
+
changes = repository.transaction do |current, transaction|
|
71
|
+
# paths to be removed: previously applied paths minus ingress paths
|
72
|
+
(current.paths - paths).each { |p| transaction.delete(p) }
|
69
73
|
|
70
|
-
|
71
|
-
|
74
|
+
# go through each ingress path
|
75
|
+
paths.each do |path|
|
76
|
+
# match target with path
|
77
|
+
target = targets[path]
|
72
78
|
|
73
|
-
|
74
|
-
|
75
|
-
changed = current.paths.include?(path) && !current.contents.find_content(path, target)
|
79
|
+
# abort entirely if matching target not found
|
80
|
+
raise SyncError, "no target for path '#{path}'" if target.nil?
|
76
81
|
|
77
|
-
|
78
|
-
|
82
|
+
# new paths are not in previously applied paths
|
83
|
+
new = !current.paths.include?(path)
|
79
84
|
|
80
|
-
|
85
|
+
# updated paths are in previously applied paths
|
86
|
+
# but the content hash changed
|
87
|
+
changed = current.paths.include?(path) && !current.contents.find_content(path, target)
|
81
88
|
|
82
|
-
|
83
|
-
|
89
|
+
# skip if unchanged
|
90
|
+
same = !new && !changed
|
84
91
|
|
85
|
-
|
86
|
-
raise SyncError, "no valid content for target at path '#{path}'" if content.nil?
|
92
|
+
next if same
|
87
93
|
|
88
|
-
|
89
|
-
|
90
|
-
transaction.insert(path, target, content) if new
|
91
|
-
transaction.update(path, target, content) if changed
|
92
|
-
end
|
94
|
+
# match content with path and target
|
95
|
+
content = contents.find_content(path, target)
|
93
96
|
|
94
|
-
#
|
95
|
-
|
96
|
-
transaction.set(targets_version: targets.version)
|
97
|
+
# abort entirely if matching content not found
|
98
|
+
raise SyncError, "no valid content for target at path '#{path}'" if content.nil?
|
97
99
|
|
98
|
-
#
|
99
|
-
# TODO:
|
100
|
+
# to be added or updated << config
|
101
|
+
# TODO: metadata (hash, version, etc...)
|
102
|
+
transaction.insert(path, target, content) if new
|
103
|
+
transaction.update(path, target, content) if changed
|
100
104
|
end
|
101
105
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
end
|
107
|
-
|
108
|
-
raise TransportError, response.to_s
|
106
|
+
# save backend opaque backend state
|
107
|
+
transaction.set(opaque_backend_state: targets.opaque_backend_state)
|
108
|
+
transaction.set(targets_version: targets.version)
|
109
|
+
|
110
|
+
# upon transaction end, new list of applied config + metadata (add, change, remove) will be saved
|
111
|
+
# TODO: also remove stale config (matching removed) from cache (client configs is exhaustive list of paths)
|
109
112
|
end
|
110
|
-
end
|
111
|
-
# rubocop:enable Metrics/AbcSize,Metrics/PerceivedComplexity,Metrics/MethodLength,Metrics/CyclomaticComplexity
|
112
113
|
|
113
|
-
|
114
|
+
if changes.empty?
|
115
|
+
Datadog.logger.debug { 'remote: no changes' }
|
116
|
+
else
|
117
|
+
dispatcher.dispatch(changes, repository)
|
118
|
+
end
|
119
|
+
end
|
114
120
|
|
115
121
|
def payload # rubocop:disable Metrics/MethodLength
|
116
122
|
state = repository.state
|
@@ -14,6 +14,7 @@ module Datadog
|
|
14
14
|
module Core
|
15
15
|
module Telemetry
|
16
16
|
# Telemetry entrypoint, coordinates sending telemetry events at various points in app lifecycle.
|
17
|
+
# Note: Telemetry does not spawn its worker thread in fork processes, thus no telemetry is sent in forked processes.
|
17
18
|
class Component
|
18
19
|
attr_reader :enabled
|
19
20
|
|
@@ -52,6 +53,7 @@ module Datadog
|
|
52
53
|
metrics_aggregation_interval_seconds: settings.telemetry.metrics_aggregation_interval_seconds,
|
53
54
|
dependency_collection: settings.telemetry.dependency_collection,
|
54
55
|
shutdown_timeout_seconds: settings.telemetry.shutdown_timeout_seconds,
|
56
|
+
log_collection_enabled: settings.telemetry.log_collection_enabled
|
55
57
|
)
|
56
58
|
end
|
57
59
|
|
@@ -67,10 +69,11 @@ module Datadog
|
|
67
69
|
http_transport:,
|
68
70
|
shutdown_timeout_seconds:,
|
69
71
|
enabled: true,
|
70
|
-
metrics_enabled: true
|
72
|
+
metrics_enabled: true,
|
73
|
+
log_collection_enabled: true
|
71
74
|
)
|
72
75
|
@enabled = enabled
|
73
|
-
@
|
76
|
+
@log_collection_enabled = log_collection_enabled
|
74
77
|
|
75
78
|
@metrics_manager = MetricsManager.new(
|
76
79
|
enabled: enabled && metrics_enabled,
|
@@ -86,6 +89,9 @@ module Datadog
|
|
86
89
|
dependency_collection: dependency_collection,
|
87
90
|
shutdown_timeout: shutdown_timeout_seconds
|
88
91
|
)
|
92
|
+
|
93
|
+
@stopped = false
|
94
|
+
|
89
95
|
@worker.start
|
90
96
|
end
|
91
97
|
|
@@ -114,7 +120,7 @@ module Datadog
|
|
114
120
|
end
|
115
121
|
|
116
122
|
def log!(event)
|
117
|
-
return
|
123
|
+
return if !@enabled || forked? || !@log_collection_enabled
|
118
124
|
|
119
125
|
@worker.enqueue(event)
|
120
126
|
end
|
@@ -13,6 +13,7 @@ module Datadog
|
|
13
13
|
ENV_INSTALL_TYPE = 'DD_INSTRUMENTATION_INSTALL_TYPE'
|
14
14
|
ENV_INSTALL_TIME = 'DD_INSTRUMENTATION_INSTALL_TIME'
|
15
15
|
ENV_AGENTLESS_URL_OVERRIDE = 'DD_TELEMETRY_AGENTLESS_URL'
|
16
|
+
ENV_LOG_COLLECTION = 'DD_TELEMETRY_LOG_COLLECTION_ENABLED'
|
16
17
|
end
|
17
18
|
end
|
18
19
|
end
|
@@ -78,17 +78,18 @@ module Datadog
|
|
78
78
|
registry_lock.synchronize do
|
79
79
|
registry[path] = tp.instruction_sequence
|
80
80
|
end
|
81
|
-
end
|
82
|
-
|
83
|
-
DI.component&.probe_manager&.install_pending_line_probes(path)
|
84
81
|
|
82
|
+
# Also, pending line probes should only be installed for
|
83
|
+
# non-eval'd code.
|
84
|
+
DI.current_component&.probe_manager&.install_pending_line_probes(path)
|
85
|
+
end
|
85
86
|
# Since this method normally is called from customer applications,
|
86
87
|
# rescue any exceptions that might not be handled to not break said
|
87
88
|
# customer applications.
|
88
89
|
rescue => exc
|
89
90
|
# TODO we do not have DI.component defined yet, remove steep:ignore
|
90
91
|
# before release.
|
91
|
-
if component = DI.
|
92
|
+
if component = DI.current_component # steep:ignore
|
92
93
|
raise if component.settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
93
94
|
component.logger.warn("Unhandled exception in script_compiled trace point: #{exc.class}: #{exc}")
|
94
95
|
component.telemetry&.report(exc, description: "Unhandled exception in script_compiled trace point")
|
data/lib/datadog/di/component.rb
CHANGED
@@ -24,7 +24,9 @@ module Datadog
|
|
24
24
|
|
25
25
|
return unless environment_supported?(settings)
|
26
26
|
|
27
|
-
new(settings, agent_settings, Datadog.logger, code_tracker: DI.code_tracker, telemetry: telemetry)
|
27
|
+
new(settings, agent_settings, Datadog.logger, code_tracker: DI.code_tracker, telemetry: telemetry).tap do |component|
|
28
|
+
DI.add_current_component(component)
|
29
|
+
end
|
28
30
|
end
|
29
31
|
|
30
32
|
def build!(settings, agent_settings, telemetry: nil)
|
@@ -99,6 +101,8 @@ module Datadog
|
|
99
101
|
# was replaced by a new instance, the new instance of it wouldn't have
|
100
102
|
# any of the already loaded code tracked.
|
101
103
|
def shutdown!(replacement = nil)
|
104
|
+
DI.remove_current_component(self)
|
105
|
+
|
102
106
|
probe_manager.clear_hooks
|
103
107
|
probe_manager.close
|
104
108
|
probe_notifier_worker.stop
|
@@ -5,6 +5,7 @@ Datadog::DI::Serializer.register(condition: lambda { |value| ActiveRecord::Base
|
|
5
5
|
# steep:ignore:start
|
6
6
|
value_to_serialize = {
|
7
7
|
attributes: value.attributes,
|
8
|
+
new_record: value.new_record?,
|
8
9
|
}
|
9
10
|
serializer.serialize_value(value_to_serialize, depth: depth ? depth - 1 : nil, type: value.class)
|
10
11
|
# steep:ignore:end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Require 'datadog/di/init' early in the application boot process to
|
4
|
+
# enable dynamic instrumentation for third-party libraries used by the
|
5
|
+
# application.
|
6
|
+
|
7
|
+
require_relative '../tracing'
|
8
|
+
require_relative '../tracing/contrib'
|
9
|
+
require_relative '../di'
|
10
|
+
|
11
|
+
# Code tracking is required for line probes to work; see the comments
|
12
|
+
# on the activate_tracking methods in di.rb for further details.
|
13
|
+
#
|
14
|
+
# Unlike di.rb which conditionally activates tracking only if the
|
15
|
+
# DD_DYNAMIC_INSTRUMENTATION_ENABLED environment variable is set, this file
|
16
|
+
# always activates tracking. This is because this file is explicitly loaded
|
17
|
+
# by customer applications for the purpose of enabling code tracking
|
18
|
+
# early in application boot process (i.e., before datadog library itself
|
19
|
+
# is loaded).
|
20
|
+
Datadog::DI.activate_tracking
|