datadog 2.8.0 → 2.10.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/CHANGELOG.md +62 -1
- data/ext/datadog_profiling_native_extension/clock_id.h +2 -2
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +66 -56
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +1 -1
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h +1 -1
- data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +16 -16
- data/ext/datadog_profiling_native_extension/collectors_stack.c +7 -7
- data/ext/datadog_profiling_native_extension/collectors_stack.h +2 -2
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +221 -127
- data/ext/datadog_profiling_native_extension/heap_recorder.c +50 -92
- data/ext/datadog_profiling_native_extension/heap_recorder.h +2 -2
- data/ext/datadog_profiling_native_extension/http_transport.c +4 -4
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +3 -0
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +3 -1
- data/ext/datadog_profiling_native_extension/profiling.c +10 -8
- data/ext/datadog_profiling_native_extension/ruby_helpers.c +8 -8
- data/ext/datadog_profiling_native_extension/stack_recorder.c +63 -76
- data/ext/datadog_profiling_native_extension/stack_recorder.h +2 -2
- data/ext/datadog_profiling_native_extension/time_helpers.h +1 -1
- data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.c +47 -0
- data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.h +31 -0
- data/ext/libdatadog_api/crashtracker.c +3 -0
- data/lib/datadog/appsec/actions_handler.rb +27 -0
- data/lib/datadog/appsec/assets/waf_rules/recommended.json +355 -157
- data/lib/datadog/appsec/assets/waf_rules/strict.json +62 -32
- data/lib/datadog/appsec/component.rb +14 -8
- data/lib/datadog/appsec/configuration/settings.rb +9 -0
- data/lib/datadog/appsec/context.rb +74 -0
- data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +12 -8
- data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +6 -6
- data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +4 -4
- data/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +1 -7
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +20 -30
- data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +6 -6
- data/lib/datadog/appsec/contrib/rack/gateway/response.rb +3 -3
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +67 -96
- data/lib/datadog/appsec/contrib/rack/reactive/request.rb +11 -11
- data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +6 -6
- data/lib/datadog/appsec/contrib/rack/reactive/response.rb +7 -7
- data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +10 -11
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +43 -60
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +23 -33
- data/lib/datadog/appsec/contrib/rails/patcher.rb +4 -14
- data/lib/datadog/appsec/contrib/rails/reactive/action.rb +7 -7
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +45 -65
- data/lib/datadog/appsec/contrib/sinatra/patcher.rb +5 -28
- data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +6 -6
- data/lib/datadog/appsec/event.rb +6 -6
- data/lib/datadog/appsec/ext.rb +8 -1
- data/lib/datadog/appsec/metrics/collector.rb +38 -0
- data/lib/datadog/appsec/metrics/exporter.rb +35 -0
- data/lib/datadog/appsec/metrics/telemetry.rb +23 -0
- data/lib/datadog/appsec/metrics.rb +13 -0
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +23 -32
- data/lib/datadog/appsec/monitor/reactive/set_user.rb +6 -6
- data/lib/datadog/appsec/processor/rule_loader.rb +0 -3
- data/lib/datadog/appsec/processor.rb +4 -3
- data/lib/datadog/appsec/response.rb +18 -80
- data/lib/datadog/appsec/security_engine/result.rb +67 -0
- data/lib/datadog/appsec/security_engine/runner.rb +88 -0
- data/lib/datadog/appsec/security_engine.rb +9 -0
- data/lib/datadog/appsec.rb +17 -8
- data/lib/datadog/auto_instrument.rb +3 -0
- data/lib/datadog/core/configuration/agent_settings_resolver.rb +39 -11
- data/lib/datadog/core/configuration/components.rb +4 -2
- data/lib/datadog/core/configuration.rb +1 -1
- data/lib/datadog/{tracing → core}/contrib/rails/utils.rb +1 -3
- data/lib/datadog/core/crashtracking/component.rb +1 -3
- data/lib/datadog/core/telemetry/event.rb +87 -3
- data/lib/datadog/core/telemetry/logging.rb +2 -2
- data/lib/datadog/core/telemetry/metric.rb +22 -0
- data/lib/datadog/core/telemetry/worker.rb +33 -0
- data/lib/datadog/di/base.rb +115 -0
- data/lib/datadog/di/code_tracker.rb +7 -4
- data/lib/datadog/di/component.rb +19 -11
- data/lib/datadog/di/configuration/settings.rb +11 -1
- data/lib/datadog/di/contrib/railtie.rb +15 -0
- data/lib/datadog/di/contrib.rb +26 -0
- data/lib/datadog/di/error.rb +5 -0
- data/lib/datadog/di/instrumenter.rb +39 -18
- data/lib/datadog/di/{init.rb → preload.rb} +2 -4
- data/lib/datadog/di/probe_manager.rb +4 -4
- data/lib/datadog/di/probe_notification_builder.rb +22 -2
- data/lib/datadog/di/probe_notifier_worker.rb +5 -6
- data/lib/datadog/di/redactor.rb +0 -1
- data/lib/datadog/di/remote.rb +30 -9
- data/lib/datadog/di/transport.rb +2 -4
- data/lib/datadog/di.rb +5 -108
- data/lib/datadog/kit/appsec/events.rb +3 -3
- data/lib/datadog/kit/identity.rb +4 -4
- data/lib/datadog/profiling/component.rb +55 -53
- data/lib/datadog/profiling/http_transport.rb +1 -26
- data/lib/datadog/tracing/contrib/action_cable/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/action_mailer/integration.rb +6 -2
- data/lib/datadog/tracing/contrib/action_pack/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/action_view/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/active_job/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/active_record/integration.rb +6 -2
- data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +3 -1
- data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +3 -1
- data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +10 -0
- data/lib/datadog/tracing/contrib/active_support/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/auto_instrument.rb +2 -2
- data/lib/datadog/tracing/contrib/aws/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/extensions.rb +15 -3
- data/lib/datadog/tracing/contrib/http/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/httprb/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/kafka/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/mongodb/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/opensearch/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/presto/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/rack/integration.rb +2 -2
- data/lib/datadog/tracing/contrib/rails/framework.rb +2 -2
- data/lib/datadog/tracing/contrib/rails/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/rest_client/integration.rb +3 -0
- data/lib/datadog/tracing/span.rb +12 -4
- data/lib/datadog/tracing/span_event.rb +123 -3
- data/lib/datadog/tracing/span_operation.rb +6 -0
- data/lib/datadog/tracing/transport/serializable_trace.rb +24 -6
- data/lib/datadog/version.rb +1 -1
- metadata +40 -17
- data/lib/datadog/appsec/contrib/sinatra/ext.rb +0 -14
- data/lib/datadog/appsec/processor/context.rb +0 -107
- data/lib/datadog/appsec/reactive/operation.rb +0 -68
- data/lib/datadog/appsec/scope.rb +0 -58
- data/lib/datadog/core/crashtracking/agent_base_url.rb +0 -21
@@ -19,100 +19,38 @@ module Datadog
|
|
19
19
|
[status, headers, body]
|
20
20
|
end
|
21
21
|
|
22
|
-
def to_sinatra_response
|
23
|
-
::Sinatra::Response.new(body, status, headers)
|
24
|
-
end
|
25
|
-
|
26
|
-
def to_action_dispatch_response
|
27
|
-
::ActionDispatch::Response.new(status, headers, body)
|
28
|
-
end
|
29
|
-
|
30
22
|
class << self
|
31
|
-
def
|
32
|
-
|
33
|
-
configured_response = nil
|
34
|
-
actions.each do |type, parameters|
|
35
|
-
# Need to use next to make steep happy :(
|
36
|
-
# I rather use break to stop the execution
|
37
|
-
next if configured_response
|
38
|
-
|
39
|
-
configured_response = case type
|
40
|
-
when 'block_request'
|
41
|
-
block_response(env, parameters)
|
42
|
-
when 'redirect_request'
|
43
|
-
redirect_response(env, parameters)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
configured_response || default_response(env)
|
48
|
-
end
|
49
|
-
|
50
|
-
def graphql_response(gateway_multiplex)
|
51
|
-
multiplex_return = []
|
52
|
-
gateway_multiplex.queries.each do |query|
|
53
|
-
# This method is only called in places where GraphQL-Ruby is already required
|
54
|
-
query_result = ::GraphQL::Query::Result.new(
|
55
|
-
query: query,
|
56
|
-
values: JSON.parse(content('application/json'))
|
57
|
-
)
|
58
|
-
multiplex_return << query_result
|
59
|
-
end
|
23
|
+
def from_interrupt_params(interrupt_params, http_accept_header)
|
24
|
+
return redirect_response(interrupt_params) if interrupt_params['location']
|
60
25
|
|
61
|
-
|
26
|
+
block_response(interrupt_params, http_accept_header)
|
62
27
|
end
|
63
28
|
|
64
29
|
private
|
65
30
|
|
66
|
-
def
|
67
|
-
content_type =
|
68
|
-
|
69
|
-
|
70
|
-
|
31
|
+
def block_response(interrupt_params, http_accept_header)
|
32
|
+
content_type = case interrupt_params['type']
|
33
|
+
when nil, 'auto' then content_type(http_accept_header)
|
34
|
+
else FORMAT_TO_CONTENT_TYPE.fetch(interrupt_params['type'], DEFAULT_CONTENT_TYPE)
|
35
|
+
end
|
71
36
|
|
72
37
|
Response.new(
|
73
|
-
status: 403,
|
38
|
+
status: interrupt_params['status_code']&.to_i || 403,
|
74
39
|
headers: { 'Content-Type' => content_type },
|
75
|
-
body:
|
40
|
+
body: [content(content_type)],
|
76
41
|
)
|
77
42
|
end
|
78
43
|
|
79
|
-
def
|
80
|
-
|
81
|
-
content_type(env)
|
82
|
-
else
|
83
|
-
FORMAT_TO_CONTENT_TYPE[options['type']]
|
84
|
-
end
|
85
|
-
|
86
|
-
body = []
|
87
|
-
body << content(content_type)
|
44
|
+
def redirect_response(interrupt_params)
|
45
|
+
status_code = interrupt_params['status_code'].to_i
|
88
46
|
|
89
47
|
Response.new(
|
90
|
-
status:
|
91
|
-
headers: { '
|
92
|
-
body:
|
48
|
+
status: (status_code >= 300 && status_code < 400 ? status_code : 303),
|
49
|
+
headers: { 'Location' => interrupt_params.fetch('location') },
|
50
|
+
body: [],
|
93
51
|
)
|
94
52
|
end
|
95
53
|
|
96
|
-
def redirect_response(env, options)
|
97
|
-
if options['location'] && !options['location'].empty?
|
98
|
-
content_type = content_type(env)
|
99
|
-
|
100
|
-
headers = {
|
101
|
-
'Content-Type' => content_type,
|
102
|
-
'Location' => options['location']
|
103
|
-
}
|
104
|
-
|
105
|
-
status_code = options['status_code'].to_i
|
106
|
-
Response.new(
|
107
|
-
status: (status_code >= 300 && status_code < 400 ? status_code : 303),
|
108
|
-
headers: headers,
|
109
|
-
body: [],
|
110
|
-
)
|
111
|
-
else
|
112
|
-
default_response(env)
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
54
|
CONTENT_TYPE_TO_FORMAT = {
|
117
55
|
'application/json' => :json,
|
118
56
|
'text/html' => :html,
|
@@ -126,10 +64,10 @@ module Datadog
|
|
126
64
|
|
127
65
|
DEFAULT_CONTENT_TYPE = 'application/json'
|
128
66
|
|
129
|
-
def content_type(
|
130
|
-
return DEFAULT_CONTENT_TYPE
|
67
|
+
def content_type(http_accept_header)
|
68
|
+
return DEFAULT_CONTENT_TYPE if http_accept_header.nil?
|
131
69
|
|
132
|
-
accept_types =
|
70
|
+
accept_types = http_accept_header.split(',').map(&:strip)
|
133
71
|
|
134
72
|
accepted = accept_types.map { |m| Utils::HTTP::MediaRange.new(m) }.sort!.reverse!
|
135
73
|
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module AppSec
|
5
|
+
module SecurityEngine
|
6
|
+
# A namespace for value-objects representing the result of WAF check.
|
7
|
+
module Result
|
8
|
+
# A generic result without indication of its type.
|
9
|
+
class Base
|
10
|
+
attr_reader :events, :actions, :derivatives, :duration_ns, :duration_ext_ns
|
11
|
+
|
12
|
+
def initialize(events:, actions:, derivatives:, timeout:, duration_ns:, duration_ext_ns:)
|
13
|
+
@events = events
|
14
|
+
@actions = actions
|
15
|
+
@derivatives = derivatives
|
16
|
+
|
17
|
+
@timeout = timeout
|
18
|
+
@duration_ns = duration_ns
|
19
|
+
@duration_ext_ns = duration_ext_ns
|
20
|
+
end
|
21
|
+
|
22
|
+
def timeout?
|
23
|
+
!!@timeout
|
24
|
+
end
|
25
|
+
|
26
|
+
def match?
|
27
|
+
raise NotImplementedError
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# A result that indicates a security rule match
|
32
|
+
class Match < Base
|
33
|
+
def match?
|
34
|
+
true
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# A result that indicates a successful security rules check without a match
|
39
|
+
class Ok < Base
|
40
|
+
def match?
|
41
|
+
false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# A result that indicates an internal security library error
|
46
|
+
class Error
|
47
|
+
attr_reader :events, :actions, :derivatives, :duration_ns, :duration_ext_ns
|
48
|
+
|
49
|
+
def initialize(duration_ext_ns:)
|
50
|
+
@events = []
|
51
|
+
@actions = @derivatives = {}
|
52
|
+
@duration_ns = 0
|
53
|
+
@duration_ext_ns = duration_ext_ns
|
54
|
+
end
|
55
|
+
|
56
|
+
def timeout?
|
57
|
+
false
|
58
|
+
end
|
59
|
+
|
60
|
+
def match?
|
61
|
+
false
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'result'
|
4
|
+
|
5
|
+
module Datadog
|
6
|
+
module AppSec
|
7
|
+
module SecurityEngine
|
8
|
+
# A class that check input via security engine (WAF) and respond with result.
|
9
|
+
class Runner
|
10
|
+
SUCCESSFUL_EXECUTION_CODES = [:ok, :match].freeze
|
11
|
+
|
12
|
+
def initialize(handle, telemetry:)
|
13
|
+
@mutex = Mutex.new
|
14
|
+
@context = WAF::Context.new(handle)
|
15
|
+
@telemetry = telemetry
|
16
|
+
|
17
|
+
@debug_tag = "libddwaf:#{WAF::VERSION::STRING} method:ddwaf_run"
|
18
|
+
end
|
19
|
+
|
20
|
+
def run(persistent_data, ephemeral_data, timeout = WAF::LibDDWAF::DDWAF_RUN_TIMEOUT)
|
21
|
+
@mutex.lock
|
22
|
+
|
23
|
+
start_ns = Core::Utils::Time.get_time(:nanosecond)
|
24
|
+
persistent_data.reject! do |_, v|
|
25
|
+
next false if v.is_a?(TrueClass) || v.is_a?(FalseClass)
|
26
|
+
|
27
|
+
v.nil? ? true : v.empty?
|
28
|
+
end
|
29
|
+
|
30
|
+
ephemeral_data.reject! do |_, v|
|
31
|
+
next false if v.is_a?(TrueClass) || v.is_a?(FalseClass)
|
32
|
+
|
33
|
+
v.nil? ? true : v.empty?
|
34
|
+
end
|
35
|
+
|
36
|
+
_code, result = try_run(persistent_data, ephemeral_data, timeout)
|
37
|
+
stop_ns = Core::Utils::Time.get_time(:nanosecond)
|
38
|
+
|
39
|
+
report_execution(result)
|
40
|
+
|
41
|
+
unless SUCCESSFUL_EXECUTION_CODES.include?(result.status)
|
42
|
+
return Result::Error.new(duration_ext_ns: stop_ns - start_ns)
|
43
|
+
end
|
44
|
+
|
45
|
+
klass = result.status == :match ? Result::Match : Result::Ok
|
46
|
+
klass.new(
|
47
|
+
events: result.events,
|
48
|
+
actions: result.actions,
|
49
|
+
derivatives: result.derivatives,
|
50
|
+
timeout: result.timeout,
|
51
|
+
duration_ns: result.total_runtime,
|
52
|
+
duration_ext_ns: (stop_ns - start_ns)
|
53
|
+
)
|
54
|
+
ensure
|
55
|
+
@mutex.unlock
|
56
|
+
end
|
57
|
+
|
58
|
+
def finalize
|
59
|
+
@context.finalize
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def try_run(persistent_data, ephemeral_data, timeout)
|
65
|
+
@context.run(persistent_data, ephemeral_data, timeout)
|
66
|
+
rescue WAF::LibDDWAF::Error => e
|
67
|
+
Datadog.logger.debug { "#{@debug_tag} execution error: #{e} backtrace: #{e.backtrace&.first(3)}" }
|
68
|
+
@telemetry.report(e, description: 'libddwaf-rb internal low-level error')
|
69
|
+
|
70
|
+
[:err_internal, WAF::Result.new(:err_internal, [], 0, false, [], [])]
|
71
|
+
end
|
72
|
+
|
73
|
+
def report_execution(result)
|
74
|
+
Datadog.logger.debug { "#{@debug_tag} execution timed out: #{result.inspect}" } if result.timeout
|
75
|
+
|
76
|
+
if SUCCESSFUL_EXECUTION_CODES.include?(result.status)
|
77
|
+
Datadog.logger.debug { "#{@debug_tag} execution result: #{result.inspect}" }
|
78
|
+
else
|
79
|
+
message = "#{@debug_tag} execution error: #{result.status.inspect}"
|
80
|
+
|
81
|
+
Datadog.logger.debug { message }
|
82
|
+
@telemetry.error(message)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/datadog/appsec.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require_relative 'appsec/configuration'
|
4
4
|
require_relative 'appsec/extensions'
|
5
|
-
require_relative 'appsec/
|
5
|
+
require_relative 'appsec/context'
|
6
6
|
require_relative 'appsec/ext'
|
7
7
|
require_relative 'appsec/utils'
|
8
8
|
|
@@ -14,19 +14,24 @@ module Datadog
|
|
14
14
|
Datadog.configuration.appsec.enabled
|
15
15
|
end
|
16
16
|
|
17
|
-
def
|
18
|
-
Datadog
|
17
|
+
def rasp_enabled?
|
18
|
+
Datadog.configuration.appsec.rasp_enabled
|
19
19
|
end
|
20
20
|
|
21
|
-
def
|
22
|
-
|
21
|
+
def active_context
|
22
|
+
Datadog::AppSec::Context.active
|
23
|
+
end
|
24
|
+
|
25
|
+
def telemetry
|
26
|
+
components.appsec&.telemetry
|
27
|
+
end
|
23
28
|
|
24
|
-
|
29
|
+
def processor
|
30
|
+
components.appsec&.processor
|
25
31
|
end
|
26
32
|
|
27
33
|
def reconfigure(ruleset:, telemetry:)
|
28
34
|
appsec_component = components.appsec
|
29
|
-
|
30
35
|
return unless appsec_component
|
31
36
|
|
32
37
|
appsec_component.reconfigure(ruleset: ruleset, telemetry: telemetry)
|
@@ -34,12 +39,16 @@ module Datadog
|
|
34
39
|
|
35
40
|
def reconfigure_lock(&block)
|
36
41
|
appsec_component = components.appsec
|
37
|
-
|
38
42
|
return unless appsec_component
|
39
43
|
|
40
44
|
appsec_component.reconfigure_lock(&block)
|
41
45
|
end
|
42
46
|
|
47
|
+
def api_security_enabled?
|
48
|
+
Datadog.configuration.appsec.api_security.enabled &&
|
49
|
+
Datadog.configuration.appsec.api_security.sample_rate.sample?
|
50
|
+
end
|
51
|
+
|
43
52
|
private
|
44
53
|
|
45
54
|
def components
|
@@ -6,6 +6,9 @@
|
|
6
6
|
require_relative '../datadog'
|
7
7
|
require_relative 'tracing/contrib/auto_instrument'
|
8
8
|
|
9
|
+
# DI is not loaded on Ruby 2.5 and JRuby
|
10
|
+
Datadog::DI::Contrib.load_now_or_later if defined?(Datadog::DI::Contrib)
|
11
|
+
|
9
12
|
Datadog::Profiling.start_if_enabled
|
10
13
|
|
11
14
|
module Datadog
|
@@ -19,21 +19,49 @@ module Datadog
|
|
19
19
|
# Whenever there is a conflict (different configurations are provided in different orders), it MUST warn the users
|
20
20
|
# about it and pick a value based on the following priority: code > environment variable > defaults.
|
21
21
|
class AgentSettingsResolver
|
22
|
-
|
23
|
-
|
24
|
-
:ssl,
|
25
|
-
|
26
|
-
:port,
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
22
|
+
# Immutable container for the resulting settings
|
23
|
+
class AgentSettings
|
24
|
+
attr_reader :adapter, :ssl, :hostname, :port, :uds_path, :timeout_seconds
|
25
|
+
|
26
|
+
def initialize(adapter: nil, ssl: nil, hostname: nil, port: nil, uds_path: nil, timeout_seconds: nil)
|
27
|
+
@adapter = adapter
|
28
|
+
@ssl = ssl
|
29
|
+
@hostname = hostname
|
30
|
+
@port = port
|
31
|
+
@uds_path = uds_path
|
32
|
+
@timeout_seconds = timeout_seconds
|
33
33
|
freeze
|
34
34
|
end
|
35
|
+
|
36
|
+
def url
|
37
|
+
case adapter
|
38
|
+
when Datadog::Core::Configuration::Ext::Agent::HTTP::ADAPTER
|
39
|
+
hostname = self.hostname
|
40
|
+
hostname = "[#{hostname}]" if hostname =~ IPV6_REGEXP
|
41
|
+
"#{ssl ? 'https' : 'http'}://#{hostname}:#{port}/"
|
42
|
+
when Datadog::Core::Configuration::Ext::Agent::UnixSocket::ADAPTER
|
43
|
+
"unix://#{uds_path}"
|
44
|
+
else
|
45
|
+
raise ArgumentError, "Unexpected adapter: #{adapter}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def ==(other)
|
50
|
+
self.class == other.class &&
|
51
|
+
adapter == other.adapter &&
|
52
|
+
ssl == other.ssl &&
|
53
|
+
hostname == other.hostname &&
|
54
|
+
port == other.port &&
|
55
|
+
uds_path == other.uds_path &&
|
56
|
+
timeout_seconds == other.timeout_seconds
|
57
|
+
end
|
35
58
|
end
|
36
59
|
|
60
|
+
# IPv6 regular expression from
|
61
|
+
# https://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses
|
62
|
+
# Does not match IPv4 addresses.
|
63
|
+
IPV6_REGEXP = /\A(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\z)/.freeze # rubocop:disable Layout/LineLength
|
64
|
+
|
37
65
|
def self.call(settings, logger: Datadog.logger)
|
38
66
|
new(settings, logger: logger).send(:call)
|
39
67
|
end
|
@@ -105,14 +105,16 @@ module Datadog
|
|
105
105
|
@profiler, profiler_logger_extra = Datadog::Profiling::Component.build_profiler_component(
|
106
106
|
settings: settings,
|
107
107
|
agent_settings: agent_settings,
|
108
|
-
optional_tracer: @tracer
|
108
|
+
optional_tracer: @tracer,
|
109
|
+
logger: @logger,
|
109
110
|
)
|
110
111
|
@environment_logger_extra.merge!(profiler_logger_extra) if profiler_logger_extra
|
111
112
|
|
112
113
|
@runtime_metrics = self.class.build_runtime_metrics_worker(settings)
|
113
114
|
@health_metrics = self.class.build_health_metrics(settings)
|
114
115
|
@appsec = Datadog::AppSec::Component.build_appsec_component(settings, telemetry: telemetry)
|
115
|
-
@dynamic_instrumentation = Datadog::DI::Component.build(settings, agent_settings, telemetry: telemetry)
|
116
|
+
@dynamic_instrumentation = Datadog::DI::Component.build(settings, agent_settings, @logger, telemetry: telemetry)
|
117
|
+
@environment_logger_extra[:dynamic_instrumentation_enabled] = !!@dynamic_instrumentation
|
116
118
|
|
117
119
|
self.class.configure_tracing(settings)
|
118
120
|
end
|
@@ -236,7 +236,7 @@ module Datadog
|
|
236
236
|
rescue ThreadError => e
|
237
237
|
logger_without_components.error(
|
238
238
|
'Detected deadlock during datadog initialization. ' \
|
239
|
-
'Please report this at https://github.com/
|
239
|
+
'Please report this at https://github.com/datadog/dd-trace-rb/blob/master/CONTRIBUTING.md#found-a-bug' \
|
240
240
|
"\n\tSource:\n\t#{Array(e.backtrace).join("\n\t")}"
|
241
241
|
)
|
242
242
|
nil
|
@@ -3,7 +3,6 @@
|
|
3
3
|
require 'libdatadog'
|
4
4
|
|
5
5
|
require_relative 'tag_builder'
|
6
|
-
require_relative 'agent_base_url'
|
7
6
|
require_relative '../utils/only_once'
|
8
7
|
require_relative '../utils/at_fork_monkey_patch'
|
9
8
|
|
@@ -31,8 +30,7 @@ module Datadog
|
|
31
30
|
|
32
31
|
def self.build(settings, agent_settings, logger:)
|
33
32
|
tags = TagBuilder.call(settings)
|
34
|
-
agent_base_url =
|
35
|
-
logger.warn('Missing agent base URL; cannot enable crash tracking') unless agent_base_url
|
33
|
+
agent_base_url = agent_settings.url
|
36
34
|
|
37
35
|
ld_library_path = ::Libdatadog.ld_library_path
|
38
36
|
logger.warn('Missing ld_library_path; cannot enable crash tracking') unless ld_library_path
|
@@ -29,6 +29,22 @@ module Datadog
|
|
29
29
|
def payload
|
30
30
|
{}
|
31
31
|
end
|
32
|
+
|
33
|
+
# Override equality to allow for deduplication
|
34
|
+
# The basic implementation is to check if the other object is an instance of the same class.
|
35
|
+
# This works for events that have no attributes.
|
36
|
+
# For events with attributes, you should override this method to compare the attributes.
|
37
|
+
def ==(other)
|
38
|
+
other.is_a?(self.class)
|
39
|
+
end
|
40
|
+
|
41
|
+
# @see #==
|
42
|
+
alias eql? ==
|
43
|
+
|
44
|
+
# @see #==
|
45
|
+
def hash
|
46
|
+
self.class.hash
|
47
|
+
end
|
32
48
|
end
|
33
49
|
|
34
50
|
# Telemetry class for the 'app-started' event
|
@@ -263,6 +279,8 @@ module Datadog
|
|
263
279
|
|
264
280
|
# Telemetry class for the 'app-client-configuration-change' event
|
265
281
|
class AppClientConfigurationChange < Base
|
282
|
+
attr_reader :changes, :origin
|
283
|
+
|
266
284
|
def type
|
267
285
|
'app-client-configuration-change'
|
268
286
|
end
|
@@ -301,6 +319,16 @@ module Datadog
|
|
301
319
|
|
302
320
|
res
|
303
321
|
end
|
322
|
+
|
323
|
+
def ==(other)
|
324
|
+
other.is_a?(AppClientConfigurationChange) && other.changes == @changes && other.origin == @origin
|
325
|
+
end
|
326
|
+
|
327
|
+
alias eql? ==
|
328
|
+
|
329
|
+
def hash
|
330
|
+
[self.class, @changes, @origin].hash
|
331
|
+
end
|
304
332
|
end
|
305
333
|
|
306
334
|
# Telemetry class for the 'app-heartbeat' event
|
@@ -319,6 +347,8 @@ module Datadog
|
|
319
347
|
|
320
348
|
# Telemetry class for the 'generate-metrics' event
|
321
349
|
class GenerateMetrics < Base
|
350
|
+
attr_reader :namespace, :metric_series
|
351
|
+
|
322
352
|
def type
|
323
353
|
'generate-metrics'
|
324
354
|
end
|
@@ -335,24 +365,54 @@ module Datadog
|
|
335
365
|
series: @metric_series.map(&:to_h)
|
336
366
|
}
|
337
367
|
end
|
368
|
+
|
369
|
+
def ==(other)
|
370
|
+
other.is_a?(GenerateMetrics) && other.namespace == @namespace && other.metric_series == @metric_series
|
371
|
+
end
|
372
|
+
|
373
|
+
alias eql? ==
|
374
|
+
|
375
|
+
def hash
|
376
|
+
[self.class, @namespace, @metric_series].hash
|
377
|
+
end
|
338
378
|
end
|
339
379
|
|
340
|
-
# Telemetry class for the 'logs' event
|
380
|
+
# Telemetry class for the 'logs' event.
|
381
|
+
# Logs with the same content are deduplicated at flush time.
|
341
382
|
class Log < Base
|
342
383
|
LEVELS = {
|
343
384
|
error: 'ERROR',
|
344
385
|
warn: 'WARN',
|
345
386
|
}.freeze
|
346
387
|
|
388
|
+
LEVELS_STRING = LEVELS.values.freeze
|
389
|
+
|
390
|
+
attr_reader :message, :level, :stack_trace, :count
|
391
|
+
|
347
392
|
def type
|
348
393
|
'logs'
|
349
394
|
end
|
350
395
|
|
351
|
-
|
396
|
+
# @param message [String] the log message
|
397
|
+
# @param level [Symbol, String] the log level. Either :error, :warn, 'ERROR', or 'WARN'.
|
398
|
+
# @param stack_trace [String, nil] the stack trace
|
399
|
+
# @param count [Integer] the number of times the log was emitted. Used for deduplication.
|
400
|
+
def initialize(message:, level:, stack_trace: nil, count: 1)
|
352
401
|
super()
|
353
402
|
@message = message
|
354
403
|
@stack_trace = stack_trace
|
355
|
-
|
404
|
+
|
405
|
+
if level.is_a?(String) && LEVELS_STRING.include?(level)
|
406
|
+
# String level is used during object copy for deduplication
|
407
|
+
@level = level
|
408
|
+
elsif level.is_a?(Symbol)
|
409
|
+
# Symbol level is used by the regular log emitter user
|
410
|
+
@level = LEVELS.fetch(level) { |k| raise ArgumentError, "Invalid log level :#{k}" }
|
411
|
+
else
|
412
|
+
raise ArgumentError, "Invalid log level #{level}"
|
413
|
+
end
|
414
|
+
|
415
|
+
@count = count
|
356
416
|
end
|
357
417
|
|
358
418
|
def payload
|
@@ -362,10 +422,24 @@ module Datadog
|
|
362
422
|
message: @message,
|
363
423
|
level: @level,
|
364
424
|
stack_trace: @stack_trace,
|
425
|
+
count: @count,
|
365
426
|
}.compact
|
366
427
|
]
|
367
428
|
}
|
368
429
|
end
|
430
|
+
|
431
|
+
# override equality to allow for deduplication
|
432
|
+
def ==(other)
|
433
|
+
other.is_a?(Log) &&
|
434
|
+
other.message == @message &&
|
435
|
+
other.level == @level && other.stack_trace == @stack_trace && other.count == @count
|
436
|
+
end
|
437
|
+
|
438
|
+
alias eql? ==
|
439
|
+
|
440
|
+
def hash
|
441
|
+
[self.class, @message, @level, @stack_trace, @count].hash
|
442
|
+
end
|
369
443
|
end
|
370
444
|
|
371
445
|
# Telemetry class for the 'distributions' event
|
@@ -395,6 +469,16 @@ module Datadog
|
|
395
469
|
}
|
396
470
|
end
|
397
471
|
end
|
472
|
+
|
473
|
+
def ==(other)
|
474
|
+
other.is_a?(MessageBatch) && other.events == @events
|
475
|
+
end
|
476
|
+
|
477
|
+
alias eql? ==
|
478
|
+
|
479
|
+
def hash
|
480
|
+
[self.class, @events].hash
|
481
|
+
end
|
398
482
|
end
|
399
483
|
end
|
400
484
|
end
|
@@ -41,7 +41,7 @@ module Datadog
|
|
41
41
|
else
|
42
42
|
'REDACTED'
|
43
43
|
end
|
44
|
-
end.join(
|
44
|
+
end.join("\n")
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
@@ -49,7 +49,7 @@ module Datadog
|
|
49
49
|
# Annoymous exceptions to be logged as <Class:0x00007f8b1c0b3b40>
|
50
50
|
message = +''
|
51
51
|
message << (exception.class.name || exception.class.inspect)
|
52
|
-
message << ':' << description if description
|
52
|
+
message << ': ' << description if description
|
53
53
|
|
54
54
|
event = Event::Log.new(
|
55
55
|
message: message,
|