datadog 2.17.0 → 2.19.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 +90 -1
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +63 -56
- data/ext/datadog_profiling_native_extension/collectors_stack.c +263 -76
- data/ext/datadog_profiling_native_extension/collectors_stack.h +20 -3
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +62 -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 +38 -26
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +6 -4
- data/ext/datadog_profiling_native_extension/ruby_helpers.c +1 -13
- data/ext/datadog_profiling_native_extension/ruby_helpers.h +3 -11
- 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 +71 -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/instrumentation/gateway/argument.rb +1 -1
- 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 +42 -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/component.rb +8 -4
- data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +1 -0
- data/lib/datadog/core/telemetry/event/app_started.rb +148 -40
- 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 +48 -5
- data/lib/datadog/di/probe_notification_builder.rb +37 -42
- data/lib/datadog/di/probe_notifier_worker.rb +9 -1
- data/lib/datadog/di/serializer.rb +10 -2
- data/lib/datadog/di/transport/http/input.rb +10 -0
- data/lib/datadog/di/transport/input.rb +10 -2
- data/lib/datadog/di.rb +0 -6
- data/lib/datadog/kit/appsec/events/v2.rb +195 -0
- data/lib/datadog/profiling/collectors/code_provenance.rb +17 -8
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +6 -0
- data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -0
- data/lib/datadog/profiling/collectors/info.rb +41 -0
- data/lib/datadog/profiling/collectors/thread_context.rb +16 -1
- data/lib/datadog/profiling/component.rb +8 -9
- data/lib/datadog/profiling/exporter.rb +9 -3
- 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/sequence_tracker.rb +44 -0
- data/lib/datadog/profiling/stack_recorder.rb +5 -5
- data/lib/datadog/profiling/tag_builder.rb +7 -37
- data/lib/datadog/profiling/tasks/setup.rb +2 -0
- data/lib/datadog/profiling.rb +1 -0
- data/lib/datadog/single_step_instrument.rb +9 -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/active_support/cache/events/cache.rb +7 -1
- data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +13 -0
- data/lib/datadog/tracing/contrib/lograge/patcher.rb +4 -2
- data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +16 -6
- data/lib/datadog/tracing/contrib/rails/patcher.rb +4 -1
- data/lib/datadog/tracing/contrib/rails/runner.rb +61 -40
- 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/diagnostics/environment_logger.rb +3 -1
- data/lib/datadog/tracing/span_event.rb +1 -1
- data/lib/datadog/tracing/span_operation.rb +22 -0
- 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
- data/lib/datadog.rb +7 -0
- metadata +14 -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
@@ -7,6 +7,10 @@
|
|
7
7
|
static VALUE _native_configurator_new(VALUE klass);
|
8
8
|
static VALUE _native_configurator_get(VALUE self);
|
9
9
|
|
10
|
+
// Used for testing in RSpec
|
11
|
+
static VALUE _native_configurator_with_local_path(DDTRACE_UNUSED VALUE _self, VALUE rb_configurator, VALUE path);
|
12
|
+
static VALUE _native_configurator_with_fleet_path(DDTRACE_UNUSED VALUE _self, VALUE rb_configurator, VALUE path);
|
13
|
+
|
10
14
|
static VALUE config_vec_class = Qnil;
|
11
15
|
|
12
16
|
// ddog_Configurator memory management
|
@@ -52,20 +56,42 @@ void library_config_init(VALUE core_module) {
|
|
52
56
|
rb_define_alloc_func(configurator_class, _native_configurator_new);
|
53
57
|
rb_define_method(configurator_class, "get", _native_configurator_get, 0);
|
54
58
|
|
59
|
+
// Used for testing in RSpec
|
60
|
+
VALUE testing_module = rb_define_module_under(stable_config_module, "Testing");
|
61
|
+
rb_define_singleton_method(testing_module, "with_local_path", _native_configurator_with_local_path, 2);
|
62
|
+
rb_define_singleton_method(testing_module, "with_fleet_path", _native_configurator_with_fleet_path, 2);
|
63
|
+
|
55
64
|
rb_undef_alloc_func(config_vec_class); // It cannot be created from Ruby code and only serves as an intermediate object for the Ruby GC
|
56
65
|
}
|
57
66
|
|
58
|
-
|
59
|
-
static VALUE _native_configurator_new(DDTRACE_UNUSED VALUE _klass) {
|
60
|
-
/*
|
67
|
+
static VALUE _native_configurator_new(VALUE klass) {
|
61
68
|
ddog_Configurator *configurator = ddog_library_configurator_new(false, DDOG_CHARSLICE_C("ruby"));
|
62
69
|
|
63
70
|
ddog_library_configurator_with_detect_process_info(configurator);
|
64
71
|
|
65
72
|
return TypedData_Wrap_Struct(klass, &configurator_typed_data, configurator);
|
66
|
-
|
73
|
+
}
|
74
|
+
|
75
|
+
static VALUE _native_configurator_with_local_path(DDTRACE_UNUSED VALUE _self, VALUE rb_configurator, VALUE path) {
|
76
|
+
ddog_Configurator *configurator;
|
77
|
+
TypedData_Get_Struct(rb_configurator, ddog_Configurator, &configurator_typed_data, configurator);
|
78
|
+
|
79
|
+
ENFORCE_TYPE(path, T_STRING);
|
67
80
|
|
68
|
-
|
81
|
+
ddog_library_configurator_with_local_path(configurator, cstr_from_ruby_string(path));
|
82
|
+
|
83
|
+
return Qnil;
|
84
|
+
}
|
85
|
+
|
86
|
+
static VALUE _native_configurator_with_fleet_path(DDTRACE_UNUSED VALUE _self, VALUE rb_configurator, VALUE path) {
|
87
|
+
ddog_Configurator *configurator;
|
88
|
+
TypedData_Get_Struct(rb_configurator, ddog_Configurator, &configurator_typed_data, configurator);
|
89
|
+
|
90
|
+
ENFORCE_TYPE(path, T_STRING);
|
91
|
+
|
92
|
+
ddog_library_configurator_with_fleet_path(configurator, cstr_from_ruby_string(path));
|
93
|
+
|
94
|
+
return Qnil;
|
69
95
|
}
|
70
96
|
|
71
97
|
static VALUE _native_configurator_get(VALUE self) {
|
@@ -96,26 +122,42 @@ static VALUE _native_configurator_get(VALUE self) {
|
|
96
122
|
|
97
123
|
VALUE local_config_hash = rb_hash_new();
|
98
124
|
VALUE fleet_config_hash = rb_hash_new();
|
99
|
-
|
100
|
-
|
125
|
+
|
126
|
+
bool local_config_id_set = false;
|
127
|
+
bool fleet_config_id_set = false;
|
128
|
+
VALUE local_hash = rb_hash_new();
|
129
|
+
VALUE fleet_hash = rb_hash_new();
|
101
130
|
for (uintptr_t i = 0; i < config_vec->len; i++) {
|
102
131
|
ddog_LibraryConfig config = config_vec->ptr[i];
|
103
132
|
VALUE selected_hash;
|
104
133
|
if (config.source == DDOG_LIBRARY_CONFIG_SOURCE_LOCAL_STABLE_CONFIG) {
|
105
134
|
selected_hash = local_config_hash;
|
135
|
+
if (!local_config_id_set) {
|
136
|
+
local_config_id_set = true;
|
137
|
+
if (config.config_id.length > 0) {
|
138
|
+
rb_hash_aset(local_hash, ID2SYM(rb_intern("id")), rb_utf8_str_new_cstr(config.config_id.ptr));
|
139
|
+
}
|
140
|
+
}
|
106
141
|
}
|
107
142
|
else {
|
108
143
|
selected_hash = fleet_config_hash;
|
144
|
+
if (!fleet_config_id_set) {
|
145
|
+
fleet_config_id_set = true;
|
146
|
+
if (config.config_id.length > 0) {
|
147
|
+
rb_hash_aset(fleet_hash, ID2SYM(rb_intern("id")), rb_utf8_str_new_cstr(config.config_id.ptr));
|
148
|
+
}
|
149
|
+
}
|
109
150
|
}
|
110
151
|
|
111
|
-
|
112
|
-
rb_hash_aset(selected_hash, rb_str_new(name.ptr, name.length), rb_str_new(config.value.ptr, config.value.length));
|
152
|
+
rb_hash_aset(selected_hash, rb_utf8_str_new_cstr(config.name.ptr), rb_utf8_str_new_cstr(config.value.ptr));
|
113
153
|
}
|
114
|
-
|
154
|
+
|
155
|
+
rb_hash_aset(local_hash, ID2SYM(rb_intern("config")), local_config_hash);
|
156
|
+
rb_hash_aset(fleet_hash, ID2SYM(rb_intern("config")), fleet_config_hash);
|
115
157
|
|
116
158
|
VALUE result = rb_hash_new();
|
117
|
-
rb_hash_aset(result, ID2SYM(rb_intern("local")),
|
118
|
-
rb_hash_aset(result, ID2SYM(rb_intern("fleet")),
|
159
|
+
rb_hash_aset(result, ID2SYM(rb_intern("local")), local_hash);
|
160
|
+
rb_hash_aset(result, ID2SYM(rb_intern("fleet")), fleet_hash);
|
119
161
|
|
120
162
|
RB_GC_GUARD(config_vec_rb);
|
121
163
|
return result;
|
@@ -17,3 +17,9 @@ static inline VALUE log_warning_without_config(VALUE warning) {
|
|
17
17
|
|
18
18
|
return rb_funcall(logger, rb_intern("warn"), 1, warning);
|
19
19
|
}
|
20
|
+
|
21
|
+
static inline ddog_CStr cstr_from_ruby_string(VALUE string) {
|
22
|
+
ENFORCE_TYPE(string, T_STRING);
|
23
|
+
ddog_CStr cstr = {.ptr = RSTRING_PTR(string), .length = RSTRING_LEN(string)};
|
24
|
+
return cstr;
|
25
|
+
}
|
@@ -1,7 +1,7 @@
|
|
1
1
|
#include <errno.h>
|
2
2
|
#include <stdlib.h>
|
3
3
|
#include <ruby.h>
|
4
|
-
#include <datadog/
|
4
|
+
#include <datadog/library-config.h>
|
5
5
|
|
6
6
|
#include "datadog_ruby_common.h"
|
7
7
|
|
@@ -36,8 +36,7 @@ void process_discovery_init(VALUE core_module) {
|
|
36
36
|
rb_define_singleton_method(process_discovery_class, "_native_close_tracer_memfd", _native_close_tracer_memfd, 2);
|
37
37
|
}
|
38
38
|
|
39
|
-
|
40
|
-
static VALUE _native_store_tracer_metadata(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self) {
|
39
|
+
static VALUE _native_store_tracer_metadata(int argc, VALUE *argv, VALUE self) {
|
41
40
|
VALUE logger;
|
42
41
|
VALUE options;
|
43
42
|
rb_scan_args(argc, argv, "1:", &logger, &options);
|
@@ -61,7 +60,6 @@ static VALUE _native_store_tracer_metadata(int argc, VALUE *argv, DDTRACE_UNUSED
|
|
61
60
|
ENFORCE_TYPE(service_env, T_STRING);
|
62
61
|
ENFORCE_TYPE(service_version, T_STRING);
|
63
62
|
|
64
|
-
/*
|
65
63
|
ddog_Result_TracerMemfdHandle result = ddog_store_tracer_metadata(
|
66
64
|
(uint8_t) NUM2UINT(schema_version),
|
67
65
|
char_slice_from_ruby_string(runtime_id),
|
@@ -86,9 +84,6 @@ static VALUE _native_store_tracer_metadata(int argc, VALUE *argv, DDTRACE_UNUSED
|
|
86
84
|
VALUE tracer_memfd_class = rb_const_get(self, rb_intern("TracerMemfd"));
|
87
85
|
VALUE tracer_memfd = TypedData_Wrap_Struct(tracer_memfd_class, &tracer_memfd_type, fd);
|
88
86
|
return tracer_memfd;
|
89
|
-
*/
|
90
|
-
|
91
|
-
rb_raise(rb_eNotImpError, "TODO: Not in use yet, waiting for libdatadog 17.1");
|
92
87
|
}
|
93
88
|
|
94
89
|
static VALUE _native_to_rb_int(DDTRACE_UNUSED VALUE _self, VALUE tracer_memfd) {
|
@@ -104,7 +104,7 @@ module Datadog
|
|
104
104
|
|
105
105
|
# mkmf sets $PKGCONFIG after the `pkg_config` gets used in extconf.rb. When `pkg_config` is unsuccessful, we use
|
106
106
|
# this helper to decide if we can show more specific error message vs a generic "something went wrong".
|
107
|
-
def self.pkg_config_missing?(command: $PKGCONFIG) #
|
107
|
+
def self.pkg_config_missing?(command: $PKGCONFIG) # standard:disable Style/GlobalVars
|
108
108
|
pkg_config_available = command && xsystem("#{command} --version")
|
109
109
|
|
110
110
|
pkg_config_available != true
|
@@ -30,6 +30,14 @@ module Datadog
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
+
def store(key, value)
|
34
|
+
return @store[key] = value if @store.delete(key)
|
35
|
+
|
36
|
+
# NOTE: evict the oldest entry if store reached the maximum allowed size
|
37
|
+
@store.shift if @store.size >= @max_size
|
38
|
+
@store[key] = value
|
39
|
+
end
|
40
|
+
|
33
41
|
# NOTE: If the key exists, it's moved to the end of the list and
|
34
42
|
# if does not, the given block will be executed and the result
|
35
43
|
# will be stored (which will add it to the end of the list).
|
@@ -40,8 +48,7 @@ module Datadog
|
|
40
48
|
|
41
49
|
# NOTE: evict the oldest entry if store reached the maximum allowed size
|
42
50
|
@store.shift if @store.size >= @max_size
|
43
|
-
|
44
|
-
@store[key] ||= yield
|
51
|
+
@store[key] = yield
|
45
52
|
end
|
46
53
|
end
|
47
54
|
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module AppSec
|
5
|
+
module APISecurity
|
6
|
+
# This is a helper module to extract the route pattern from the Rack::Request.
|
7
|
+
module RouteExtractor
|
8
|
+
SINATRA_ROUTE_KEY = 'sinatra.route'
|
9
|
+
SINATRA_ROUTE_SEPARATOR = ' '
|
10
|
+
GRAPE_ROUTE_KEY = 'grape.routing_args'
|
11
|
+
RAILS_ROUTE_KEY = 'action_dispatch.route_uri_pattern'
|
12
|
+
RAILS_ROUTES_KEY = 'action_dispatch.routes'
|
13
|
+
RAILS_PATH_PARAMS_KEY = 'action_dispatch.request.path_parameters'
|
14
|
+
RAILS_FORMAT_SUFFIX = '(.:format)'
|
15
|
+
|
16
|
+
# HACK: We rely on the fact that each contrib will modify `request.env`
|
17
|
+
# and store information sufficient to compute the canonical
|
18
|
+
# route (ex: `/users/:id`).
|
19
|
+
#
|
20
|
+
# When contribs like Sinatra or Grape are used, they could be mounted
|
21
|
+
# into the Rails app, hence you can see the use of the `script_name`
|
22
|
+
# that will contain the path prefix of the mounted app.
|
23
|
+
#
|
24
|
+
# Rack
|
25
|
+
# does not support named arguments, so we have to use `path`
|
26
|
+
# Sinatra
|
27
|
+
# uses `sinatra.route` with a string like "GET /users/:id"
|
28
|
+
# Grape
|
29
|
+
# uses `grape.routing_args` with a hash with a `:route_info` key
|
30
|
+
# that contains a `Grape::Router::Route` object that contains
|
31
|
+
# `Grape::Router::Pattern` object with an `origin` method
|
32
|
+
# Rails < 7.1 (slow path)
|
33
|
+
# uses `action_dispatch.routes` to store `ActionDispatch::Routing::RouteSet`
|
34
|
+
# which can recognize requests
|
35
|
+
# Rails > 7.1 (fast path)
|
36
|
+
# uses `action_dispatch.route_uri_pattern` with a string like
|
37
|
+
# "/users/:id(.:format)"
|
38
|
+
#
|
39
|
+
# WARNING: This method works only *after* the request has been routed.
|
40
|
+
#
|
41
|
+
# WARNING: In Rails > 7.1 when a route was not found,
|
42
|
+
# action_dispatch.route_uri_pattern will not be set.
|
43
|
+
# In Rails < 7.1 it also will not be set even if a route was found,
|
44
|
+
# but in this case action_dispatch.request.path_parameters won't be empty.
|
45
|
+
def self.route_pattern(request)
|
46
|
+
if request.env.key?(GRAPE_ROUTE_KEY)
|
47
|
+
pattern = request.env[GRAPE_ROUTE_KEY][:route_info]&.pattern&.origin
|
48
|
+
"#{request.script_name}#{pattern}"
|
49
|
+
elsif request.env.key?(SINATRA_ROUTE_KEY)
|
50
|
+
pattern = request.env[SINATRA_ROUTE_KEY].split(SINATRA_ROUTE_SEPARATOR, 2)[1]
|
51
|
+
"#{request.script_name}#{pattern}"
|
52
|
+
elsif request.env.key?(RAILS_ROUTE_KEY)
|
53
|
+
request.env[RAILS_ROUTE_KEY].delete_suffix(RAILS_FORMAT_SUFFIX)
|
54
|
+
elsif request.env.key?(RAILS_ROUTES_KEY) && !request.env.fetch(RAILS_PATH_PARAMS_KEY, {}).empty?
|
55
|
+
pattern = request.env[RAILS_ROUTES_KEY].router
|
56
|
+
.recognize(request) { |route, _| break route.path.spec.to_s }
|
57
|
+
|
58
|
+
# NOTE: If rails is unable to recognize request it returns empty Array
|
59
|
+
pattern = nil if pattern&.empty?
|
60
|
+
|
61
|
+
# NOTE: If rails can't recognize the request, we are going to fallback
|
62
|
+
# to generic request path
|
63
|
+
(pattern || request.path).delete_suffix(RAILS_FORMAT_SUFFIX)
|
64
|
+
else
|
65
|
+
request.path
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'zlib'
|
4
|
+
require_relative 'lru_cache'
|
5
|
+
require_relative 'route_extractor'
|
6
|
+
require_relative '../../core/utils/time'
|
7
|
+
|
8
|
+
module Datadog
|
9
|
+
module AppSec
|
10
|
+
module APISecurity
|
11
|
+
# A thread-local sampler for API security based on defined delay between
|
12
|
+
# samples with caching capability.
|
13
|
+
class Sampler
|
14
|
+
THREAD_KEY = :datadog_appsec_api_security_sampler
|
15
|
+
MAX_CACHE_SIZE = 4096
|
16
|
+
|
17
|
+
class << self
|
18
|
+
def thread_local
|
19
|
+
sampler = Thread.current.thread_variable_get(THREAD_KEY)
|
20
|
+
return sampler unless sampler.nil?
|
21
|
+
|
22
|
+
Thread.current.thread_variable_set(THREAD_KEY, new(sample_delay))
|
23
|
+
end
|
24
|
+
|
25
|
+
# @api private
|
26
|
+
def reset!
|
27
|
+
Thread.current.thread_variable_set(THREAD_KEY, nil)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def sample_delay
|
33
|
+
Datadog.configuration.appsec.api_security.sample_delay
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def initialize(sample_delay)
|
38
|
+
raise ArgumentError, 'sample_delay must be an Integer' unless sample_delay.is_a?(Integer)
|
39
|
+
|
40
|
+
@cache = LRUCache.new(MAX_CACHE_SIZE)
|
41
|
+
@sample_delay_seconds = sample_delay
|
42
|
+
end
|
43
|
+
|
44
|
+
def sample?(request, response)
|
45
|
+
return true if @sample_delay_seconds.zero?
|
46
|
+
|
47
|
+
key = Zlib.crc32("#{request.request_method}#{RouteExtractor.route_pattern(request)}#{response.status}")
|
48
|
+
current_timestamp = Core::Utils::Time.now.to_i
|
49
|
+
cached_timestamp = @cache[key] || 0
|
50
|
+
|
51
|
+
return false if current_timestamp - cached_timestamp <= @sample_delay_seconds
|
52
|
+
|
53
|
+
@cache.store(key, current_timestamp)
|
54
|
+
true
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -1,9 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'api_security/sampler'
|
4
|
+
|
3
5
|
module Datadog
|
4
6
|
module AppSec
|
5
7
|
# A namespace for API Security features.
|
6
8
|
module APISecurity
|
9
|
+
def self.enabled?
|
10
|
+
Datadog.configuration.appsec.api_security.enabled?
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.sample?(request, response)
|
14
|
+
Sampler.thread_local.sample?(request, response)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.sample_trace?(trace)
|
18
|
+
# NOTE: Reads as "if trace is priority sampled or if in standalone mode"
|
19
|
+
trace&.priority_sampled? || !Datadog.configuration.apm.tracing.enabled
|
20
|
+
end
|
7
21
|
end
|
8
22
|
end
|
9
23
|
end
|