datadog 2.2.0 → 2.4.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 +87 -2
- data/ext/datadog_profiling_loader/datadog_profiling_loader.c +9 -1
- data/ext/datadog_profiling_loader/extconf.rb +14 -26
- data/ext/datadog_profiling_native_extension/clock_id.h +1 -0
- data/ext/datadog_profiling_native_extension/clock_id_from_pthread.c +1 -2
- data/ext/datadog_profiling_native_extension/clock_id_noop.c +1 -2
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +257 -69
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +53 -28
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h +34 -4
- data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +4 -0
- data/ext/datadog_profiling_native_extension/collectors_stack.c +136 -81
- data/ext/datadog_profiling_native_extension/collectors_stack.h +2 -2
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +661 -48
- data/ext/datadog_profiling_native_extension/collectors_thread_context.h +10 -1
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +83 -0
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +53 -0
- data/ext/datadog_profiling_native_extension/extconf.rb +91 -69
- data/ext/datadog_profiling_native_extension/gvl_profiling_helper.c +50 -0
- data/ext/datadog_profiling_native_extension/gvl_profiling_helper.h +75 -0
- data/ext/datadog_profiling_native_extension/heap_recorder.c +54 -12
- data/ext/datadog_profiling_native_extension/heap_recorder.h +3 -1
- data/ext/datadog_profiling_native_extension/helpers.h +6 -17
- data/ext/datadog_profiling_native_extension/http_transport.c +41 -9
- data/ext/datadog_profiling_native_extension/libdatadog_helpers.c +0 -86
- data/ext/datadog_profiling_native_extension/libdatadog_helpers.h +2 -23
- data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +61 -172
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +116 -139
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +20 -11
- data/ext/datadog_profiling_native_extension/profiling.c +1 -3
- data/ext/datadog_profiling_native_extension/ruby_helpers.c +0 -33
- data/ext/datadog_profiling_native_extension/ruby_helpers.h +1 -26
- data/ext/datadog_profiling_native_extension/setup_signal_handler.h +1 -0
- data/ext/datadog_profiling_native_extension/stack_recorder.c +14 -2
- data/ext/datadog_profiling_native_extension/stack_recorder.h +2 -0
- data/ext/datadog_profiling_native_extension/time_helpers.c +0 -15
- data/ext/datadog_profiling_native_extension/time_helpers.h +36 -6
- data/ext/{datadog_profiling_native_extension → libdatadog_api}/crashtracker.c +37 -22
- data/ext/libdatadog_api/datadog_ruby_common.c +83 -0
- data/ext/libdatadog_api/datadog_ruby_common.h +53 -0
- data/ext/libdatadog_api/extconf.rb +108 -0
- data/ext/libdatadog_api/macos_development.md +26 -0
- data/ext/libdatadog_extconf_helpers.rb +130 -0
- data/lib/datadog/appsec/assets/waf_rules/recommended.json +2184 -108
- data/lib/datadog/appsec/assets/waf_rules/strict.json +1430 -2
- data/lib/datadog/appsec/component.rb +29 -8
- data/lib/datadog/appsec/configuration/settings.rb +2 -2
- data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +1 -0
- data/lib/datadog/appsec/contrib/devise/patcher/rememberable_patch.rb +21 -0
- data/lib/datadog/appsec/contrib/devise/patcher.rb +12 -2
- data/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +35 -0
- data/lib/datadog/appsec/contrib/graphql/gateway/multiplex.rb +109 -0
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +71 -0
- data/lib/datadog/appsec/contrib/graphql/integration.rb +54 -0
- data/lib/datadog/appsec/contrib/graphql/patcher.rb +37 -0
- data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +59 -0
- data/lib/datadog/appsec/contrib/rack/gateway/request.rb +3 -6
- data/lib/datadog/appsec/event.rb +1 -1
- data/lib/datadog/appsec/processor/actions.rb +1 -1
- data/lib/datadog/appsec/processor/rule_loader.rb +3 -1
- data/lib/datadog/appsec/processor/rule_merger.rb +33 -15
- data/lib/datadog/appsec/processor.rb +36 -37
- data/lib/datadog/appsec/rate_limiter.rb +25 -40
- data/lib/datadog/appsec/remote.rb +7 -3
- data/lib/datadog/appsec/response.rb +15 -1
- data/lib/datadog/appsec.rb +3 -2
- data/lib/datadog/core/configuration/components.rb +18 -15
- data/lib/datadog/core/configuration/settings.rb +135 -9
- data/lib/datadog/core/crashtracking/agent_base_url.rb +21 -0
- data/lib/datadog/core/crashtracking/component.rb +111 -0
- data/lib/datadog/core/crashtracking/tag_builder.rb +39 -0
- data/lib/datadog/core/diagnostics/environment_logger.rb +8 -11
- data/lib/datadog/core/environment/execution.rb +5 -5
- data/lib/datadog/core/metrics/client.rb +7 -0
- data/lib/datadog/core/rate_limiter.rb +183 -0
- data/lib/datadog/core/remote/client/capabilities.rb +4 -3
- data/lib/datadog/core/remote/component.rb +4 -2
- data/lib/datadog/core/remote/negotiation.rb +4 -4
- data/lib/datadog/core/remote/tie.rb +2 -0
- data/lib/datadog/core/runtime/metrics.rb +1 -1
- data/lib/datadog/core/telemetry/component.rb +51 -2
- data/lib/datadog/core/telemetry/emitter.rb +9 -11
- data/lib/datadog/core/telemetry/event.rb +37 -1
- data/lib/datadog/core/telemetry/ext.rb +1 -0
- data/lib/datadog/core/telemetry/http/adapters/net.rb +10 -12
- data/lib/datadog/core/telemetry/http/ext.rb +3 -0
- data/lib/datadog/core/telemetry/http/transport.rb +38 -9
- data/lib/datadog/core/telemetry/logger.rb +51 -0
- data/lib/datadog/core/telemetry/logging.rb +71 -0
- data/lib/datadog/core/telemetry/request.rb +13 -1
- data/lib/datadog/core/utils/at_fork_monkey_patch.rb +102 -0
- data/lib/datadog/core/utils/time.rb +12 -0
- data/lib/datadog/di/code_tracker.rb +168 -0
- data/lib/datadog/di/configuration/settings.rb +163 -0
- data/lib/datadog/di/configuration.rb +11 -0
- data/lib/datadog/di/error.rb +31 -0
- data/lib/datadog/di/extensions.rb +16 -0
- data/lib/datadog/di/probe.rb +133 -0
- data/lib/datadog/di/probe_builder.rb +41 -0
- data/lib/datadog/di/redactor.rb +188 -0
- data/lib/datadog/di/serializer.rb +193 -0
- data/lib/datadog/di.rb +14 -0
- data/lib/datadog/kit/appsec/events.rb +2 -4
- data/lib/datadog/opentelemetry/sdk/propagator.rb +2 -0
- data/lib/datadog/opentelemetry/sdk/span_processor.rb +10 -0
- data/lib/datadog/opentelemetry/sdk/trace/span.rb +23 -0
- data/lib/datadog/profiling/collectors/code_provenance.rb +7 -7
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +28 -26
- data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +11 -13
- data/lib/datadog/profiling/collectors/info.rb +15 -6
- data/lib/datadog/profiling/collectors/thread_context.rb +30 -2
- data/lib/datadog/profiling/component.rb +89 -95
- data/lib/datadog/profiling/exporter.rb +3 -3
- data/lib/datadog/profiling/ext/dir_monkey_patches.rb +3 -3
- data/lib/datadog/profiling/ext.rb +21 -21
- data/lib/datadog/profiling/flush.rb +1 -1
- data/lib/datadog/profiling/http_transport.rb +14 -7
- data/lib/datadog/profiling/load_native_extension.rb +5 -5
- data/lib/datadog/profiling/preload.rb +1 -1
- data/lib/datadog/profiling/profiler.rb +5 -8
- data/lib/datadog/profiling/scheduler.rb +33 -25
- data/lib/datadog/profiling/stack_recorder.rb +3 -0
- data/lib/datadog/profiling/tag_builder.rb +2 -2
- data/lib/datadog/profiling/tasks/exec.rb +5 -5
- data/lib/datadog/profiling/tasks/setup.rb +16 -35
- data/lib/datadog/profiling.rb +4 -5
- data/lib/datadog/single_step_instrument.rb +12 -0
- data/lib/datadog/tracing/contrib/action_cable/instrumentation.rb +8 -12
- data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +5 -0
- data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +78 -0
- data/lib/datadog/tracing/contrib/action_pack/action_dispatch/patcher.rb +33 -0
- data/lib/datadog/tracing/contrib/action_pack/patcher.rb +2 -0
- data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +4 -0
- data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +3 -1
- data/lib/datadog/tracing/contrib/active_record/events/sql.rb +4 -1
- data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +5 -1
- data/lib/datadog/tracing/contrib/aws/instrumentation.rb +5 -0
- data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +6 -1
- data/lib/datadog/tracing/contrib/ext.rb +14 -0
- data/lib/datadog/tracing/contrib/faraday/middleware.rb +9 -0
- data/lib/datadog/tracing/contrib/grape/endpoint.rb +19 -0
- data/lib/datadog/tracing/contrib/graphql/patcher.rb +9 -12
- data/lib/datadog/tracing/contrib/graphql/trace_patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/graphql/tracing_patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +14 -10
- data/lib/datadog/tracing/contrib/graphql/unified_trace_patcher.rb +10 -4
- data/lib/datadog/tracing/contrib/http/instrumentation.rb +18 -15
- data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +6 -5
- data/lib/datadog/tracing/contrib/httpclient/patcher.rb +1 -14
- data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +5 -0
- data/lib/datadog/tracing/contrib/httprb/patcher.rb +1 -14
- data/lib/datadog/tracing/contrib/lograge/patcher.rb +15 -0
- data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +2 -0
- data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +5 -0
- data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +17 -13
- data/lib/datadog/tracing/contrib/opensearch/patcher.rb +13 -6
- data/lib/datadog/tracing/contrib/patcher.rb +2 -1
- data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +5 -0
- data/lib/datadog/tracing/contrib/pg/instrumentation.rb +4 -1
- data/lib/datadog/tracing/contrib/presto/patcher.rb +1 -13
- data/lib/datadog/tracing/contrib/propagation/sql_comment/ext.rb +28 -0
- data/lib/datadog/tracing/contrib/propagation/sql_comment/mode.rb +5 -1
- data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +22 -10
- data/lib/datadog/tracing/contrib/rack/middlewares.rb +27 -0
- data/lib/datadog/tracing/contrib/redis/tags.rb +4 -0
- data/lib/datadog/tracing/contrib/sinatra/tracer.rb +4 -0
- data/lib/datadog/tracing/contrib/stripe/request.rb +3 -2
- data/lib/datadog/tracing/contrib/trilogy/configuration/settings.rb +5 -0
- data/lib/datadog/tracing/contrib/trilogy/instrumentation.rb +4 -1
- data/lib/datadog/tracing/diagnostics/environment_logger.rb +14 -16
- data/lib/datadog/tracing/distributed/propagation.rb +7 -0
- data/lib/datadog/tracing/metadata/errors.rb +9 -1
- data/lib/datadog/tracing/metadata/ext.rb +6 -0
- data/lib/datadog/tracing/pipeline/span_filter.rb +2 -2
- data/lib/datadog/tracing/remote.rb +5 -2
- data/lib/datadog/tracing/sampling/matcher.rb +6 -1
- data/lib/datadog/tracing/sampling/rate_sampler.rb +1 -1
- data/lib/datadog/tracing/sampling/rule.rb +2 -0
- data/lib/datadog/tracing/sampling/rule_sampler.rb +9 -5
- data/lib/datadog/tracing/sampling/span/ext.rb +1 -1
- data/lib/datadog/tracing/sampling/span/rule.rb +2 -2
- data/lib/datadog/tracing/span.rb +9 -2
- data/lib/datadog/tracing/span_event.rb +41 -0
- data/lib/datadog/tracing/span_operation.rb +6 -2
- data/lib/datadog/tracing/trace_operation.rb +26 -2
- data/lib/datadog/tracing/tracer.rb +14 -12
- data/lib/datadog/tracing/transport/http/client.rb +1 -0
- data/lib/datadog/tracing/transport/io/client.rb +1 -0
- data/lib/datadog/tracing/transport/serializable_trace.rb +3 -0
- data/lib/datadog/tracing/workers/trace_writer.rb +1 -1
- data/lib/datadog/tracing/workers.rb +1 -1
- data/lib/datadog/version.rb +1 -1
- metadata +46 -11
- data/lib/datadog/profiling/crashtracker.rb +0 -91
- data/lib/datadog/profiling/ext/forking.rb +0 -98
- data/lib/datadog/tracing/sampling/rate_limiter.rb +0 -185
@@ -0,0 +1,163 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module DI
|
5
|
+
module Configuration
|
6
|
+
# Settings
|
7
|
+
module Settings
|
8
|
+
def self.extended(base)
|
9
|
+
base = base.singleton_class unless base.is_a?(Class)
|
10
|
+
add_settings!(base)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.add_settings!(base)
|
14
|
+
base.class_eval do
|
15
|
+
# The setting has "internal" prefix to prevent it from being
|
16
|
+
# prematurely turned on by customers.
|
17
|
+
settings :dynamic_instrumentation do
|
18
|
+
option :enabled do |o|
|
19
|
+
o.type :bool
|
20
|
+
# The environment variable has an "internal" prefix so that
|
21
|
+
# any customers that have the "proper" environment variable
|
22
|
+
# turned on (i.e. DD_DYNAMIC_INSTRUMENTATION_ENABLED)
|
23
|
+
# do not enable Ruby DI until the latter is ready for
|
24
|
+
# customer testing.
|
25
|
+
o.env "DD_DYNAMIC_INSTRUMENTATION_ENABLED"
|
26
|
+
o.default false
|
27
|
+
end
|
28
|
+
|
29
|
+
# This option instructs dynamic instrumentation to use
|
30
|
+
# untargeted trace points when installing line probes and
|
31
|
+
# code tracking is not active.
|
32
|
+
# WARNING: untargeted trace points carry a massive performance
|
33
|
+
# penalty for the entire file in which a line probe is placed.
|
34
|
+
#
|
35
|
+
# If this option is set to false, which is the default,
|
36
|
+
# dynamic instrumentation will add probes that reference
|
37
|
+
# unknown files to the list of pending probes, and when
|
38
|
+
# the respective files are loaded, the line probes will be
|
39
|
+
# installed using targeted trace points. If the file in
|
40
|
+
# question is already loaded when the probe is received
|
41
|
+
# (for example, it is in a third-party library loaded during
|
42
|
+
# application boot), and code tracking was not active when
|
43
|
+
# the file was loaded, such files will not be instrumentable
|
44
|
+
# via line probes.
|
45
|
+
#
|
46
|
+
# If this option is set to true
|
47
|
+
#
|
48
|
+
# activated, DI will in
|
49
|
+
# activated or because the files being targeted have beenIf true and code tracking is not enabled, dynamic instrumentation
|
50
|
+
# will use untargeted trace points.
|
51
|
+
# If false and code tracking is not enabled, dynamic
|
52
|
+
# instrumentation will not instrument any files loaded
|
53
|
+
# WARNING: these trace points will greatly degrade performance
|
54
|
+
# of all code in the instrumented files.
|
55
|
+
option :untargeted_trace_points do |o|
|
56
|
+
o.type :bool
|
57
|
+
o.default false
|
58
|
+
end
|
59
|
+
|
60
|
+
# If true, all of the catch-all rescue blocks in DI
|
61
|
+
# will propagate the exceptions onward.
|
62
|
+
# WARNING: for internal Datadog use only - this will break
|
63
|
+
# the DI product and potentially the library in general in
|
64
|
+
# a multitude of ways, cause resource leakage, permanent
|
65
|
+
# performance decreases, etc.
|
66
|
+
option :propagate_all_exceptions do |o|
|
67
|
+
o.type :bool
|
68
|
+
o.default false
|
69
|
+
end
|
70
|
+
|
71
|
+
# An array of variable and key names to redact in addition to
|
72
|
+
# the built-in list of identifiers.
|
73
|
+
#
|
74
|
+
# The names will be normalized by removing the following
|
75
|
+
# symbols: _, -, @, $, and then matched to the complete
|
76
|
+
# variable or key name while ignoring the case.
|
77
|
+
# For example, specifying pass_word will match password and
|
78
|
+
# PASSWORD, and specifying PASSWORD will match pass_word.
|
79
|
+
# Note that, while the at sign (@) is used in Ruby to refer
|
80
|
+
# to instance variables, it does not have any significance
|
81
|
+
# for this setting (and is removed before matching identifiers).
|
82
|
+
option :redacted_identifiers do |o|
|
83
|
+
o.env "DD_DYNAMIC_INSTRUMENTATION_REDACTED_IDENTIFIERS"
|
84
|
+
o.env_parser do |value|
|
85
|
+
value&.split(",")&.map(&:strip)
|
86
|
+
end
|
87
|
+
|
88
|
+
o.type :array
|
89
|
+
o.default []
|
90
|
+
end
|
91
|
+
|
92
|
+
# An array of class names, values of which will be redacted from
|
93
|
+
# dynamic instrumentation snapshots. Example: FooClass.
|
94
|
+
# If a name is suffixed by '*', it becomes a wildcard and
|
95
|
+
# instances of any class whose name begins with the specified
|
96
|
+
# prefix will be redacted (example: Foo*).
|
97
|
+
#
|
98
|
+
# The names must all be fully-qualified, if any prefix of a
|
99
|
+
# class name is configured to be redacted, the value will be
|
100
|
+
# subject to redaction. For example, if Foo* is in the
|
101
|
+
# redacted class name list, instances of Foo, FooBar,
|
102
|
+
# Foo::Bar are all subject to redaction, but Bar::Foo will
|
103
|
+
# not be subject to redaction.
|
104
|
+
#
|
105
|
+
# Leading double-colon is permitted but has no effect,
|
106
|
+
# because the names are always considered to be fully-qualified.
|
107
|
+
# For example, adding ::Foo to the list will redact instances
|
108
|
+
# of Foo.
|
109
|
+
#
|
110
|
+
# Trailing colons should not be used because they will trigger
|
111
|
+
# exact match behavior but Ruby class names do not have
|
112
|
+
# trailing colons. For example, Foo:: will not cause anything
|
113
|
+
# to be redacted. Use Foo::* to redact all classes under
|
114
|
+
# the Foo module.
|
115
|
+
option :redacted_type_names do |o|
|
116
|
+
o.env "DD_DYNAMIC_INSTRUMENTATION_REDACTED_TYPES"
|
117
|
+
o.env_parser do |value|
|
118
|
+
value&.split(",")&.map(&:strip)
|
119
|
+
end
|
120
|
+
|
121
|
+
o.type :array
|
122
|
+
o.default []
|
123
|
+
end
|
124
|
+
|
125
|
+
# Maximum number of object or collection traversals that
|
126
|
+
# will be permitted when serializing captured values.
|
127
|
+
option :max_capture_depth do |o|
|
128
|
+
o.type :int
|
129
|
+
o.default 3
|
130
|
+
end
|
131
|
+
|
132
|
+
# Maximum number of collection (Array and Hash) elements
|
133
|
+
# that will be captured. Arrays and hashes that have more
|
134
|
+
# elements will be truncated to this many elements.
|
135
|
+
option :max_capture_collection_size do |o|
|
136
|
+
o.type :int
|
137
|
+
o.default 100
|
138
|
+
end
|
139
|
+
|
140
|
+
# Strings longer than this length will be truncated to this
|
141
|
+
# length in dynamic instrumentation snapshots.
|
142
|
+
#
|
143
|
+
# Note that while all values are stringified during
|
144
|
+
# serialization, only values which are originally instances
|
145
|
+
# of the String class are subject to this length limit.
|
146
|
+
option :max_capture_string_length do |o|
|
147
|
+
o.type :int
|
148
|
+
o.default 255
|
149
|
+
end
|
150
|
+
|
151
|
+
# Maximim number of attributes that will be captured for
|
152
|
+
# a single non-primitive value.
|
153
|
+
option :max_capture_attribute_count do |o|
|
154
|
+
o.type :int
|
155
|
+
o.default 20
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module DI
|
5
|
+
# Base class for Dynamic Instrumentation exceptions.
|
6
|
+
#
|
7
|
+
# None of these exceptions should be propagated out of DI to user
|
8
|
+
# applications, therefore these exceptions are not considered to be
|
9
|
+
# part of the public API of the library.
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
class Error < StandardError
|
13
|
+
# Probe does not contain a line number (i.e., is not a line probe).
|
14
|
+
class MissingLineNumber < Error
|
15
|
+
end
|
16
|
+
|
17
|
+
# Failed to communicate to the local Datadog agent (e.g. to send
|
18
|
+
# probe status or a snapshot).
|
19
|
+
class AgentCommunicationError < Error
|
20
|
+
end
|
21
|
+
|
22
|
+
# Attempting to instrument a method or file which does not exist.
|
23
|
+
#
|
24
|
+
# This could be due to the code that is referenced in the probe
|
25
|
+
# having not been loaded yet, or due to the probe referencing code
|
26
|
+
# that does not in fact exist anywhere (e.g. due to a misspelling).
|
27
|
+
class DITargetNotDefined < Error
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../core/configuration"
|
4
|
+
require_relative "configuration"
|
5
|
+
|
6
|
+
module Datadog
|
7
|
+
module DI
|
8
|
+
# Extends Datadog tracing with DI features
|
9
|
+
module Extensions
|
10
|
+
# Inject DI into global objects.
|
11
|
+
def self.activate!
|
12
|
+
Core::Configuration::Settings.extend(Configuration::Settings)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "error"
|
4
|
+
require_relative "../core/rate_limiter"
|
5
|
+
|
6
|
+
module Datadog
|
7
|
+
module DI
|
8
|
+
# Encapsulates probe information (as received via remote config)
|
9
|
+
# and state (e.g. whether the probe was installed, or executed).
|
10
|
+
#
|
11
|
+
# It is possible that remote configuration will specify an unsupported
|
12
|
+
# probe type or attribute, due to new DI functionality being added
|
13
|
+
# over time. We want to have predictable behavior in such cases, and
|
14
|
+
# since we can't guarantee that there will be enough information in
|
15
|
+
# a remote config payload to construct a functional probe, ProbeBuilder
|
16
|
+
# and remote config code must be prepared to deal with exceptions
|
17
|
+
# raised by Probe constructor in particular. Therefore, Probe constructor
|
18
|
+
# will raise an exception if it determines that there is not enough
|
19
|
+
# information (or confilcting information) in the arguments to create a
|
20
|
+
# functional probe, and upstream code is tasked with not spamming logs
|
21
|
+
# with notifications of such errors (and potentially limiting the
|
22
|
+
# attempts to construct probe from a given payload).
|
23
|
+
#
|
24
|
+
# Note that, while remote configuration provides line numbers as an
|
25
|
+
# array, the only supported line number configuration is a single line
|
26
|
+
# (this is the case for all languages currently). Therefore Probe
|
27
|
+
# only supports one line number, and ProbeBuilder is responsible for
|
28
|
+
# extracting that one line number out of the array received from RC.
|
29
|
+
#
|
30
|
+
# Note: only some of the parameter/attribute values are currently validated.
|
31
|
+
#
|
32
|
+
# @api private
|
33
|
+
class Probe
|
34
|
+
def initialize(id:, type:,
|
35
|
+
file: nil, line_no: nil, type_name: nil, method_name: nil,
|
36
|
+
template: nil, capture_snapshot: false, max_capture_depth: nil, rate_limit: nil)
|
37
|
+
# Perform some sanity checks here to detect unexpected attribute
|
38
|
+
# combinations, in order to not do them in subsequent code.
|
39
|
+
if line_no && method_name
|
40
|
+
raise ArgumentError, "Probe contains both line number and method name: #{id}"
|
41
|
+
end
|
42
|
+
|
43
|
+
if type_name && !method_name || method_name && !type_name
|
44
|
+
raise ArgumentError, "Partial method probe definition: #{id}"
|
45
|
+
end
|
46
|
+
|
47
|
+
@id = id
|
48
|
+
@type = type
|
49
|
+
@file = file
|
50
|
+
@line_no = line_no
|
51
|
+
@type_name = type_name
|
52
|
+
@method_name = method_name
|
53
|
+
@template = template
|
54
|
+
@capture_snapshot = !!capture_snapshot
|
55
|
+
@max_capture_depth = max_capture_depth
|
56
|
+
|
57
|
+
# These checks use instance methods that have more complex logic
|
58
|
+
# than checking a single argument value. To avoid duplicating
|
59
|
+
# the logic here, use the methods and perform these checks after
|
60
|
+
# instance variable assignment.
|
61
|
+
unless method? || line?
|
62
|
+
raise ArgumentError, "Unhandled probe type: neither method nor line probe: #{id}"
|
63
|
+
end
|
64
|
+
|
65
|
+
@rate_limit = rate_limit || (@capture_snapshot ? 1 : 5000)
|
66
|
+
@rate_limiter = Datadog::Core::TokenBucket.new(@rate_limit)
|
67
|
+
end
|
68
|
+
|
69
|
+
attr_reader :id
|
70
|
+
attr_reader :type
|
71
|
+
attr_reader :file
|
72
|
+
attr_reader :line_no
|
73
|
+
attr_reader :type_name
|
74
|
+
attr_reader :method_name
|
75
|
+
attr_reader :template
|
76
|
+
|
77
|
+
# Configured maximum capture depth. Can be nil in which case
|
78
|
+
# the global default will be used.
|
79
|
+
attr_reader :max_capture_depth
|
80
|
+
|
81
|
+
# Rate limit in effect, in invocations per second. Always present.
|
82
|
+
attr_reader :rate_limit
|
83
|
+
|
84
|
+
# Rate limiter object. For internal DI use only.
|
85
|
+
attr_reader :rate_limiter
|
86
|
+
|
87
|
+
def capture_snapshot?
|
88
|
+
@capture_snapshot
|
89
|
+
end
|
90
|
+
|
91
|
+
# Returns whether the probe is a line probe.
|
92
|
+
#
|
93
|
+
# Method probes may still specify a file name (to aid in locating the
|
94
|
+
# method or for stack traversal purposes?), therefore we do not check
|
95
|
+
# for file name/path presence here and just consider the line number.
|
96
|
+
def line?
|
97
|
+
!line_no.nil?
|
98
|
+
end
|
99
|
+
|
100
|
+
# Returns whether the probe is a method probe.
|
101
|
+
def method?
|
102
|
+
!!(type_name && method_name)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Returns the line number associated with the probe, raising
|
106
|
+
# Error::MissingLineNumber if the probe does not have a line number
|
107
|
+
# associated with it.
|
108
|
+
#
|
109
|
+
# This method is used by instrumentation driver to ensure a line number
|
110
|
+
# that is passed into the instrumentation logic is actually a line number
|
111
|
+
# and not nil.
|
112
|
+
def line_no!
|
113
|
+
if line_no.nil?
|
114
|
+
raise Error::MissingLineNumber, "Probe #{id} does not have a line number associated with it"
|
115
|
+
end
|
116
|
+
line_no
|
117
|
+
end
|
118
|
+
|
119
|
+
# Source code location of the probe, for diagnostic reporting.
|
120
|
+
def location
|
121
|
+
if method?
|
122
|
+
"#{type_name}.#{method_name}"
|
123
|
+
elsif line?
|
124
|
+
"#{file}:#{line_no}"
|
125
|
+
else
|
126
|
+
# This case should not be possible because constructor verifies that
|
127
|
+
# the probe is a method or a line probe.
|
128
|
+
raise NotImplementedError
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "probe"
|
4
|
+
|
5
|
+
module Datadog
|
6
|
+
module DI
|
7
|
+
# Creates Probe instances from remote configuration payloads.
|
8
|
+
#
|
9
|
+
# Due to the dynamic instrumentation product evolving over time,
|
10
|
+
# it is possible that the payload corresponds to a type of probe that the
|
11
|
+
# current version of the library does not handle.
|
12
|
+
# For now ArgumentError is raised in such cases (by ProbeBuilder or
|
13
|
+
# Probe constructor), since generally DI is meant to rescue all exceptions
|
14
|
+
# internally and not propagate any exceptions to applications.
|
15
|
+
# A dedicated exception could be added in the future if there is a use case
|
16
|
+
# for it.
|
17
|
+
#
|
18
|
+
# @api private
|
19
|
+
module ProbeBuilder
|
20
|
+
module_function def build_from_remote_config(config)
|
21
|
+
# The validations here are not yet comprehensive.
|
22
|
+
Probe.new(
|
23
|
+
id: config.fetch("id"),
|
24
|
+
type: config.fetch("type"),
|
25
|
+
file: config["where"]&.[]("sourceFile"),
|
26
|
+
# Sometimes lines are sometimes received as an array of nil
|
27
|
+
# for some reason.
|
28
|
+
line_no: config["where"]&.[]("lines")&.compact&.map(&:to_i)&.first,
|
29
|
+
type_name: config["where"]&.[]("typeName"),
|
30
|
+
method_name: config["where"]&.[]("methodName"),
|
31
|
+
template: config["template"],
|
32
|
+
capture_snapshot: !!config["captureSnapshot"],
|
33
|
+
max_capture_depth: config["capture"]&.[]("maxReferenceDepth"),
|
34
|
+
rate_limit: config["sampling"]&.[]("snapshotsPerSecond"),
|
35
|
+
)
|
36
|
+
rescue KeyError => exc
|
37
|
+
raise ArgumentError, "Malformed remote configuration entry for probe: #{exc.class}: #{exc}: #{config}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,188 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module DI
|
5
|
+
# Provides logic to identify sensitive information in snapshots captured
|
6
|
+
# by dynamic instrumentation.
|
7
|
+
#
|
8
|
+
# Redaction can be performed based on identifier or attribute name,
|
9
|
+
# or class name of said identifier or attribute. Redaction does not take
|
10
|
+
# into account variable values.
|
11
|
+
#
|
12
|
+
# There is a built-in list of identifier names which will be subject to
|
13
|
+
# redaction. Additional names can be provided by the user via the
|
14
|
+
# settings.dynamic_instrumentation.redacted_identifiers setting or
|
15
|
+
# the DD_DYNAMIC_INSTRUMENTATION_REDACTED_IDENTIFIERS environment
|
16
|
+
# variable. Currently no class names are subject to redaction by default;
|
17
|
+
# class names can be provided via the
|
18
|
+
# settings.dynamic_instrumentation.redacted_type_names setting or
|
19
|
+
# DD_DYNAMIC_INSTRUMENTATION_REDACTED_TYPES environment variable.
|
20
|
+
#
|
21
|
+
# Redacted identifiers must match exactly to an attribute name, a key
|
22
|
+
# in a hash or a variable name. Redacted types can either be matched
|
23
|
+
# exactly or, if the name is suffixed with an asterisk (*), any class
|
24
|
+
# whose name contains the specified prefix will be subject to redaction.
|
25
|
+
#
|
26
|
+
# When specifying class (type) names to be redacted, user must specify
|
27
|
+
# fully-qualified names. For example, if `Token` or `Token*` are
|
28
|
+
# specified to be redacted, instances of ::Token will be redacted
|
29
|
+
# but instances of ::Foo::Token will not be. To redact the latter,
|
30
|
+
# specify `Foo::Token` or `::Foo::Token` as redacted types.
|
31
|
+
#
|
32
|
+
# This class does not perform redaction itself (i.e., value replacement
|
33
|
+
# with a placeholder). This replacement is performed by Serializer.
|
34
|
+
#
|
35
|
+
# @api private
|
36
|
+
class Redactor
|
37
|
+
def initialize(settings)
|
38
|
+
@settings = settings
|
39
|
+
end
|
40
|
+
|
41
|
+
attr_reader :settings
|
42
|
+
|
43
|
+
def redact_identifier?(name)
|
44
|
+
redacted_identifiers.include?(normalize(name))
|
45
|
+
end
|
46
|
+
|
47
|
+
def redact_type?(value)
|
48
|
+
# Classses can be nameless, do not attempt to redact in that case.
|
49
|
+
if (cls_name = value.class.name)
|
50
|
+
redacted_type_names_regexp.match?(cls_name)
|
51
|
+
else
|
52
|
+
false
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def redacted_identifiers
|
59
|
+
@redacted_identifiers ||= begin
|
60
|
+
names = DEFAULT_REDACTED_IDENTIFIERS + settings.dynamic_instrumentation.redacted_identifiers
|
61
|
+
names.map! do |name|
|
62
|
+
normalize(name)
|
63
|
+
end
|
64
|
+
Set.new(names)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def redacted_type_names_regexp
|
69
|
+
@redacted_type_names_regexp ||= begin
|
70
|
+
names = settings.dynamic_instrumentation.redacted_type_names
|
71
|
+
names = names.map do |name|
|
72
|
+
if name.start_with?("::")
|
73
|
+
# :: prefix is redundant, all names are expected to be
|
74
|
+
# fully-qualified.
|
75
|
+
#
|
76
|
+
# Defaulting to empty string is for steep.
|
77
|
+
name = name[2...name.length] || ""
|
78
|
+
end
|
79
|
+
if name.end_with?("*")
|
80
|
+
# Defaulting to empty string is for steep.
|
81
|
+
name = name[0..-2] || ""
|
82
|
+
suffix = ".*"
|
83
|
+
else
|
84
|
+
suffix = ""
|
85
|
+
end
|
86
|
+
Regexp.escape(name) + suffix
|
87
|
+
end.join("|")
|
88
|
+
Regexp.new("\\A(?:#{names})\\z")
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Copied from dd-trace-py
|
93
|
+
DEFAULT_REDACTED_IDENTIFIERS = [
|
94
|
+
"2fa",
|
95
|
+
"accesstoken",
|
96
|
+
"aiohttpsession",
|
97
|
+
"apikey",
|
98
|
+
"apisecret",
|
99
|
+
"apisignature",
|
100
|
+
"appkey",
|
101
|
+
"applicationkey",
|
102
|
+
"auth",
|
103
|
+
"authorization",
|
104
|
+
"authtoken",
|
105
|
+
"ccnumber",
|
106
|
+
"certificatepin",
|
107
|
+
"cipher",
|
108
|
+
"clientid",
|
109
|
+
"clientsecret",
|
110
|
+
"connectionstring",
|
111
|
+
"connectsid",
|
112
|
+
"cookie",
|
113
|
+
"credentials",
|
114
|
+
"creditcard",
|
115
|
+
"csrf",
|
116
|
+
"csrftoken",
|
117
|
+
"cvv",
|
118
|
+
"databaseurl",
|
119
|
+
"dburl",
|
120
|
+
"encryptionkey",
|
121
|
+
"encryptionkeyid",
|
122
|
+
"env",
|
123
|
+
"geolocation",
|
124
|
+
"gpgkey",
|
125
|
+
"ipaddress",
|
126
|
+
"jti",
|
127
|
+
"jwt",
|
128
|
+
"licensekey",
|
129
|
+
"masterkey",
|
130
|
+
"mysqlpwd",
|
131
|
+
"nonce",
|
132
|
+
"oauth",
|
133
|
+
"oauthtoken",
|
134
|
+
"otp",
|
135
|
+
"passhash",
|
136
|
+
"passwd",
|
137
|
+
"password",
|
138
|
+
"passwordb",
|
139
|
+
"pemfile",
|
140
|
+
"pgpkey",
|
141
|
+
"phpsessid",
|
142
|
+
"pin",
|
143
|
+
"pincode",
|
144
|
+
"pkcs8",
|
145
|
+
"privatekey",
|
146
|
+
"publickey",
|
147
|
+
"pwd",
|
148
|
+
"recaptchakey",
|
149
|
+
"refreshtoken",
|
150
|
+
"routingnumber",
|
151
|
+
"salt",
|
152
|
+
"secret",
|
153
|
+
"secretkey",
|
154
|
+
"secrettoken",
|
155
|
+
"securityanswer",
|
156
|
+
"securitycode",
|
157
|
+
"securityquestion",
|
158
|
+
"serviceaccountcredentials",
|
159
|
+
"session",
|
160
|
+
"sessionid",
|
161
|
+
"sessionkey",
|
162
|
+
"setcookie",
|
163
|
+
"signature",
|
164
|
+
"signaturekey",
|
165
|
+
"sshkey",
|
166
|
+
"ssn",
|
167
|
+
"symfony",
|
168
|
+
"token",
|
169
|
+
"transactionid",
|
170
|
+
"twiliotoken",
|
171
|
+
"usersession",
|
172
|
+
"voterid",
|
173
|
+
"xapikey",
|
174
|
+
"xauthtoken",
|
175
|
+
"xcsrftoken",
|
176
|
+
"xforwardedfor",
|
177
|
+
"xrealip",
|
178
|
+
"xsrf",
|
179
|
+
"xsrftoken",
|
180
|
+
]
|
181
|
+
|
182
|
+
# Input can be a string or a symbol.
|
183
|
+
def normalize(str)
|
184
|
+
str.to_s.strip.downcase.gsub(/[-_$@]/, "")
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|