datadog 2.17.0 → 2.18.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 +44 -1
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +12 -46
- data/ext/datadog_profiling_native_extension/collectors_stack.c +227 -49
- data/ext/datadog_profiling_native_extension/collectors_stack.h +19 -3
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +63 -12
- data/ext/datadog_profiling_native_extension/collectors_thread_context.h +1 -0
- data/ext/datadog_profiling_native_extension/extconf.rb +7 -0
- data/ext/datadog_profiling_native_extension/heap_recorder.c +239 -363
- data/ext/datadog_profiling_native_extension/heap_recorder.h +4 -6
- data/ext/datadog_profiling_native_extension/libdatadog_helpers.c +22 -0
- data/ext/datadog_profiling_native_extension/libdatadog_helpers.h +8 -5
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +1 -0
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +6 -3
- data/ext/datadog_profiling_native_extension/ruby_helpers.c +1 -13
- data/ext/datadog_profiling_native_extension/ruby_helpers.h +2 -10
- data/ext/datadog_profiling_native_extension/stack_recorder.c +154 -57
- data/ext/libdatadog_api/extconf.rb +2 -2
- data/ext/libdatadog_api/library_config.c +54 -12
- data/ext/libdatadog_api/library_config.h +6 -0
- data/ext/libdatadog_api/process_discovery.c +2 -7
- data/ext/libdatadog_extconf_helpers.rb +1 -1
- data/lib/datadog/appsec/api_security/lru_cache.rb +9 -2
- data/lib/datadog/appsec/api_security/route_extractor.rb +65 -0
- data/lib/datadog/appsec/api_security/sampler.rb +59 -0
- data/lib/datadog/appsec/api_security.rb +14 -0
- data/lib/datadog/appsec/assets/waf_rules/recommended.json +257 -85
- data/lib/datadog/appsec/assets/waf_rules/strict.json +10 -78
- data/lib/datadog/appsec/component.rb +30 -54
- data/lib/datadog/appsec/configuration/settings.rb +60 -2
- data/lib/datadog/appsec/context.rb +6 -6
- data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +1 -1
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +27 -16
- data/lib/datadog/appsec/processor/rule_loader.rb +5 -6
- data/lib/datadog/appsec/remote.rb +15 -55
- data/lib/datadog/appsec/security_engine/engine.rb +194 -0
- data/lib/datadog/appsec/security_engine/runner.rb +10 -11
- data/lib/datadog/appsec.rb +4 -7
- data/lib/datadog/core/configuration/agent_settings.rb +52 -0
- data/lib/datadog/core/configuration/agent_settings_resolver.rb +1 -43
- data/lib/datadog/core/configuration/components.rb +2 -4
- data/lib/datadog/core/configuration/option.rb +9 -9
- data/lib/datadog/core/configuration/settings.rb +22 -10
- data/lib/datadog/core/configuration/stable_config.rb +1 -2
- data/lib/datadog/core/crashtracking/tag_builder.rb +4 -22
- data/lib/datadog/core/process_discovery/tracer_memfd.rb +15 -0
- data/lib/datadog/core/process_discovery.rb +5 -1
- data/lib/datadog/core/remote/configuration/repository.rb +12 -0
- data/lib/datadog/core/tag_builder.rb +56 -0
- data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +1 -0
- data/lib/datadog/core/telemetry/event/app_started.rb +129 -39
- data/lib/datadog/core/telemetry/logger.rb +5 -4
- data/lib/datadog/core/telemetry/logging.rb +11 -5
- data/lib/datadog/core/transport/http/adapters/net.rb +17 -2
- data/lib/datadog/core/transport/http/builder.rb +2 -2
- data/lib/datadog/core/transport/http/env.rb +8 -0
- data/lib/datadog/core/utils.rb +7 -0
- data/lib/datadog/di/instrumenter.rb +52 -2
- data/lib/datadog/di/probe_notification_builder.rb +31 -41
- data/lib/datadog/di/probe_notifier_worker.rb +9 -1
- data/lib/datadog/di/serializer.rb +6 -2
- data/lib/datadog/di/transport/http/input.rb +10 -0
- data/lib/datadog/di/transport/input.rb +10 -2
- data/lib/datadog/profiling/collectors/code_provenance.rb +17 -8
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +4 -0
- data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -0
- data/lib/datadog/profiling/collectors/thread_context.rb +16 -1
- data/lib/datadog/profiling/component.rb +7 -9
- data/lib/datadog/profiling/ext.rb +0 -12
- data/lib/datadog/profiling/http_transport.rb +2 -2
- data/lib/datadog/profiling/profiler.rb +2 -0
- data/lib/datadog/profiling/scheduler.rb +2 -1
- data/lib/datadog/profiling/stack_recorder.rb +5 -5
- data/lib/datadog/profiling/tag_builder.rb +5 -37
- data/lib/datadog/profiling/tasks/setup.rb +2 -0
- data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +15 -0
- data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +19 -12
- data/lib/datadog/tracing/contrib/action_pack/ext.rb +2 -0
- data/lib/datadog/tracing/contrib/lograge/patcher.rb +4 -2
- data/lib/datadog/tracing/contrib/sidekiq/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +5 -2
- data/lib/datadog/tracing/sync_writer.rb +1 -1
- data/lib/datadog/tracing/trace_operation.rb +12 -4
- data/lib/datadog/tracing/tracer.rb +6 -2
- data/lib/datadog/version.rb +1 -1
- metadata +12 -10
- data/lib/datadog/appsec/assets/waf_rules/processors.json +0 -321
- data/lib/datadog/appsec/assets/waf_rules/scanners.json +0 -1023
- data/lib/datadog/appsec/processor/rule_merger.rb +0 -171
- data/lib/datadog/appsec/processor.rb +0 -107
@@ -82,7 +82,11 @@ module Datadog
|
|
82
82
|
# between positional and keyword arguments. We convert positional
|
83
83
|
# arguments to keyword arguments ("arg1", "arg2", ...) and ensure
|
84
84
|
# the positional arguments are listed first.
|
85
|
-
|
85
|
+
#
|
86
|
+
# Instance variables are technically a hash just like kwargs,
|
87
|
+
# we take them as a separate parameter to avoid a hash merge
|
88
|
+
# in upstream code.
|
89
|
+
def serialize_args(args, kwargs, instance_vars,
|
86
90
|
depth: settings.dynamic_instrumentation.max_capture_depth,
|
87
91
|
attribute_count: settings.dynamic_instrumentation.max_capture_attribute_count)
|
88
92
|
counter = 0
|
@@ -91,7 +95,7 @@ module Datadog
|
|
91
95
|
# Conversion to symbol is needed here to put args ahead of
|
92
96
|
# kwargs when they are merged below.
|
93
97
|
c[:"arg#{counter}"] = value
|
94
|
-
end.update(kwargs)
|
98
|
+
end.update(kwargs).update(instance_vars)
|
95
99
|
serialize_vars(combined, depth: depth, attribute_count: attribute_count)
|
96
100
|
end
|
97
101
|
|
@@ -53,6 +53,16 @@ module Datadog
|
|
53
53
|
# Encode body & type
|
54
54
|
env.headers[HEADER_CONTENT_TYPE] = encoder.content_type
|
55
55
|
env.body = env.request.parcel.data
|
56
|
+
env.query = {
|
57
|
+
# DEV: In theory we could serialize the tags here
|
58
|
+
# rather than requiring them to be pre-serialized.
|
59
|
+
# In practice the tags should be relatively static
|
60
|
+
# (they would change when process forks, and hostname
|
61
|
+
# could change at any time but probably we should ignore
|
62
|
+
# those changes), therefore serializing the tags
|
63
|
+
# every time would be wasteful.
|
64
|
+
ddtags: env.request.serialized_tags,
|
65
|
+
}
|
56
66
|
|
57
67
|
super
|
58
68
|
end
|
@@ -12,6 +12,13 @@ module Datadog
|
|
12
12
|
end
|
13
13
|
|
14
14
|
class Request < Datadog::Core::Transport::Request
|
15
|
+
attr_reader :serialized_tags
|
16
|
+
|
17
|
+
def initialize(parcel, serialized_tags)
|
18
|
+
super(parcel)
|
19
|
+
|
20
|
+
@serialized_tags = serialized_tags
|
21
|
+
end
|
15
22
|
end
|
16
23
|
|
17
24
|
class Transport
|
@@ -28,10 +35,11 @@ module Datadog
|
|
28
35
|
@apis[HTTP::API::INPUT]
|
29
36
|
end
|
30
37
|
|
31
|
-
def send_input(payload)
|
38
|
+
def send_input(payload, tags)
|
32
39
|
json = JSON.dump(payload)
|
33
40
|
parcel = EncodedParcel.new(json)
|
34
|
-
|
41
|
+
serialized_tags = Core::TagBuilder.serialize_tags(tags)
|
42
|
+
request = Request.new(parcel, serialized_tags)
|
35
43
|
|
36
44
|
response = @client.send_input_payload(request)
|
37
45
|
unless response.ok?
|
@@ -14,7 +14,10 @@ module Datadog
|
|
14
14
|
#
|
15
15
|
# This class acts both as a collector (collecting data) as well as a recorder (records/serializes it)
|
16
16
|
class CodeProvenance
|
17
|
-
def initialize(
|
17
|
+
def initialize(
|
18
|
+
standard_library_path: RbConfig::CONFIG.fetch("rubylibdir"),
|
19
|
+
ruby_native_filename: Datadog::Profiling::Collectors::Stack._native_ruby_native_filename
|
20
|
+
)
|
18
21
|
@libraries_by_name = {}
|
19
22
|
@libraries_by_path = {}
|
20
23
|
@seen_files = Set.new
|
@@ -26,6 +29,7 @@ module Datadog
|
|
26
29
|
name: "stdlib",
|
27
30
|
version: RUBY_VERSION,
|
28
31
|
path: standard_library_path,
|
32
|
+
extra_path: ruby_native_filename,
|
29
33
|
)
|
30
34
|
)
|
31
35
|
end
|
@@ -37,10 +41,6 @@ module Datadog
|
|
37
41
|
self
|
38
42
|
end
|
39
43
|
|
40
|
-
def generate
|
41
|
-
seen_libraries
|
42
|
-
end
|
43
|
-
|
44
44
|
def generate_json
|
45
45
|
JSON.generate(v1: seen_libraries.to_a)
|
46
46
|
end
|
@@ -79,7 +79,15 @@ module Datadog
|
|
79
79
|
loaded_specs.each do |spec|
|
80
80
|
next if libraries_by_name.key?(spec.name)
|
81
81
|
|
82
|
-
record_library(
|
82
|
+
record_library(
|
83
|
+
Library.new(
|
84
|
+
kind: "library",
|
85
|
+
name: spec.name,
|
86
|
+
version: spec.version,
|
87
|
+
path: spec.gem_dir,
|
88
|
+
extra_path: (spec.extension_dir if spec.extensions.any?),
|
89
|
+
)
|
90
|
+
)
|
83
91
|
recorded_library = true
|
84
92
|
end
|
85
93
|
|
@@ -110,11 +118,12 @@ module Datadog
|
|
110
118
|
class Library
|
111
119
|
attr_reader :kind, :name, :version
|
112
120
|
|
113
|
-
def initialize(kind:, name:, version:, path:)
|
121
|
+
def initialize(kind:, name:, version:, path:, extra_path: nil)
|
122
|
+
extra_path = nil if extra_path&.empty?
|
114
123
|
@kind = kind.freeze
|
115
124
|
@name = name.dup.freeze
|
116
125
|
@version = version.to_s.dup.freeze
|
117
|
-
@paths = [path.dup.freeze].freeze
|
126
|
+
@paths = [path.dup.freeze, extra_path.dup.freeze].compact.freeze
|
118
127
|
freeze
|
119
128
|
end
|
120
129
|
|
@@ -33,6 +33,9 @@ module Datadog
|
|
33
33
|
Datadog.logger.warn(
|
34
34
|
"Profiling dynamic sampling rate disabled. This should only be used for testing, and will increase overhead!"
|
35
35
|
)
|
36
|
+
Datadog::Core::Telemetry::Logger.error(
|
37
|
+
"Profiling dynamic sampling rate disabled. This should only be used for testing, and will increase overhead!"
|
38
|
+
)
|
36
39
|
end
|
37
40
|
|
38
41
|
self.class._native_initialize(
|
@@ -77,6 +80,7 @@ module Datadog
|
|
77
80
|
"Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
|
78
81
|
)
|
79
82
|
on_failure_proc&.call
|
83
|
+
Datadog::Core::Telemetry::Logger.report(e, description: "CpuAndWallTimeWorker thread error", pii_safe: true)
|
80
84
|
end
|
81
85
|
@worker_thread.name = self.class.name # Repeated from above to make sure thread gets named asap
|
82
86
|
@worker_thread.thread_variable_set(:fork_safe, true)
|
@@ -41,6 +41,7 @@ module Datadog
|
|
41
41
|
"IdleSamplingHelper thread error. " \
|
42
42
|
"Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
|
43
43
|
)
|
44
|
+
Datadog::Core::Telemetry::Logger.report(e, description: "IdleSamplingHelper thread error", pii_safe: true)
|
44
45
|
end
|
45
46
|
@worker_thread.name = self.class.name # Repeated from above to make sure thread gets named asap
|
46
47
|
@worker_thread.thread_variable_set(:fork_safe, true)
|
@@ -21,7 +21,8 @@ module Datadog
|
|
21
21
|
endpoint_collection_enabled:,
|
22
22
|
timeline_enabled:,
|
23
23
|
waiting_for_gvl_threshold_ns:,
|
24
|
-
otel_context_enabled
|
24
|
+
otel_context_enabled:,
|
25
|
+
native_filenames_enabled:
|
25
26
|
)
|
26
27
|
tracer_context_key = safely_extract_context_key_from(tracer)
|
27
28
|
self.class._native_initialize(
|
@@ -33,6 +34,7 @@ module Datadog
|
|
33
34
|
timeline_enabled: timeline_enabled,
|
34
35
|
waiting_for_gvl_threshold_ns: waiting_for_gvl_threshold_ns,
|
35
36
|
otel_context_enabled: otel_context_enabled,
|
37
|
+
native_filenames_enabled: validate_native_filenames(native_filenames_enabled),
|
36
38
|
)
|
37
39
|
end
|
38
40
|
|
@@ -44,6 +46,7 @@ module Datadog
|
|
44
46
|
timeline_enabled: false,
|
45
47
|
waiting_for_gvl_threshold_ns: 10_000_000,
|
46
48
|
otel_context_enabled: false,
|
49
|
+
native_filenames_enabled: true,
|
47
50
|
**options
|
48
51
|
)
|
49
52
|
new(
|
@@ -54,6 +57,7 @@ module Datadog
|
|
54
57
|
timeline_enabled: timeline_enabled,
|
55
58
|
waiting_for_gvl_threshold_ns: waiting_for_gvl_threshold_ns,
|
56
59
|
otel_context_enabled: otel_context_enabled,
|
60
|
+
native_filenames_enabled: native_filenames_enabled,
|
57
61
|
**options,
|
58
62
|
)
|
59
63
|
end
|
@@ -81,6 +85,17 @@ module Datadog
|
|
81
85
|
context = provider.instance_variable_get(:@context)
|
82
86
|
context&.instance_variable_get(:@key)
|
83
87
|
end
|
88
|
+
|
89
|
+
def validate_native_filenames(native_filenames_enabled)
|
90
|
+
if native_filenames_enabled && !Datadog::Profiling::Collectors::Stack._native_filenames_available?
|
91
|
+
Datadog.logger.debug(
|
92
|
+
"Native filenames are enabled, but the required dladdr API was not available. Disabling native filenames."
|
93
|
+
)
|
94
|
+
false
|
95
|
+
else
|
96
|
+
native_filenames_enabled
|
97
|
+
end
|
98
|
+
end
|
84
99
|
end
|
85
100
|
end
|
86
101
|
end
|
@@ -96,6 +96,7 @@ module Datadog
|
|
96
96
|
timeline_enabled: timeline_enabled,
|
97
97
|
waiting_for_gvl_threshold_ns: settings.profiling.advanced.waiting_for_gvl_threshold_ns,
|
98
98
|
otel_context_enabled: settings.profiling.advanced.preview_otel_context_enabled,
|
99
|
+
native_filenames_enabled: settings.profiling.advanced.native_filenames_enabled,
|
99
100
|
)
|
100
101
|
end
|
101
102
|
|
@@ -221,13 +222,14 @@ module Datadog
|
|
221
222
|
end
|
222
223
|
|
223
224
|
unless allocation_profiling_enabled
|
224
|
-
|
225
|
+
logger.warn(
|
226
|
+
"Heap profiling was requested but allocation profiling is not enabled. " \
|
227
|
+
"Heap profiling has been disabled."
|
228
|
+
)
|
229
|
+
return false
|
225
230
|
end
|
226
231
|
|
227
|
-
logger.
|
228
|
-
"Enabled experimental heap profiling: heap_sample_rate=#{heap_sample_rate}. This is experimental, not " \
|
229
|
-
"recommended, and will increase overhead!"
|
230
|
-
)
|
232
|
+
logger.debug("Enabled heap profiling: heap_sample_rate=#{heap_sample_rate}")
|
231
233
|
|
232
234
|
true
|
233
235
|
end
|
@@ -237,10 +239,6 @@ module Datadog
|
|
237
239
|
|
238
240
|
return false unless heap_profiling_enabled && heap_size_profiling_enabled
|
239
241
|
|
240
|
-
logger.warn(
|
241
|
-
"Enabled experimental heap size profiling. This is experimental, not recommended, and will increase overhead!"
|
242
|
-
)
|
243
|
-
|
244
242
|
true
|
245
243
|
end
|
246
244
|
|
@@ -11,19 +11,7 @@ module Datadog
|
|
11
11
|
|
12
12
|
module Transport
|
13
13
|
module HTTP
|
14
|
-
FORM_FIELD_TAG_ENV = "env"
|
15
|
-
FORM_FIELD_TAG_HOST = "host"
|
16
|
-
FORM_FIELD_TAG_LANGUAGE = "language"
|
17
|
-
FORM_FIELD_TAG_PID = "process_id"
|
18
14
|
FORM_FIELD_TAG_PROFILER_VERSION = "profiler_version"
|
19
|
-
FORM_FIELD_TAG_RUNTIME = "runtime"
|
20
|
-
FORM_FIELD_TAG_RUNTIME_ENGINE = "runtime_engine"
|
21
|
-
FORM_FIELD_TAG_RUNTIME_ID = "runtime-id"
|
22
|
-
FORM_FIELD_TAG_RUNTIME_VERSION = "runtime_version"
|
23
|
-
FORM_FIELD_TAG_SERVICE = "service"
|
24
|
-
FORM_FIELD_TAG_VERSION = "version"
|
25
|
-
TAG_GIT_REPOSITORY_URL = "git.repository_url"
|
26
|
-
TAG_GIT_COMMIT_SHA = "git.commit.sha"
|
27
15
|
|
28
16
|
CODE_PROVENANCE_FILENAME = "code-provenance.json"
|
29
17
|
end
|
@@ -37,7 +37,7 @@ module Datadog
|
|
37
37
|
Datadog.logger.debug("Successfully reported profiling data")
|
38
38
|
true
|
39
39
|
else
|
40
|
-
Datadog.logger.
|
40
|
+
Datadog.logger.warn(
|
41
41
|
"Failed to report profiling data (#{config_without_api_key}): " \
|
42
42
|
"server returned unexpected HTTP #{result} status code"
|
43
43
|
)
|
@@ -47,7 +47,7 @@ module Datadog
|
|
47
47
|
false
|
48
48
|
end
|
49
49
|
else
|
50
|
-
Datadog.logger.
|
50
|
+
Datadog.logger.warn("Failed to report profiling data (#{config_without_api_key}): #{result}")
|
51
51
|
Datadog::Core::Telemetry::Logger.error("Failed to report profiling data")
|
52
52
|
false
|
53
53
|
end
|
@@ -50,6 +50,8 @@ module Datadog
|
|
50
50
|
"Detected issue with profiler (#{failed_component} component), stopping profiling. " \
|
51
51
|
"See previous log messages for details."
|
52
52
|
)
|
53
|
+
Datadog::Core::Telemetry::Logger
|
54
|
+
.error("Detected issue with profiler (#{failed_component} component), stopping profiling")
|
53
55
|
|
54
56
|
# We explicitly not stop the crash tracker in this situation, under the assumption that, if a component failed,
|
55
57
|
# we're operating in a degraded state and crash tracking may still be helpful.
|
@@ -68,6 +68,7 @@ module Datadog
|
|
68
68
|
"Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
|
69
69
|
)
|
70
70
|
on_failure_proc&.call
|
71
|
+
Datadog::Core::Telemetry::Logger.report(e, description: "Profiling::Scheduler thread error")
|
71
72
|
raise
|
72
73
|
ensure
|
73
74
|
Datadog.logger.debug("#flush was interrupted or failed before it could complete") if interrupted
|
@@ -133,7 +134,7 @@ module Datadog
|
|
133
134
|
begin
|
134
135
|
transport.export(flush)
|
135
136
|
rescue => e
|
136
|
-
Datadog.logger.
|
137
|
+
Datadog.logger.warn(
|
137
138
|
"Unable to report profile. Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
|
138
139
|
)
|
139
140
|
Datadog::Core::Telemetry::Logger.report(e, description: "Unable to report profile")
|
@@ -23,7 +23,7 @@ module Datadog
|
|
23
23
|
# This isn't something we expect to happen normally, but because it would break the assumptions of the
|
24
24
|
# C-level mutexes (that there is a single serializer thread), we add it here as an extra safeguard against it
|
25
25
|
# accidentally happening.
|
26
|
-
@
|
26
|
+
@no_concurrent_serialize_mutex = Mutex.new
|
27
27
|
|
28
28
|
self.class._native_initialize(
|
29
29
|
self_instance: self,
|
@@ -60,7 +60,7 @@ module Datadog
|
|
60
60
|
end
|
61
61
|
|
62
62
|
def serialize
|
63
|
-
status, result = @
|
63
|
+
status, result = @no_concurrent_serialize_mutex.synchronize { self.class._native_serialize(self) }
|
64
64
|
|
65
65
|
if status == :ok
|
66
66
|
start, finish, encoded_profile, profile_stats = result
|
@@ -71,15 +71,15 @@ module Datadog
|
|
71
71
|
else
|
72
72
|
error_message = result
|
73
73
|
|
74
|
-
Datadog.logger.
|
75
|
-
Datadog::Core::Telemetry::Logger.error("Failed to serialize profiling data")
|
74
|
+
Datadog.logger.warn("Failed to serialize profiling data: #{error_message}")
|
75
|
+
Datadog::Core::Telemetry::Logger.error("Failed to serialize profiling data (#{error_message})")
|
76
76
|
|
77
77
|
nil
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
81
81
|
def serialize!
|
82
|
-
status, result = @
|
82
|
+
status, result = @no_concurrent_serialize_mutex.synchronize { self.class._native_serialize(self) }
|
83
83
|
|
84
84
|
if status == :ok
|
85
85
|
_start, _finish, encoded_profile = result
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative "../core/tag_builder"
|
3
4
|
require_relative "../core/utils"
|
4
|
-
require_relative "../core/environment/git"
|
5
5
|
|
6
6
|
module Datadog
|
7
7
|
module Profiling
|
@@ -11,45 +11,13 @@ module Datadog
|
|
11
11
|
|
12
12
|
def self.call(
|
13
13
|
settings:,
|
14
|
-
# Unified service tagging
|
15
|
-
env: settings.env,
|
16
|
-
service: settings.service,
|
17
|
-
version: settings.version,
|
18
14
|
# Other metadata
|
19
|
-
|
20
|
-
language: Core::Environment::Identity.lang,
|
21
|
-
pid: Process.pid.to_s,
|
22
|
-
profiler_version: Core::Environment::Identity.gem_datadog_version,
|
23
|
-
runtime_engine: Core::Environment::Identity.lang_engine,
|
24
|
-
runtime_id: Core::Environment::Identity.id,
|
25
|
-
runtime_version: Core::Environment::Identity.lang_version,
|
26
|
-
git_repository_url: Core::Environment::Git.git_repository_url,
|
27
|
-
git_commit_sha: Core::Environment::Git.git_commit_sha,
|
28
|
-
# User-provided tags
|
29
|
-
user_tags: settings.tags
|
15
|
+
profiler_version: Core::Environment::Identity.gem_datadog_version
|
30
16
|
)
|
31
|
-
|
32
|
-
# When changing or adding these, make sure they are kept in sync with
|
33
|
-
# https://docs.google.com/spreadsheets/d/1LOGMf4c4Avbtn36uZ2SWvhIGKRPLM1BoWkUP4JYj7hA/ (Datadog internal link)
|
34
|
-
FORM_FIELD_TAG_HOST => host,
|
35
|
-
FORM_FIELD_TAG_LANGUAGE => language,
|
36
|
-
FORM_FIELD_TAG_PID => pid,
|
17
|
+
hash = Core::TagBuilder.tags(settings).merge(
|
37
18
|
FORM_FIELD_TAG_PROFILER_VERSION => profiler_version,
|
38
|
-
|
39
|
-
|
40
|
-
FORM_FIELD_TAG_RUNTIME_ID => runtime_id,
|
41
|
-
FORM_FIELD_TAG_RUNTIME_VERSION => runtime_version,
|
42
|
-
}
|
43
|
-
tags[FORM_FIELD_TAG_ENV] = env if env
|
44
|
-
tags[FORM_FIELD_TAG_SERVICE] = service if service
|
45
|
-
tags[FORM_FIELD_TAG_VERSION] = version if version
|
46
|
-
tags[TAG_GIT_REPOSITORY_URL] = git_repository_url if git_repository_url
|
47
|
-
tags[TAG_GIT_COMMIT_SHA] = git_commit_sha if git_commit_sha
|
48
|
-
|
49
|
-
# Make sure everything is an utf-8 string, to avoid encoding issues in native code/further downstream
|
50
|
-
user_tags.merge(tags).map do |key, value|
|
51
|
-
[Datadog::Core::Utils.utf8_encode(key), Datadog::Core::Utils.utf8_encode(value)]
|
52
|
-
end.to_h
|
19
|
+
)
|
20
|
+
Core::Utils.encode_tags(hash)
|
53
21
|
end
|
54
22
|
end
|
55
23
|
end
|
@@ -19,6 +19,7 @@ module Datadog
|
|
19
19
|
"Profiler extensions unavailable. Cause: #{e.class.name} #{e.message} " \
|
20
20
|
"Location: #{Array(e.backtrace).first}"
|
21
21
|
end
|
22
|
+
Datadog::Core::Telemetry::Logger.report(e, description: "Profiler extensions unavailable")
|
22
23
|
end
|
23
24
|
end
|
24
25
|
|
@@ -33,6 +34,7 @@ module Datadog
|
|
33
34
|
"Error during post-fork hooks. Cause: #{e.class.name} #{e.message} " \
|
34
35
|
"Location: #{Array(e.backtrace).first}"
|
35
36
|
end
|
37
|
+
Datadog::Core::Telemetry::Logger.report(e, description: "Error during post-fork hooks")
|
36
38
|
end
|
37
39
|
end
|
38
40
|
end
|
@@ -68,6 +68,12 @@ module Datadog
|
|
68
68
|
|
69
69
|
span.set_tag(Ext::TAG_ROUTE_ACTION, payload.fetch(:action))
|
70
70
|
span.set_tag(Ext::TAG_ROUTE_CONTROLLER, payload.fetch(:controller))
|
71
|
+
if (runtime = payload[:view_runtime])
|
72
|
+
span.set_tag(Ext::TAG_VIEW_RUNTIME, runtime)
|
73
|
+
end
|
74
|
+
if (runtime = payload[:db_runtime])
|
75
|
+
span.set_tag(Ext::TAG_DB_RUNTIME, runtime)
|
76
|
+
end
|
71
77
|
|
72
78
|
exception = payload[:exception_object]
|
73
79
|
if exception.nil?
|
@@ -118,6 +124,15 @@ module Datadog
|
|
118
124
|
payload[:exception] = [e.class.name, e.message]
|
119
125
|
payload[:exception_object] = e
|
120
126
|
raise e
|
127
|
+
ensure
|
128
|
+
# Database and view runtime are available for controllers
|
129
|
+
# deriving from ActionController::Base.
|
130
|
+
# They are not defined on controllers deriving from
|
131
|
+
# ActionController::Metal, unless
|
132
|
+
# ActionController::Instrumentation is explicitly included
|
133
|
+
# into the controller class.
|
134
|
+
payload[:db_runtime] = db_runtime if respond_to?(:db_runtime)
|
135
|
+
payload[:view_runtime] = view_runtime if respond_to?(:view_runtime)
|
121
136
|
end
|
122
137
|
# rubocop:enable Lint/RescueException
|
123
138
|
ensure
|
@@ -9,9 +9,12 @@ module Datadog
|
|
9
9
|
module ActionDispatch
|
10
10
|
# Instrumentation for ActionDispatch components
|
11
11
|
module Instrumentation
|
12
|
+
SCRIPT_NAME_KEY = 'SCRIPT_NAME'
|
13
|
+
FORMAT_SUFFIX = '(.:format)'
|
14
|
+
|
12
15
|
module_function
|
13
16
|
|
14
|
-
def set_http_route_tags(route_spec,
|
17
|
+
def set_http_route_tags(route_spec, route_path)
|
15
18
|
return unless Tracing.enabled?
|
16
19
|
|
17
20
|
return unless route_spec
|
@@ -19,10 +22,10 @@ module Datadog
|
|
19
22
|
request_trace = Tracing.active_trace
|
20
23
|
return unless request_trace
|
21
24
|
|
22
|
-
request_trace.set_tag(Tracing::Metadata::Ext::HTTP::TAG_ROUTE, route_spec
|
25
|
+
request_trace.set_tag(Tracing::Metadata::Ext::HTTP::TAG_ROUTE, route_spec)
|
23
26
|
|
24
|
-
if
|
25
|
-
request_trace.set_tag(Tracing::Metadata::Ext::HTTP::TAG_ROUTE_PATH,
|
27
|
+
if route_path && !route_path.empty?
|
28
|
+
request_trace.set_tag(Tracing::Metadata::Ext::HTTP::TAG_ROUTE_PATH, route_path)
|
26
29
|
end
|
27
30
|
end
|
28
31
|
|
@@ -40,16 +43,17 @@ module Datadog
|
|
40
43
|
# Instrumentation for ActionDispatch::Journey::Router for Rails versions older than 7.1
|
41
44
|
module Router
|
42
45
|
def find_routes(req)
|
46
|
+
# result is an array of [match, parameters, route] tuples
|
43
47
|
result = super
|
48
|
+
result.each do |_, _, route|
|
49
|
+
next unless Instrumentation.dispatcher_route?(route)
|
44
50
|
|
45
|
-
|
46
|
-
|
51
|
+
http_route = route.path.spec.to_s
|
52
|
+
http_route.delete_suffix!(FORMAT_SUFFIX)
|
47
53
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
break
|
52
|
-
end
|
54
|
+
Instrumentation.set_http_route_tags(http_route, req.env[SCRIPT_NAME_KEY])
|
55
|
+
|
56
|
+
break
|
53
57
|
end
|
54
58
|
|
55
59
|
result
|
@@ -62,7 +66,10 @@ module Datadog
|
|
62
66
|
def find_routes(req)
|
63
67
|
super do |match, parameters, route|
|
64
68
|
if Instrumentation.dispatcher_route?(route)
|
65
|
-
|
69
|
+
http_route = route.path.spec.to_s
|
70
|
+
http_route.delete_suffix!(FORMAT_SUFFIX)
|
71
|
+
|
72
|
+
Instrumentation.set_http_route_tags(http_route, req.env[SCRIPT_NAME_KEY])
|
66
73
|
end
|
67
74
|
|
68
75
|
yield [match, parameters, route]
|
@@ -20,10 +20,12 @@ module Datadog
|
|
20
20
|
|
21
21
|
# patch applies our patch
|
22
22
|
def patch
|
23
|
+
# First check Lograge logger directly for when keep_original_rails_log option is used
|
24
|
+
used_logger = ::Lograge.logger || ::Lograge::LogSubscribers::ActionController.logger
|
25
|
+
|
23
26
|
# ActiveSupport::TaggedLogging is the default Rails logger since Rails 5
|
24
27
|
if defined?(::ActiveSupport::TaggedLogging::Formatter) &&
|
25
|
-
::
|
26
|
-
.logger&.formatter.is_a?(::ActiveSupport::TaggedLogging::Formatter)
|
28
|
+
used_logger&.formatter.is_a?(::ActiveSupport::TaggedLogging::Formatter)
|
27
29
|
Datadog.logger.warn(
|
28
30
|
'Lograge and ActiveSupport::TaggedLogging (the default Rails log formatter) are not compatible: ' \
|
29
31
|
'Lograge does not account for Rails log tags, creating polluted logs and breaking log formatting. ' \
|
@@ -13,6 +13,7 @@ module Datadog
|
|
13
13
|
ENV_ANALYTICS_ENABLED = 'DD_TRACE_SIDEKIQ_ANALYTICS_ENABLED'
|
14
14
|
ENV_ANALYTICS_SAMPLE_RATE = 'DD_TRACE_SIDEKIQ_ANALYTICS_SAMPLE_RATE'
|
15
15
|
SERVICE_NAME = 'sidekiq'
|
16
|
+
SIDEKIQ_8_SECONDS_PER_INTEGER = 0.001 # Sidekiq 8 uses integer epoch milliseconds, rather than epoch floats
|
16
17
|
SPAN_PUSH = 'sidekiq.push'
|
17
18
|
SPAN_JOB = 'sidekiq.job'
|
18
19
|
SPAN_JOB_FETCH = 'sidekiq.job_fetch'
|
@@ -22,7 +22,7 @@ module Datadog
|
|
22
22
|
@quantize = options[:quantize] || configuration[:quantize]
|
23
23
|
end
|
24
24
|
|
25
|
-
def call(worker, job, queue)
|
25
|
+
def call(worker, job, queue) # rubocop:disable Metrics/MethodLength
|
26
26
|
resource = job_resource(job)
|
27
27
|
|
28
28
|
if @distributed_tracing
|
@@ -61,7 +61,10 @@ module Datadog
|
|
61
61
|
span.set_tag(Ext::TAG_JOB_RETRY_COUNT, job['retry_count'])
|
62
62
|
span.set_tag(Ext::TAG_JOB_QUEUE, job['queue'])
|
63
63
|
span.set_tag(Ext::TAG_JOB_WRAPPER, job['class']) if job['wrapped']
|
64
|
-
|
64
|
+
|
65
|
+
enqueued_at = job['enqueued_at']
|
66
|
+
enqueued_at *= Ext::SIDEKIQ_8_SECONDS_PER_INTEGER if enqueued_at.is_a?(Integer)
|
67
|
+
span.set_tag(Ext::TAG_JOB_DELAY, 1000.0 * (Core::Utils::Time.now.utc.to_f - enqueued_at.to_f))
|
65
68
|
|
66
69
|
args = job['args']
|
67
70
|
if args && !args.empty?
|
@@ -25,7 +25,7 @@ module Datadog
|
|
25
25
|
# @param [Datadog::Tracing::Transport::Traces::Transport] transport a custom transport instance.
|
26
26
|
# If provided, overrides `transport_options` and `agent_settings`.
|
27
27
|
# @param [Hash<Symbol,Object>] transport_options options for the default transport instance.
|
28
|
-
# @param [Datadog::Tracing::Configuration::
|
28
|
+
# @param [Datadog::Tracing::Configuration::AgentSettings] agent_settings agent options for
|
29
29
|
# the default transport instance.
|
30
30
|
def initialize(transport: nil, transport_options: {}, agent_settings: nil, logger: Datadog.logger)
|
31
31
|
@logger = logger
|
@@ -79,7 +79,7 @@ module Datadog
|
|
79
79
|
trace_state: nil,
|
80
80
|
trace_state_unknown_fields: nil,
|
81
81
|
remote_parent: false,
|
82
|
-
tracer: nil,
|
82
|
+
tracer: nil, # DEV-3.0: deprecated, remove in 3.0
|
83
83
|
baggage: nil
|
84
84
|
)
|
85
85
|
@logger = logger
|
@@ -106,7 +106,6 @@ module Datadog
|
|
106
106
|
@apm_tracing_enabled = apm_tracing_enabled
|
107
107
|
@trace_state = trace_state
|
108
108
|
@trace_state_unknown_fields = trace_state_unknown_fields
|
109
|
-
@tracer = tracer
|
110
109
|
@baggage = baggage
|
111
110
|
|
112
111
|
# Generic tags
|
@@ -329,7 +328,7 @@ module Datadog
|
|
329
328
|
span_id = @active_span && @active_span.id
|
330
329
|
span_id ||= @parent_span_id unless finished?
|
331
330
|
# sample the trace_operation with the tracer
|
332
|
-
|
331
|
+
events.trace_propagated.publish(self)
|
333
332
|
|
334
333
|
TraceDigest.new(
|
335
334
|
span_id: span_id,
|
@@ -399,12 +398,14 @@ module Datadog
|
|
399
398
|
attr_reader \
|
400
399
|
:span_before_start,
|
401
400
|
:span_finished,
|
402
|
-
:trace_finished
|
401
|
+
:trace_finished,
|
402
|
+
:trace_propagated
|
403
403
|
|
404
404
|
def initialize
|
405
405
|
@span_before_start = SpanBeforeStart.new
|
406
406
|
@span_finished = SpanFinished.new
|
407
407
|
@trace_finished = TraceFinished.new
|
408
|
+
@trace_propagated = TracePropagated.new
|
408
409
|
end
|
409
410
|
|
410
411
|
# Triggered before a span starts.
|
@@ -421,6 +422,13 @@ module Datadog
|
|
421
422
|
end
|
422
423
|
end
|
423
424
|
|
425
|
+
# Triggered when trace is being propagated between applications or contexts
|
426
|
+
class TracePropagated < Tracing::Event
|
427
|
+
def initialize
|
428
|
+
super(:trace_propagated)
|
429
|
+
end
|
430
|
+
end
|
431
|
+
|
424
432
|
# Triggered when the trace finishes, regardless of error.
|
425
433
|
class TraceFinished < Tracing::Event
|
426
434
|
def initialize
|