diff --git a/.circleci/config.yml b/.circleci/config.yml index ed9caf20e38..6aabbeeb7f8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -65,7 +65,7 @@ save_bundle_checksum: &save_bundle_checksum command: | if [ "$CI_BUNDLE_CACHE_HIT" != 1 ]; then # Recompute gemfiles/*.lock checksum, as those files might have changed - cat Gemfile Gemfile.lock Appraisals gemfiles/*.gemfile gemfiles/*.gemfile.lock | md5sum > .circleci/bundle_checksum + cat Gemfile Gemfile.lock ruby-*.gemfile gemfiles/*.gemfile gemfiles/*.gemfile.lock | md5sum > .circleci/bundle_checksum fi cp .circleci/bundle_checksum /usr/local/bundle/bundle_checksum step_bundle_install: &step_bundle_install @@ -96,7 +96,7 @@ step_compute_bundle_checksum: &step_compute_bundle_checksum # updating the gemset lock files produces extremely large commits. command: | bundle lock # Create Gemfile.lock - cat Gemfile Gemfile.lock Appraisals gemfiles/*.gemfile gemfiles/*.gemfile.lock | md5sum > .circleci/bundle_checksum + cat Gemfile Gemfile.lock ruby-*.gemfile gemfiles/*.gemfile gemfiles/*.gemfile.lock | md5sum > .circleci/bundle_checksum step_get_test_agent_trace_check_results: &step_get_test_agent_trace_check_results run: name: Get APM Test Agent Trace Check Results diff --git a/.github/workflows/test-memory-leaks.yaml b/.github/workflows/test-memory-leaks.yaml index e1842cb38b6..44d7cb094bf 100644 --- a/.github/workflows/test-memory-leaks.yaml +++ b/.github/workflows/test-memory-leaks.yaml @@ -7,10 +7,10 @@ jobs: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 with: - ruby-version: 3.4.0-preview2 # TODO: Use stable version once 3.4 is out + ruby-version: 3.4.1 bundler-cache: true # runs 'bundle install' and caches installed gems automatically bundler: latest - cache-version: v1 # bump this to invalidate cache + cache-version: v2 # bump this to invalidate cache - run: sudo apt-get update && (sudo apt-get install -y valgrind || sleep 5 && sudo apt-get install -y valgrind) && valgrind --version - run: gem update --system 3.5.23 # TODO: This is a workaround for a buggy rubygems in 3.4.0-preview2; remove once stable version 3.4 is out - run: bundle exec rake compile spec:profiling:memcheck diff --git a/Steepfile b/Steepfile index 24d49808692..d2cce9c3ef6 100644 --- a/Steepfile +++ b/Steepfile @@ -80,7 +80,6 @@ target :datadog do ignore 'lib/datadog/core/buffer/thread_safe.rb' ignore 'lib/datadog/core/chunker.rb' ignore 'lib/datadog/core/configuration.rb' - ignore 'lib/datadog/core/configuration/agent_settings_resolver.rb' ignore 'lib/datadog/core/configuration/base.rb' ignore 'lib/datadog/core/configuration/components.rb' ignore 'lib/datadog/core/configuration/dependency_resolver.rb' diff --git a/appraisal/ruby-3.3.rb b/appraisal/ruby-3.3.rb index d361fcd68a7..c7fffc3b558 100644 --- a/appraisal/ruby-3.3.rb +++ b/appraisal/ruby-3.3.rb @@ -180,8 +180,6 @@ gem 'dalli', '< 3.0.0' gem 'presto-client', '>= 0.5.14' # Renamed to trino-client in >= 1.0 gem 'qless', '0.12.0' - - gem 'racc' # Remove this once graphql resolves issue for ruby 3.3 preview. https://github.com/rmosolgo/graphql-ruby/issues/4650 end appraise 'core-old' do diff --git a/appraisal/ruby-3.4.rb b/appraisal/ruby-3.4.rb index e83945820bc..17a81807b66 100644 --- a/appraisal/ruby-3.4.rb +++ b/appraisal/ruby-3.4.rb @@ -191,8 +191,6 @@ gem 'dalli', '< 3.0.0' gem 'presto-client', '>= 0.5.14' # Renamed to trino-client in >= 1.0 gem 'qless', '0.12.0' - - gem 'racc' # Remove this once graphql resolves issue for ruby 3.3 preview. https://github.com/rmosolgo/graphql-ruby/issues/4650 end appraise 'core-old' do diff --git a/benchmarks/profiler_gc.rb b/benchmarks/profiler_gc.rb index e96198cdfba..401af152d84 100644 --- a/benchmarks/profiler_gc.rb +++ b/benchmarks/profiler_gc.rb @@ -14,7 +14,7 @@ def create_profiler # We take a dummy sample so that the context for the main thread is created, as otherwise the GC profiling methods do # not create it (because we don't want to do memory allocations in the middle of GC) - Datadog::Profiling::Collectors::ThreadContext::Testing._native_sample(@collector, Thread.current) + Datadog::Profiling::Collectors::ThreadContext::Testing._native_sample(@collector, Thread.current, false) end def run_benchmark @@ -29,7 +29,7 @@ def run_benchmark x.report('profiler gc') do Datadog::Profiling::Collectors::ThreadContext::Testing._native_on_gc_start(@collector) Datadog::Profiling::Collectors::ThreadContext::Testing._native_on_gc_finish(@collector) - Datadog::Profiling::Collectors::ThreadContext::Testing._native_sample_after_gc(@collector, false) + Datadog::Profiling::Collectors::ThreadContext::Testing._native_sample_after_gc(@collector, false, false) end x.save! "#{File.basename(__FILE__)}-results.json" unless VALIDATE_BENCHMARK_MODE @@ -52,7 +52,7 @@ def run_benchmark estimated_gc_per_minute.times do Datadog::Profiling::Collectors::ThreadContext::Testing._native_on_gc_start(@collector) Datadog::Profiling::Collectors::ThreadContext::Testing._native_on_gc_finish(@collector) - Datadog::Profiling::Collectors::ThreadContext::Testing._native_sample_after_gc(@collector, false) + Datadog::Profiling::Collectors::ThreadContext::Testing._native_sample_after_gc(@collector, false, false) end @recorder.serialize diff --git a/benchmarks/profiler_sample_gvl.rb b/benchmarks/profiler_sample_gvl.rb index 76e8528f417..7688730b714 100644 --- a/benchmarks/profiler_sample_gvl.rb +++ b/benchmarks/profiler_sample_gvl.rb @@ -27,7 +27,7 @@ def initialize @target_thread = thread_with_very_deep_stack # Sample once to trigger thread context creation for all threads (including @target_thread) - Datadog::Profiling::Collectors::ThreadContext::Testing._native_sample(@collector, PROFILER_OVERHEAD_STACK_THREAD) + Datadog::Profiling::Collectors::ThreadContext::Testing._native_sample(@collector, PROFILER_OVERHEAD_STACK_THREAD, false) end def create_profiler diff --git a/benchmarks/profiler_sample_loop_v2.rb b/benchmarks/profiler_sample_loop_v2.rb index e007375cf6c..624f29bad25 100644 --- a/benchmarks/profiler_sample_loop_v2.rb +++ b/benchmarks/profiler_sample_loop_v2.rb @@ -37,7 +37,7 @@ def run_benchmark ) x.report("stack collector #{ENV['CONFIG']}") do - Datadog::Profiling::Collectors::ThreadContext::Testing._native_sample(@collector, PROFILER_OVERHEAD_STACK_THREAD) + Datadog::Profiling::Collectors::ThreadContext::Testing._native_sample(@collector, PROFILER_OVERHEAD_STACK_THREAD, false) end x.save! "#{File.basename(__FILE__)}-results.json" unless VALIDATE_BENCHMARK_MODE diff --git a/benchmarks/profiler_sample_serialize.rb b/benchmarks/profiler_sample_serialize.rb index 47ae1b6854a..b90997c42d5 100644 --- a/benchmarks/profiler_sample_serialize.rb +++ b/benchmarks/profiler_sample_serialize.rb @@ -35,7 +35,7 @@ def run_benchmark simulate_seconds = 60 (samples_per_second * simulate_seconds).times do - Datadog::Profiling::Collectors::ThreadContext::Testing._native_sample(@collector, PROFILER_OVERHEAD_STACK_THREAD) + Datadog::Profiling::Collectors::ThreadContext::Testing._native_sample(@collector, PROFILER_OVERHEAD_STACK_THREAD, false) end @recorder.serialize diff --git a/docs/Compatibility.md b/docs/Compatibility.md index 7334f2254a9..6dbcf8e5e12 100644 --- a/docs/Compatibility.md +++ b/docs/Compatibility.md @@ -9,7 +9,8 @@ The Ruby Datadog Trace library is open source. See the [dd-trace-rb][1] GitHub r | Type | Documentation | Version | Support type | Gem version support | |-------|----------------------------|-----------|---------------------------|---------------------| -| MRI | https://www.ruby-lang.org/ | 3.3 | [latest](#support-latest) | Latest | +| MRI | https://www.ruby-lang.org/ | 3.4 | [latest](#support-latest) | Latest | +| | | 3.3 | [latest](#support-latest) | Latest | | | | 3.2 | [latest](#support-latest) | Latest | | | | 3.1 | [latest](#support-latest) | Latest | | | | 3.0 | [latest](#support-latest) | Latest | diff --git a/docs/DevelopmentGuide.md b/docs/DevelopmentGuide.md index adf99bc3e7d..f3f07ec21b2 100644 --- a/docs/DevelopmentGuide.md +++ b/docs/DevelopmentGuide.md @@ -65,9 +65,9 @@ All tests should run in CI. When adding new `_spec.rb` files, you may need to ad { 'foo' => { # With default dependencies for each Ruby runtime - '' => '✅ 2.1 / ✅ 2.2 / ✅ 2.3 / ✅ 2.4 / ✅ 2.5 / ✅ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ 3.3 / ✅ jruby', + '' => '✅ 2.1 / ✅ 2.2 / ✅ 2.3 / ✅ 2.4 / ✅ 2.5 / ✅ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ 3.3 / ✅ 3.4 / ✅ jruby', # or with dependency group definition `foo-on-rails`, that includes additional gems - 'foo-on-rails' => '✅ 2.1 / ✅ 2.2 / ✅ 2.3 / ✅ 2.4 / ✅ 2.5 / ✅ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ 3.3 / ✅ jruby' + 'foo-on-rails' => '✅ 2.1 / ✅ 2.2 / ✅ 2.3 / ✅ 2.4 / ✅ 2.5 / ✅ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ 3.3 / ✅ 3.4 / ✅ jruby' }, } ``` @@ -98,9 +98,9 @@ Take `bundle exec rake test:redis` as example, multiple versions of `redis` from ```ruby { 'redis' => { - 'redis-3' => '✅ 2.1 / ✅ 2.2 / ✅ 2.3 / ✅ 2.4 / ✅ 2.5 / ✅ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ 3.3 / ✅ jruby', - 'redis-4' => '❌ 2.1 / ❌ 2.2 / ❌ 2.3 / ✅ 2.4 / ✅ 2.5 / ✅ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ 3.3 / ✅ jruby', - 'redis-5' => '❌ 2.1 / ❌ 2.2 / ❌ 2.3 / ❌ 2.4 / ✅ 2.5 / ✅ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ 3.3 / ✅ jruby' + 'redis-3' => '✅ 2.5 / ✅ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ 3.3 / ✅ 3.4 / ✅ jruby', + 'redis-4' => '✅ 2.5 / ✅ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ 3.3 / ✅ 3.4 / ✅ jruby', + 'redis-5' => '✅ 2.5 / ✅ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ 3.3 / ✅ 3.4 / ✅ jruby' } } ``` @@ -223,12 +223,31 @@ https://github.com/datadog/dd-apm-test-agent#readme **Linting** -The trace library uses Rubocop to enforce [code style](https://github.com/bbatsov/ruby-style-guide) and quality. To check, run: +Most of the library uses Rubocop to enforce [code style](https://github.com/bbatsov/ruby-style-guide) and quality. To check, run: ``` $ bundle exec rake rubocop ``` +To change your code to the version that rubocop wants, run: + +``` +$ bundle exec rake rubocop -A +``` + +Profiling and Dynamic Instrumentation use [standard](https://github.com/standardrb/standard) +instead of Rubocop. To check files with standard, run: + +``` +$ bundle exec rake standard +``` + +To change your code to the version that standard wants, run: + +``` +$ bundle exec rake standard:fix +``` + ## Appendix ### Writing new integrations diff --git a/docs/GettingStarted.md b/docs/GettingStarted.md index 894903047bd..9262b29bcb4 100644 --- a/docs/GettingStarted.md +++ b/docs/GettingStarted.md @@ -1547,11 +1547,10 @@ Rake::Task['my_task'].invoke | Key | Env Var| Type | Description | Default | | -------------- | - | ------- | -------------------------------------------------------------------------------------------------------- | -------- | -| `enabled` | | `Bool` | Defines whether Rake tasks should be traced. Useful for temporarily disabling tracing. `true` or `false` | `true` | +| `enabled` | `DD_TRACE_RAKE_ENABLED` | `Bool` | Defines whether Rake tasks should be traced. Useful for temporarily disabling tracing. `true` or `false` | `true` | | `quantize` | | `Hash` | Hash containing options for quantization of task arguments. See below for more details and examples. | `{}` | | `service_name` | | `String` | Service name used for `rake` instrumentation | `'rake'` | | `tasks` | | `Array` | Names of the Rake tasks to instrument | `[]` | -| `enabled` | `DD_TRACE_RAKE_ENABLED` | `Bool` | Whether the integration should create spans. | `true` | **Configuring task quantization behavior** diff --git a/ext/datadog_profiling_native_extension/clock_id.h b/ext/datadog_profiling_native_extension/clock_id.h index b302380eab7..f02bcd5bd1b 100644 --- a/ext/datadog_profiling_native_extension/clock_id.h +++ b/ext/datadog_profiling_native_extension/clock_id.h @@ -5,13 +5,13 @@ #include // Contains the operating-system specific identifier needed to fetch CPU-time, and a flag to indicate if we failed to fetch it -typedef struct thread_cpu_time_id { +typedef struct { bool valid; clockid_t clock_id; } thread_cpu_time_id; // Contains the current cpu time, and a flag to indicate if we failed to fetch it -typedef struct thread_cpu_time { +typedef struct { bool valid; long result_ns; } thread_cpu_time; diff --git a/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c b/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c index e4e9b69473e..e40c2a1a14e 100644 --- a/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +++ b/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c @@ -92,7 +92,7 @@ unsigned int MAX_ALLOC_WEIGHT = 10000; #endif // Contains state for a single CpuAndWallTimeWorker instance -struct cpu_and_wall_time_worker_state { +typedef struct { // These are immutable after initialization bool gc_profiling_enabled; @@ -187,7 +187,7 @@ struct cpu_and_wall_time_worker_state { uint64_t gvl_sampling_time_ns_max; uint64_t gvl_sampling_time_ns_total; } stats; -}; +} cpu_and_wall_time_worker_state; static VALUE _native_new(VALUE klass); static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self); @@ -195,7 +195,7 @@ static void cpu_and_wall_time_worker_typed_data_mark(void *state_ptr); static VALUE _native_sampling_loop(VALUE self, VALUE instance); static VALUE _native_stop(DDTRACE_UNUSED VALUE _self, VALUE self_instance, VALUE worker_thread); static VALUE stop(VALUE self_instance, VALUE optional_exception); -static void stop_state(struct cpu_and_wall_time_worker_state *state, VALUE optional_exception); +static void stop_state(cpu_and_wall_time_worker_state *state, VALUE optional_exception); static void handle_sampling_signal(DDTRACE_UNUSED int _signal, DDTRACE_UNUSED siginfo_t *_info, DDTRACE_UNUSED void *_ucontext); static void *run_sampling_trigger_loop(void *state_ptr); static void interrupt_sampling_trigger_loop(void *state_ptr); @@ -221,14 +221,14 @@ static VALUE _native_stats(DDTRACE_UNUSED VALUE self, VALUE instance); static VALUE _native_stats_reset_not_thread_safe(DDTRACE_UNUSED VALUE self, VALUE instance); void *simulate_sampling_signal_delivery(DDTRACE_UNUSED void *_unused); static void grab_gvl_and_sample(void); -static void reset_stats_not_thread_safe(struct cpu_and_wall_time_worker_state *state); +static void reset_stats_not_thread_safe(cpu_and_wall_time_worker_state *state); static void sleep_for(uint64_t time_ns); static VALUE _native_allocation_count(DDTRACE_UNUSED VALUE self); static void on_newobj_event(DDTRACE_UNUSED VALUE unused1, DDTRACE_UNUSED void *unused2); -static void disable_tracepoints(struct cpu_and_wall_time_worker_state *state); +static void disable_tracepoints(cpu_and_wall_time_worker_state *state); static VALUE _native_with_blocked_sigprof(DDTRACE_UNUSED VALUE self); static VALUE rescued_sample_allocation(VALUE tracepoint_data); -static void delayed_error(struct cpu_and_wall_time_worker_state *state, const char *error); +static void delayed_error(cpu_and_wall_time_worker_state *state, const char *error); static VALUE _native_delayed_error(DDTRACE_UNUSED VALUE self, VALUE instance, VALUE error_msg); static VALUE _native_hold_signals(DDTRACE_UNUSED VALUE self); static VALUE _native_resume_signals(DDTRACE_UNUSED VALUE self); @@ -262,7 +262,7 @@ static VALUE _native_gvl_profiling_hook_active(DDTRACE_UNUSED VALUE self, VALUE // This global state is needed because a bunch of functions on this file need to access it from situations // (e.g. signal handler) where it's impossible or just awkward to pass it as an argument. static VALUE active_sampler_instance = Qnil; -static struct cpu_and_wall_time_worker_state *active_sampler_instance_state = NULL; +static cpu_and_wall_time_worker_state *active_sampler_instance_state = NULL; // See handle_sampling_signal for details on what this does #ifdef NO_POSTPONED_TRIGGER @@ -334,7 +334,7 @@ void collectors_cpu_and_wall_time_worker_init(VALUE profiling_module) { rb_define_singleton_method(testing_module, "_native_gvl_profiling_hook_active", _native_gvl_profiling_hook_active, 1); } -// This structure is used to define a Ruby object that stores a pointer to a struct cpu_and_wall_time_worker_state +// This structure is used to define a Ruby object that stores a pointer to a cpu_and_wall_time_worker_state // See also https://github.com/ruby/ruby/blob/master/doc/extension.rdoc for how this works static const rb_data_type_t cpu_and_wall_time_worker_typed_data = { .wrap_struct_name = "Datadog::Profiling::Collectors::CpuAndWallTimeWorker", @@ -350,7 +350,7 @@ static const rb_data_type_t cpu_and_wall_time_worker_typed_data = { static VALUE _native_new(VALUE klass) { long now = monotonic_wall_time_now_ns(RAISE_ON_FAILURE); - struct cpu_and_wall_time_worker_state *state = ruby_xcalloc(1, sizeof(struct cpu_and_wall_time_worker_state)); + cpu_and_wall_time_worker_state *state = ruby_xcalloc(1, sizeof(cpu_and_wall_time_worker_state)); // Note: Any exceptions raised from this note until the TypedData_Wrap_Struct call will lead to the state memory // being leaked. @@ -414,8 +414,8 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel ENFORCE_BOOLEAN(gvl_profiling_enabled); ENFORCE_BOOLEAN(skip_idle_samples_for_testing) - struct cpu_and_wall_time_worker_state *state; - TypedData_Get_Struct(self_instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state); + cpu_and_wall_time_worker_state *state; + TypedData_Get_Struct(self_instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state); state->gc_profiling_enabled = (gc_profiling_enabled == Qtrue); state->no_signals_workaround_enabled = (no_signals_workaround_enabled == Qtrue); @@ -445,7 +445,7 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel // Since our state contains references to Ruby objects, we need to tell the Ruby GC about them static void cpu_and_wall_time_worker_typed_data_mark(void *state_ptr) { - struct cpu_and_wall_time_worker_state *state = (struct cpu_and_wall_time_worker_state *) state_ptr; + cpu_and_wall_time_worker_state *state = (cpu_and_wall_time_worker_state *) state_ptr; rb_gc_mark(state->thread_context_collector_instance); rb_gc_mark(state->idle_sampling_helper_instance); @@ -457,8 +457,8 @@ static void cpu_and_wall_time_worker_typed_data_mark(void *state_ptr) { // Called in a background thread created in CpuAndWallTimeWorker#start static VALUE _native_sampling_loop(DDTRACE_UNUSED VALUE _self, VALUE instance) { - struct cpu_and_wall_time_worker_state *state; - TypedData_Get_Struct(instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state); + cpu_and_wall_time_worker_state *state; + TypedData_Get_Struct(instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state); // If we already got a delayed exception registered even before starting, raise before starting if (state->failure_exception != Qnil) { @@ -466,7 +466,7 @@ static VALUE _native_sampling_loop(DDTRACE_UNUSED VALUE _self, VALUE instance) { rb_exc_raise(state->failure_exception); } - struct cpu_and_wall_time_worker_state *old_state = active_sampler_instance_state; + cpu_and_wall_time_worker_state *old_state = active_sampler_instance_state; if (old_state != NULL) { if (is_thread_alive(old_state->owner_thread)) { rb_raise( @@ -546,15 +546,15 @@ static VALUE _native_sampling_loop(DDTRACE_UNUSED VALUE _self, VALUE instance) { } static VALUE _native_stop(DDTRACE_UNUSED VALUE _self, VALUE self_instance, VALUE worker_thread) { - struct cpu_and_wall_time_worker_state *state; - TypedData_Get_Struct(self_instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state); + cpu_and_wall_time_worker_state *state; + TypedData_Get_Struct(self_instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state); state->stop_thread = worker_thread; return stop(self_instance, /* optional_exception: */ Qnil); } -static void stop_state(struct cpu_and_wall_time_worker_state *state, VALUE optional_exception) { +static void stop_state(cpu_and_wall_time_worker_state *state, VALUE optional_exception) { atomic_store(&state->should_run, false); state->failure_exception = optional_exception; @@ -563,8 +563,8 @@ static void stop_state(struct cpu_and_wall_time_worker_state *state, VALUE optio } static VALUE stop(VALUE self_instance, VALUE optional_exception) { - struct cpu_and_wall_time_worker_state *state; - TypedData_Get_Struct(self_instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state); + cpu_and_wall_time_worker_state *state; + TypedData_Get_Struct(self_instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state); stop_state(state, optional_exception); @@ -575,7 +575,7 @@ static VALUE stop(VALUE self_instance, VALUE optional_exception) { // We need to be careful not to change any state that may be observed OR to restore it if we do. For instance, if anything // we do here can set `errno`, then we must be careful to restore the old `errno` after the fact. static void handle_sampling_signal(DDTRACE_UNUSED int _signal, DDTRACE_UNUSED siginfo_t *_info, DDTRACE_UNUSED void *_ucontext) { - struct cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above + cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above // This can potentially happen if the CpuAndWallTimeWorker was stopped while the signal delivery was happening; nothing to do if (state == NULL) return; @@ -650,7 +650,7 @@ static void handle_sampling_signal(DDTRACE_UNUSED int _signal, DDTRACE_UNUSED si // The actual sampling trigger loop always runs **without** the global vm lock. static void *run_sampling_trigger_loop(void *state_ptr) { - struct cpu_and_wall_time_worker_state *state = (struct cpu_and_wall_time_worker_state *) state_ptr; + cpu_and_wall_time_worker_state *state = (cpu_and_wall_time_worker_state *) state_ptr; uint64_t minimum_time_between_signals = MILLIS_AS_NS(10); @@ -709,13 +709,13 @@ static void *run_sampling_trigger_loop(void *state_ptr) { // This is called by the Ruby VM when it wants to shut down the background thread static void interrupt_sampling_trigger_loop(void *state_ptr) { - struct cpu_and_wall_time_worker_state *state = (struct cpu_and_wall_time_worker_state *) state_ptr; + cpu_and_wall_time_worker_state *state = (cpu_and_wall_time_worker_state *) state_ptr; atomic_store(&state->should_run, false); } static void sample_from_postponed_job(DDTRACE_UNUSED void *_unused) { - struct cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above + cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above // This can potentially happen if the CpuAndWallTimeWorker was stopped while the postponed job was waiting to be executed; nothing to do if (state == NULL) return; @@ -735,8 +735,8 @@ static void sample_from_postponed_job(DDTRACE_UNUSED void *_unused) { } static VALUE rescued_sample_from_postponed_job(VALUE self_instance) { - struct cpu_and_wall_time_worker_state *state; - TypedData_Get_Struct(self_instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state); + cpu_and_wall_time_worker_state *state; + TypedData_Get_Struct(self_instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state); long wall_time_ns_before_sample = monotonic_wall_time_now_ns(RAISE_ON_FAILURE); @@ -791,8 +791,8 @@ static VALUE _native_current_sigprof_signal_handler(DDTRACE_UNUSED VALUE self) { } static VALUE release_gvl_and_run_sampling_trigger_loop(VALUE instance) { - struct cpu_and_wall_time_worker_state *state; - TypedData_Get_Struct(instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state); + cpu_and_wall_time_worker_state *state; + TypedData_Get_Struct(instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state); // Final preparations: Setup signal handler and enable tracepoints. We run these here and not in `_native_sampling_loop` // because they may raise exceptions. @@ -842,7 +842,7 @@ static VALUE release_gvl_and_run_sampling_trigger_loop(VALUE instance) { // This method exists only to enable testing Datadog::Profiling::Collectors::CpuAndWallTimeWorker behavior using RSpec. // It SHOULD NOT be used for other purposes. static VALUE _native_is_running(DDTRACE_UNUSED VALUE self, VALUE instance) { - struct cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above + cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above return (state != NULL && is_thread_alive(state->owner_thread) && state->self_instance == instance) ? Qtrue : Qfalse; } @@ -875,8 +875,8 @@ static VALUE _native_trigger_sample(DDTRACE_UNUSED VALUE self) { // This method exists only to enable testing Datadog::Profiling::Collectors::CpuAndWallTimeWorker behavior using RSpec. // It SHOULD NOT be used for other purposes. static VALUE _native_gc_tracepoint(DDTRACE_UNUSED VALUE self, VALUE instance) { - struct cpu_and_wall_time_worker_state *state; - TypedData_Get_Struct(instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state); + cpu_and_wall_time_worker_state *state; + TypedData_Get_Struct(instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state); return state->gc_tracepoint; } @@ -902,7 +902,7 @@ static void on_gc_event(VALUE tracepoint_data, DDTRACE_UNUSED void *unused) { int event = rb_tracearg_event_flag(rb_tracearg_from_tracepoint(tracepoint_data)); if (event != RUBY_INTERNAL_EVENT_GC_ENTER && event != RUBY_INTERNAL_EVENT_GC_EXIT) return; // Unknown event - struct cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above + cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above // This should not happen in a normal situation because the tracepoint is always enabled after the instance is set // and disabled before it is cleared, but just in case... @@ -926,7 +926,7 @@ static void on_gc_event(VALUE tracepoint_data, DDTRACE_UNUSED void *unused) { } static void after_gc_from_postponed_job(DDTRACE_UNUSED void *_unused) { - struct cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above + cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above // This can potentially happen if the CpuAndWallTimeWorker was stopped while the postponed job was waiting to be executed; nothing to do if (state == NULL) return; @@ -981,8 +981,8 @@ static VALUE _native_simulate_sample_from_postponed_job(DDTRACE_UNUSED VALUE sel // In the future, if we add more other components with tracepoints, we will need to coordinate stopping all such // tracepoints before doing the other cleaning steps. static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE instance) { - struct cpu_and_wall_time_worker_state *state; - TypedData_Get_Struct(instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state); + cpu_and_wall_time_worker_state *state; + TypedData_Get_Struct(instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state); // Disable all tracepoints, so that there are no more attempts to mutate the profile disable_tracepoints(state); @@ -1000,8 +1000,8 @@ static VALUE _native_is_sigprof_blocked_in_current_thread(DDTRACE_UNUSED VALUE s } static VALUE _native_stats(DDTRACE_UNUSED VALUE self, VALUE instance) { - struct cpu_and_wall_time_worker_state *state; - TypedData_Get_Struct(instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state); + cpu_and_wall_time_worker_state *state; + TypedData_Get_Struct(instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state); unsigned long total_cpu_samples_attempted = state->stats.cpu_sampled + state->stats.cpu_skipped; VALUE effective_cpu_sample_rate = @@ -1059,14 +1059,14 @@ static VALUE _native_stats(DDTRACE_UNUSED VALUE self, VALUE instance) { } static VALUE _native_stats_reset_not_thread_safe(DDTRACE_UNUSED VALUE self, VALUE instance) { - struct cpu_and_wall_time_worker_state *state; - TypedData_Get_Struct(instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state); + cpu_and_wall_time_worker_state *state; + TypedData_Get_Struct(instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state); reset_stats_not_thread_safe(state); return Qnil; } void *simulate_sampling_signal_delivery(DDTRACE_UNUSED void *_unused) { - struct cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above + cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above // This can potentially happen if the CpuAndWallTimeWorker was stopped while the IdleSamplingHelper was trying to execute this action if (state == NULL) return NULL; @@ -1082,7 +1082,7 @@ void *simulate_sampling_signal_delivery(DDTRACE_UNUSED void *_unused) { static void grab_gvl_and_sample(void) { rb_thread_call_with_gvl(simulate_sampling_signal_delivery, NULL); } -static void reset_stats_not_thread_safe(struct cpu_and_wall_time_worker_state *state) { +static void reset_stats_not_thread_safe(cpu_and_wall_time_worker_state *state) { // NOTE: This is not really thread safe so ongoing sampling operations that are concurrent with a reset can have their stats: // * Lost (writes after stats retrieval but before reset). // * Included in the previous stats window (writes before stats retrieval and reset). @@ -1116,7 +1116,7 @@ static void sleep_for(uint64_t time_ns) { } static VALUE _native_allocation_count(DDTRACE_UNUSED VALUE self) { - struct cpu_and_wall_time_worker_state *state = active_sampler_instance_state; + cpu_and_wall_time_worker_state *state = active_sampler_instance_state; bool are_allocations_being_tracked = state != NULL && state->allocation_profiling_enabled && state->allocation_counting_enabled; @@ -1149,7 +1149,7 @@ static VALUE _native_allocation_count(DDTRACE_UNUSED VALUE self) { // call `rb_tracearg_from_tracepoint(anything)` anywhere during this function or its callees to get the data, so that's // why it's not being passed as an argument. static void on_newobj_event(DDTRACE_UNUSED VALUE unused1, DDTRACE_UNUSED void *unused2) { - struct cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above + cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above // This should not happen in a normal situation because the tracepoint is always enabled after the instance is set // and disabled before it is cleared, but just in case... @@ -1171,6 +1171,16 @@ static void on_newobj_event(DDTRACE_UNUSED VALUE unused1, DDTRACE_UNUSED void *u return; } + // If Ruby is in the middle of raising an exception, we don't want to try to sample. This is because if we accidentally + // trigger an exception inside the profiler code, bad things will happen (specifically, Ruby will try to kill off the + // thread even though we may try to catch the exception). + // + // Note that "in the middle of raising an exception" means the exception itself has already been allocated. + // What's getting allocated now is probably the backtrace objects (@ivoanjo or at least that's what I've observed) + if (is_raised_flag_set(rb_thread_current())) { + return; + } + // Hot path: Dynamic sampling rate is usually enabled and the sampling decision is usually false if (RB_LIKELY(state->dynamic_sampling_rate_enabled && !discrete_dynamic_sampler_should_sample(&state->allocation_sampler))) { state->stats.allocation_skipped++; @@ -1225,7 +1235,7 @@ static void on_newobj_event(DDTRACE_UNUSED VALUE unused1, DDTRACE_UNUSED void *u state->during_sample = false; } -static void disable_tracepoints(struct cpu_and_wall_time_worker_state *state) { +static void disable_tracepoints(cpu_and_wall_time_worker_state *state) { if (state->gc_tracepoint != Qnil) { rb_tracepoint_disable(state->gc_tracepoint); } @@ -1254,7 +1264,7 @@ static VALUE _native_with_blocked_sigprof(DDTRACE_UNUSED VALUE self) { } static VALUE rescued_sample_allocation(DDTRACE_UNUSED VALUE unused) { - struct cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above + cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above // This should not happen in a normal situation because on_newobj_event already checked for this, but just in case... if (state == NULL) return Qnil; @@ -1283,7 +1293,7 @@ static VALUE rescued_sample_allocation(DDTRACE_UNUSED VALUE unused) { return Qnil; } -static void delayed_error(struct cpu_and_wall_time_worker_state *state, const char *error) { +static void delayed_error(cpu_and_wall_time_worker_state *state, const char *error) { // If we can't raise an immediate exception at the calling site, use the asynchronous flow through the main worker loop. stop_state(state, rb_exc_new_cstr(rb_eRuntimeError, error)); } @@ -1291,8 +1301,8 @@ static void delayed_error(struct cpu_and_wall_time_worker_state *state, const ch static VALUE _native_delayed_error(DDTRACE_UNUSED VALUE self, VALUE instance, VALUE error_msg) { ENFORCE_TYPE(error_msg, T_STRING); - struct cpu_and_wall_time_worker_state *state; - TypedData_Get_Struct(instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state); + cpu_and_wall_time_worker_state *state; + TypedData_Get_Struct(instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state); delayed_error(state, rb_string_value_cstr(&error_msg)); @@ -1345,7 +1355,7 @@ static VALUE _native_resume_signals(DDTRACE_UNUSED VALUE self) { rb_postponed_job_register_one(0, after_gvl_running_from_postponed_job, NULL); #endif } else if (result == ON_GVL_RUNNING_DONT_SAMPLE) { - struct cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above + cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above if (state == NULL) return; // This should not happen, but just in case... @@ -1358,7 +1368,7 @@ static VALUE _native_resume_signals(DDTRACE_UNUSED VALUE self) { } static void after_gvl_running_from_postponed_job(DDTRACE_UNUSED void *_unused) { - struct cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above + cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above // This can potentially happen if the CpuAndWallTimeWorker was stopped while the postponed job was waiting to be executed; nothing to do if (state == NULL) return; @@ -1372,8 +1382,8 @@ static VALUE _native_resume_signals(DDTRACE_UNUSED VALUE self) { } static VALUE rescued_after_gvl_running_from_postponed_job(VALUE self_instance) { - struct cpu_and_wall_time_worker_state *state; - TypedData_Get_Struct(self_instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state); + cpu_and_wall_time_worker_state *state; + TypedData_Get_Struct(self_instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state); long wall_time_ns_before_sample = monotonic_wall_time_now_ns(RAISE_ON_FAILURE); thread_context_collector_sample_after_gvl_running(state->thread_context_collector_instance, rb_thread_current(), wall_time_ns_before_sample); @@ -1394,8 +1404,8 @@ static VALUE _native_resume_signals(DDTRACE_UNUSED VALUE self) { } static VALUE _native_gvl_profiling_hook_active(DDTRACE_UNUSED VALUE self, VALUE instance) { - struct cpu_and_wall_time_worker_state *state; - TypedData_Get_Struct(instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state); + cpu_and_wall_time_worker_state *state; + TypedData_Get_Struct(instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state); return state->gvl_profiling_hook != NULL ? Qtrue : Qfalse; } diff --git a/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c b/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c index 25fcb0b3dbe..d310d3ca993 100644 --- a/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +++ b/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c @@ -333,7 +333,7 @@ static VALUE _native_should_sample(VALUE self, VALUE now); static VALUE _native_after_sample(VALUE self, VALUE now); static VALUE _native_state_snapshot(VALUE self); -typedef struct sampler_state { +typedef struct { discrete_dynamic_sampler sampler; } sampler_state; diff --git a/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h b/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h index 7e1edfb5c42..1c0b0aedb2c 100644 --- a/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h +++ b/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h @@ -16,7 +16,7 @@ // every event and is thus, in theory, susceptible to some pattern // biases. In practice, the dynamic readjustment of sampling interval // and randomized starting point should help with avoiding heavy biases. -typedef struct discrete_dynamic_sampler { +typedef struct { // --- Config --- // Name of this sampler for debug logs. const char *debug_name; diff --git a/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c b/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c index a34a81feaf2..fcbc42eaa94 100644 --- a/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +++ b/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c @@ -21,15 +21,15 @@ typedef enum { ACTION_WAIT, ACTION_RUN, ACTION_STOP } action; // Contains state for a single CpuAndWallTimeWorker instance -struct idle_sampling_loop_state { +typedef struct { pthread_mutex_t wakeup_mutex; pthread_cond_t wakeup; action requested_action; void (*run_action_function)(void); -}; +} idle_sampling_loop_state; static VALUE _native_new(VALUE klass); -static void reset_state(struct idle_sampling_loop_state *state); +static void reset_state(idle_sampling_loop_state *state); static VALUE _native_idle_sampling_loop(DDTRACE_UNUSED VALUE self, VALUE self_instance); static VALUE _native_stop(DDTRACE_UNUSED VALUE self, VALUE self_instance); static void *run_idle_sampling_loop(void *state_ptr); @@ -62,7 +62,7 @@ void collectors_idle_sampling_helper_init(VALUE profiling_module) { rb_define_singleton_method(testing_module, "_native_idle_sampling_helper_request_action", _native_idle_sampling_helper_request_action, 1); } -// This structure is used to define a Ruby object that stores a pointer to a struct idle_sampling_loop_state +// This structure is used to define a Ruby object that stores a pointer to a idle_sampling_loop_state // See also https://github.com/ruby/ruby/blob/master/doc/extension.rdoc for how this works static const rb_data_type_t idle_sampling_helper_typed_data = { .wrap_struct_name = "Datadog::Profiling::Collectors::IdleSamplingHelper", @@ -76,7 +76,7 @@ static const rb_data_type_t idle_sampling_helper_typed_data = { }; static VALUE _native_new(VALUE klass) { - struct idle_sampling_loop_state *state = ruby_xcalloc(1, sizeof(struct idle_sampling_loop_state)); + idle_sampling_loop_state *state = ruby_xcalloc(1, sizeof(idle_sampling_loop_state)); // Note: Any exceptions raised from this note until the TypedData_Wrap_Struct call will lead to the state memory // being leaked. @@ -90,7 +90,7 @@ static VALUE _native_new(VALUE klass) { return TypedData_Wrap_Struct(klass, &idle_sampling_helper_typed_data, state); } -static void reset_state(struct idle_sampling_loop_state *state) { +static void reset_state(idle_sampling_loop_state *state) { state->wakeup_mutex = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER; state->wakeup = (pthread_cond_t) PTHREAD_COND_INITIALIZER; state->requested_action = ACTION_WAIT; @@ -101,8 +101,8 @@ static void reset_state(struct idle_sampling_loop_state *state) { // a pristine state before recreating the worker thread (this includes resetting the mutex in case it was left // locked halfway through the VM forking) static VALUE _native_reset(DDTRACE_UNUSED VALUE self, VALUE self_instance) { - struct idle_sampling_loop_state *state; - TypedData_Get_Struct(self_instance, struct idle_sampling_loop_state, &idle_sampling_helper_typed_data, state); + idle_sampling_loop_state *state; + TypedData_Get_Struct(self_instance, idle_sampling_loop_state, &idle_sampling_helper_typed_data, state); reset_state(state); @@ -110,8 +110,8 @@ static VALUE _native_reset(DDTRACE_UNUSED VALUE self, VALUE self_instance) { } static VALUE _native_idle_sampling_loop(DDTRACE_UNUSED VALUE self, VALUE self_instance) { - struct idle_sampling_loop_state *state; - TypedData_Get_Struct(self_instance, struct idle_sampling_loop_state, &idle_sampling_helper_typed_data, state); + idle_sampling_loop_state *state; + TypedData_Get_Struct(self_instance, idle_sampling_loop_state, &idle_sampling_helper_typed_data, state); // Release GVL and run the loop waiting for requests rb_thread_call_without_gvl(run_idle_sampling_loop, state, interrupt_idle_sampling_loop, state); @@ -120,7 +120,7 @@ static VALUE _native_idle_sampling_loop(DDTRACE_UNUSED VALUE self, VALUE self_in } static void *run_idle_sampling_loop(void *state_ptr) { - struct idle_sampling_loop_state *state = (struct idle_sampling_loop_state *) state_ptr; + idle_sampling_loop_state *state = (idle_sampling_loop_state *) state_ptr; int error = 0; while (true) { @@ -164,7 +164,7 @@ static void *run_idle_sampling_loop(void *state_ptr) { } static void interrupt_idle_sampling_loop(void *state_ptr) { - struct idle_sampling_loop_state *state = (struct idle_sampling_loop_state *) state_ptr; + idle_sampling_loop_state *state = (idle_sampling_loop_state *) state_ptr; int error = 0; // Note about the error handling in this situation: Something bad happening at this stage is really really awkward to @@ -189,8 +189,8 @@ static void interrupt_idle_sampling_loop(void *state_ptr) { } static VALUE _native_stop(DDTRACE_UNUSED VALUE self, VALUE self_instance) { - struct idle_sampling_loop_state *state; - TypedData_Get_Struct(self_instance, struct idle_sampling_loop_state, &idle_sampling_helper_typed_data, state); + idle_sampling_loop_state *state; + TypedData_Get_Struct(self_instance, idle_sampling_loop_state, &idle_sampling_helper_typed_data, state); ENFORCE_SUCCESS_GVL(pthread_mutex_lock(&state->wakeup_mutex)); state->requested_action = ACTION_STOP; @@ -204,12 +204,12 @@ static VALUE _native_stop(DDTRACE_UNUSED VALUE self, VALUE self_instance) { // Assumption: Function gets called without the global VM lock void idle_sampling_helper_request_action(VALUE self_instance, void (*run_action_function)(void)) { - struct idle_sampling_loop_state *state; + idle_sampling_loop_state *state; if (!rb_typeddata_is_kind_of(self_instance, &idle_sampling_helper_typed_data)) { grab_gvl_and_raise(rb_eTypeError, "Wrong argument for idle_sampling_helper_request_action"); } // This should never fail the the above check passes - TypedData_Get_Struct(self_instance, struct idle_sampling_loop_state, &idle_sampling_helper_typed_data, state); + TypedData_Get_Struct(self_instance, idle_sampling_loop_state, &idle_sampling_helper_typed_data, state); ENFORCE_SUCCESS_NO_GVL(pthread_mutex_lock(&state->wakeup_mutex)); if (state->requested_action == ACTION_WAIT) { diff --git a/ext/datadog_profiling_native_extension/collectors_stack.c b/ext/datadog_profiling_native_extension/collectors_stack.c index c7445dfc9ca..201a548f388 100644 --- a/ext/datadog_profiling_native_extension/collectors_stack.c +++ b/ext/datadog_profiling_native_extension/collectors_stack.c @@ -14,11 +14,11 @@ static VALUE missing_string = Qnil; // Used as scratch space during sampling -struct sampling_buffer { +struct sampling_buffer { // Note: typedef'd in the header to sampling_buffer uint16_t max_frames; ddog_prof_Location *locations; frame_info *stack_buffer; -}; // Note: typedef'd in the header to sampling_buffer +}; static VALUE _native_sample(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self); static VALUE native_sample_do(VALUE args); @@ -44,7 +44,7 @@ void collectors_stack_init(VALUE profiling_module) { rb_global_variable(&missing_string); } -struct native_sample_args { +typedef struct { VALUE in_gc; VALUE recorder_instance; sample_values values; @@ -52,7 +52,7 @@ struct native_sample_args { VALUE thread; ddog_prof_Location *locations; sampling_buffer *buffer; -}; +} native_sample_args; // This method exists only to enable testing Datadog::Profiling::Collectors::Stack behavior using RSpec. // It SHOULD NOT be used for other purposes. @@ -123,7 +123,7 @@ static VALUE _native_sample(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self) { ddog_prof_Slice_Label slice_labels = {.ptr = labels, .len = labels_count}; - struct native_sample_args args_struct = { + native_sample_args args_struct = { .in_gc = in_gc, .recorder_instance = recorder_instance, .values = values, @@ -137,7 +137,7 @@ static VALUE _native_sample(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self) { } static VALUE native_sample_do(VALUE args) { - struct native_sample_args *args_struct = (struct native_sample_args *) args; + native_sample_args *args_struct = (native_sample_args *) args; if (args_struct->in_gc == Qtrue) { record_placeholder_stack( @@ -160,7 +160,7 @@ static VALUE native_sample_do(VALUE args) { } static VALUE native_sample_ensure(VALUE args) { - struct native_sample_args *args_struct = (struct native_sample_args *) args; + native_sample_args *args_struct = (native_sample_args *) args; ruby_xfree(args_struct->locations); sampling_buffer_free(args_struct->buffer); diff --git a/ext/datadog_profiling_native_extension/collectors_thread_context.c b/ext/datadog_profiling_native_extension/collectors_thread_context.c index 0b56268bed5..ba351b0c1fa 100644 --- a/ext/datadog_profiling_native_extension/collectors_thread_context.c +++ b/ext/datadog_profiling_native_extension/collectors_thread_context.c @@ -9,6 +9,7 @@ #include "private_vm_api_access.h" #include "stack_recorder.h" #include "time_helpers.h" +#include "unsafe_api_calls_check.h" // Used to trigger sampling of threads, based on external "events", such as: // * periodic timer for cpu-time and wall-time @@ -112,14 +113,14 @@ static uint32_t global_waiting_for_gvl_threshold_ns = MILLIS_AS_NS(10); typedef enum { OTEL_CONTEXT_ENABLED_FALSE, OTEL_CONTEXT_ENABLED_ONLY, OTEL_CONTEXT_ENABLED_BOTH } otel_context_enabled; // Contains state for a single ThreadContext instance -struct thread_context_collector_state { +typedef struct { // Note: Places in this file that usually need to be changed when this struct is changed are tagged with // "Update this when modifying state struct" // Required by Datadog::Profiling::Collectors::Stack as a scratch buffer during sampling ddog_prof_Location *locations; uint16_t max_frames; - // Hashmap + // Hashmap st_table *hash_map_per_thread_context; // Datadog::Profiling::StackRecorder instance VALUE recorder_instance; @@ -162,10 +163,10 @@ struct thread_context_collector_state { long wall_time_at_previous_gc_ns; // Will be INVALID_TIME unless there's accumulated time above long wall_time_at_last_flushed_gc_event_ns; // Starts at 0 and then will always be valid } gc_tracking; -}; +} thread_context_collector_state; // Tracks per-thread state -struct per_thread_context { +typedef struct { sampling_buffer *sampling_buffer; char thread_id[THREAD_ID_LIMIT_CHARS]; ddog_CharSlice thread_id_char_slice; @@ -181,21 +182,21 @@ struct per_thread_context { long cpu_time_at_start_ns; long wall_time_at_start_ns; } gc_tracking; -}; +} per_thread_context; // Used to correlate profiles with traces -struct trace_identifiers { +typedef struct { bool valid; uint64_t local_root_span_id; uint64_t span_id; VALUE trace_endpoint; -}; +} trace_identifiers; -struct otel_span { +typedef struct { VALUE span; VALUE span_id; VALUE trace_id; -}; +} otel_span; static void thread_context_collector_typed_data_mark(void *state_ptr); static void thread_context_collector_typed_data_free(void *state_ptr); @@ -203,24 +204,24 @@ static int hash_map_per_thread_context_mark(st_data_t key_thread, st_data_t _val static int hash_map_per_thread_context_free_values(st_data_t _thread, st_data_t value_per_thread_context, st_data_t _argument); static VALUE _native_new(VALUE klass); static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self); -static VALUE _native_sample(VALUE self, VALUE collector_instance, VALUE profiler_overhead_stack_thread); +static VALUE _native_sample(VALUE self, VALUE collector_instance, VALUE profiler_overhead_stack_thread, VALUE allow_exception); static VALUE _native_on_gc_start(VALUE self, VALUE collector_instance); static VALUE _native_on_gc_finish(VALUE self, VALUE collector_instance); -static VALUE _native_sample_after_gc(DDTRACE_UNUSED VALUE self, VALUE collector_instance, VALUE reset_monotonic_to_system_state); +static VALUE _native_sample_after_gc(DDTRACE_UNUSED VALUE self, VALUE collector_instance, VALUE reset_monotonic_to_system_state, VALUE allow_exception); static void update_metrics_and_sample( - struct thread_context_collector_state *state, + thread_context_collector_state *state, VALUE thread_being_sampled, VALUE stack_from_thread, - struct per_thread_context *thread_context, + per_thread_context *thread_context, sampling_buffer* sampling_buffer, long current_cpu_time_ns, long current_monotonic_wall_time_ns ); static void trigger_sample_for_thread( - struct thread_context_collector_state *state, + thread_context_collector_state *state, VALUE thread, VALUE stack_from_thread, - struct per_thread_context *thread_context, + per_thread_context *thread_context, sampling_buffer* sampling_buffer, sample_values values, long current_monotonic_wall_time_ns, @@ -230,37 +231,37 @@ static void trigger_sample_for_thread( bool is_safe_to_allocate_objects ); static VALUE _native_thread_list(VALUE self); -static struct per_thread_context *get_or_create_context_for(VALUE thread, struct thread_context_collector_state *state); -static struct per_thread_context *get_context_for(VALUE thread, struct thread_context_collector_state *state); -static void initialize_context(VALUE thread, struct per_thread_context *thread_context, struct thread_context_collector_state *state); -static void free_context(struct per_thread_context* thread_context); +static per_thread_context *get_or_create_context_for(VALUE thread, thread_context_collector_state *state); +static per_thread_context *get_context_for(VALUE thread, thread_context_collector_state *state); +static void initialize_context(VALUE thread, per_thread_context *thread_context, thread_context_collector_state *state); +static void free_context(per_thread_context* thread_context); static VALUE _native_inspect(VALUE self, VALUE collector_instance); -static VALUE per_thread_context_st_table_as_ruby_hash(struct thread_context_collector_state *state); +static VALUE per_thread_context_st_table_as_ruby_hash(thread_context_collector_state *state); static int per_thread_context_as_ruby_hash(st_data_t key_thread, st_data_t value_context, st_data_t result_hash); -static VALUE stats_as_ruby_hash(struct thread_context_collector_state *state); -static VALUE gc_tracking_as_ruby_hash(struct thread_context_collector_state *state); -static void remove_context_for_dead_threads(struct thread_context_collector_state *state); +static VALUE stats_as_ruby_hash(thread_context_collector_state *state); +static VALUE gc_tracking_as_ruby_hash(thread_context_collector_state *state); +static void remove_context_for_dead_threads(thread_context_collector_state *state); static int remove_if_dead_thread(st_data_t key_thread, st_data_t value_context, st_data_t _argument); static VALUE _native_per_thread_context(VALUE self, VALUE collector_instance); static long update_time_since_previous_sample(long *time_at_previous_sample_ns, long current_time_ns, long gc_start_time_ns, bool is_wall_time); -static long cpu_time_now_ns(struct per_thread_context *thread_context); +static long cpu_time_now_ns(per_thread_context *thread_context); static long thread_id_for(VALUE thread); static VALUE _native_stats(VALUE self, VALUE collector_instance); static VALUE _native_gc_tracking(VALUE self, VALUE collector_instance); static void trace_identifiers_for( - struct thread_context_collector_state *state, + thread_context_collector_state *state, VALUE thread, - struct trace_identifiers *trace_identifiers_result, + trace_identifiers *trace_identifiers_result, bool is_safe_to_allocate_objects ); static bool should_collect_resource(VALUE root_span); static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE collector_instance); -static VALUE thread_list(struct thread_context_collector_state *state); +static VALUE thread_list(thread_context_collector_state *state); static VALUE _native_sample_allocation(DDTRACE_UNUSED VALUE self, VALUE collector_instance, VALUE sample_weight, VALUE new_object); static VALUE _native_new_empty_thread(VALUE self); static ddog_CharSlice ruby_value_type_to_class_name(enum ruby_value_type type); static void ddtrace_otel_trace_identifiers_for( - struct thread_context_collector_state *state, + thread_context_collector_state *state, VALUE *active_trace, VALUE *root_span, VALUE *numeric_span_id, @@ -270,10 +271,10 @@ static void ddtrace_otel_trace_identifiers_for( ); static VALUE _native_sample_skipped_allocation_samples(DDTRACE_UNUSED VALUE self, VALUE collector_instance, VALUE skipped_samples); static bool handle_gvl_waiting( - struct thread_context_collector_state *state, + thread_context_collector_state *state, VALUE thread_being_sampled, VALUE stack_from_thread, - struct per_thread_context *thread_context, + per_thread_context *thread_context, sampling_buffer* sampling_buffer, long current_cpu_time_ns ); @@ -283,13 +284,14 @@ static VALUE _native_on_gvl_running(DDTRACE_UNUSED VALUE self, VALUE thread); static VALUE _native_sample_after_gvl_running(DDTRACE_UNUSED VALUE self, VALUE collector_instance, VALUE thread); static VALUE _native_apply_delta_to_cpu_time_at_previous_sample_ns(DDTRACE_UNUSED VALUE self, VALUE collector_instance, VALUE thread, VALUE delta_ns); static void otel_without_ddtrace_trace_identifiers_for( - struct thread_context_collector_state *state, + thread_context_collector_state *state, VALUE thread, - struct trace_identifiers *trace_identifiers_result, + trace_identifiers *trace_identifiers_result, bool is_safe_to_allocate_objects ); -static struct otel_span otel_span_from(VALUE otel_context, VALUE otel_current_span_key); +static otel_span otel_span_from(VALUE otel_context, VALUE otel_current_span_key); static uint64_t otel_span_id_to_uint(VALUE otel_span_id); +static VALUE safely_lookup_hash_without_going_into_ruby_code(VALUE hash, VALUE key); void collectors_thread_context_init(VALUE profiling_module) { VALUE collectors_module = rb_define_module_under(profiling_module, "Collectors"); @@ -310,11 +312,11 @@ void collectors_thread_context_init(VALUE profiling_module) { rb_define_singleton_method(collectors_thread_context_class, "_native_initialize", _native_initialize, -1); rb_define_singleton_method(collectors_thread_context_class, "_native_inspect", _native_inspect, 1); rb_define_singleton_method(collectors_thread_context_class, "_native_reset_after_fork", _native_reset_after_fork, 1); - rb_define_singleton_method(testing_module, "_native_sample", _native_sample, 2); + rb_define_singleton_method(testing_module, "_native_sample", _native_sample, 3); rb_define_singleton_method(testing_module, "_native_sample_allocation", _native_sample_allocation, 3); rb_define_singleton_method(testing_module, "_native_on_gc_start", _native_on_gc_start, 1); rb_define_singleton_method(testing_module, "_native_on_gc_finish", _native_on_gc_finish, 1); - rb_define_singleton_method(testing_module, "_native_sample_after_gc", _native_sample_after_gc, 2); + rb_define_singleton_method(testing_module, "_native_sample_after_gc", _native_sample_after_gc, 3); rb_define_singleton_method(testing_module, "_native_thread_list", _native_thread_list, 0); rb_define_singleton_method(testing_module, "_native_per_thread_context", _native_per_thread_context, 1); rb_define_singleton_method(testing_module, "_native_stats", _native_stats, 1); @@ -355,7 +357,7 @@ void collectors_thread_context_init(VALUE profiling_module) { gc_profiling_init(); } -// This structure is used to define a Ruby object that stores a pointer to a struct thread_context_collector_state +// This structure is used to define a Ruby object that stores a pointer to a thread_context_collector_state // See also https://github.com/ruby/ruby/blob/master/doc/extension.rdoc for how this works static const rb_data_type_t thread_context_collector_typed_data = { .wrap_struct_name = "Datadog::Profiling::Collectors::ThreadContext", @@ -371,7 +373,7 @@ static const rb_data_type_t thread_context_collector_typed_data = { // This function is called by the Ruby GC to give us a chance to mark any Ruby objects that we're holding on to, // so that they don't get garbage collected static void thread_context_collector_typed_data_mark(void *state_ptr) { - struct thread_context_collector_state *state = (struct thread_context_collector_state *) state_ptr; + thread_context_collector_state *state = (thread_context_collector_state *) state_ptr; // Update this when modifying state struct rb_gc_mark(state->recorder_instance); @@ -382,7 +384,7 @@ static void thread_context_collector_typed_data_mark(void *state_ptr) { } static void thread_context_collector_typed_data_free(void *state_ptr) { - struct thread_context_collector_state *state = (struct thread_context_collector_state *) state_ptr; + thread_context_collector_state *state = (thread_context_collector_state *) state_ptr; // Update this when modifying state struct @@ -407,13 +409,13 @@ static int hash_map_per_thread_context_mark(st_data_t key_thread, DDTRACE_UNUSED // Used to clear each of the per_thread_contexts inside the hash_map_per_thread_context static int hash_map_per_thread_context_free_values(DDTRACE_UNUSED st_data_t _thread, st_data_t value_per_thread_context, DDTRACE_UNUSED st_data_t _argument) { - struct per_thread_context *thread_context = (struct per_thread_context*) value_per_thread_context; + per_thread_context *thread_context = (per_thread_context*) value_per_thread_context; free_context(thread_context); return ST_CONTINUE; } static VALUE _native_new(VALUE klass) { - struct thread_context_collector_state *state = ruby_xcalloc(1, sizeof(struct thread_context_collector_state)); + thread_context_collector_state *state = ruby_xcalloc(1, sizeof(thread_context_collector_state)); // Note: Any exceptions raised from this note until the TypedData_Wrap_Struct call will lead to the state memory // being leaked. @@ -469,8 +471,8 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel ENFORCE_BOOLEAN(timeline_enabled); ENFORCE_TYPE(waiting_for_gvl_threshold_ns, T_FIXNUM); - struct thread_context_collector_state *state; - TypedData_Get_Struct(self_instance, struct thread_context_collector_state, &thread_context_collector_typed_data, state); + thread_context_collector_state *state; + TypedData_Get_Struct(self_instance, thread_context_collector_state, &thread_context_collector_typed_data, state); // Update this when modifying state struct state->max_frames = sampling_buffer_check_max_frames(NUM2INT(max_frames)); @@ -504,40 +506,63 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel // This method exists only to enable testing Datadog::Profiling::Collectors::ThreadContext behavior using RSpec. // It SHOULD NOT be used for other purposes. -static VALUE _native_sample(DDTRACE_UNUSED VALUE _self, VALUE collector_instance, VALUE profiler_overhead_stack_thread) { +static VALUE _native_sample(DDTRACE_UNUSED VALUE _self, VALUE collector_instance, VALUE profiler_overhead_stack_thread, VALUE allow_exception) { + ENFORCE_BOOLEAN(allow_exception); + if (!is_thread_alive(profiler_overhead_stack_thread)) rb_raise(rb_eArgError, "Unexpected: profiler_overhead_stack_thread is not alive"); + if (allow_exception == Qfalse) debug_enter_unsafe_context(); + thread_context_collector_sample(collector_instance, monotonic_wall_time_now_ns(RAISE_ON_FAILURE), profiler_overhead_stack_thread); + + if (allow_exception == Qfalse) debug_leave_unsafe_context(); + return Qtrue; } // This method exists only to enable testing Datadog::Profiling::Collectors::ThreadContext behavior using RSpec. // It SHOULD NOT be used for other purposes. static VALUE _native_on_gc_start(DDTRACE_UNUSED VALUE self, VALUE collector_instance) { + debug_enter_unsafe_context(); + thread_context_collector_on_gc_start(collector_instance); + + debug_leave_unsafe_context(); + return Qtrue; } // This method exists only to enable testing Datadog::Profiling::Collectors::ThreadContext behavior using RSpec. // It SHOULD NOT be used for other purposes. static VALUE _native_on_gc_finish(DDTRACE_UNUSED VALUE self, VALUE collector_instance) { + debug_enter_unsafe_context(); + (void) !thread_context_collector_on_gc_finish(collector_instance); + + debug_leave_unsafe_context(); + return Qtrue; } // This method exists only to enable testing Datadog::Profiling::Collectors::ThreadContext behavior using RSpec. // It SHOULD NOT be used for other purposes. -static VALUE _native_sample_after_gc(DDTRACE_UNUSED VALUE self, VALUE collector_instance, VALUE reset_monotonic_to_system_state) { +static VALUE _native_sample_after_gc(DDTRACE_UNUSED VALUE self, VALUE collector_instance, VALUE reset_monotonic_to_system_state, VALUE allow_exception) { ENFORCE_BOOLEAN(reset_monotonic_to_system_state); + ENFORCE_BOOLEAN(allow_exception); - struct thread_context_collector_state *state; - TypedData_Get_Struct(collector_instance, struct thread_context_collector_state, &thread_context_collector_typed_data, state); + thread_context_collector_state *state; + TypedData_Get_Struct(collector_instance, thread_context_collector_state, &thread_context_collector_typed_data, state); if (reset_monotonic_to_system_state == Qtrue) { state->time_converter_state = (monotonic_to_system_epoch_state) MONOTONIC_TO_SYSTEM_EPOCH_INITIALIZER; } + if (allow_exception == Qfalse) debug_enter_unsafe_context(); + thread_context_collector_sample_after_gc(collector_instance); + + if (allow_exception == Qfalse) debug_leave_unsafe_context(); + return Qtrue; } @@ -552,11 +577,11 @@ static VALUE _native_sample_after_gc(DDTRACE_UNUSED VALUE self, VALUE collector_ // The `profiler_overhead_stack_thread` is used to attribute the profiler overhead to a stack borrowed from a different thread // (belonging to ddtrace), so that the overhead is visible in the profile rather than blamed on user code. void thread_context_collector_sample(VALUE self_instance, long current_monotonic_wall_time_ns, VALUE profiler_overhead_stack_thread) { - struct thread_context_collector_state *state; - TypedData_Get_Struct(self_instance, struct thread_context_collector_state, &thread_context_collector_typed_data, state); + thread_context_collector_state *state; + TypedData_Get_Struct(self_instance, thread_context_collector_state, &thread_context_collector_typed_data, state); VALUE current_thread = rb_thread_current(); - struct per_thread_context *current_thread_context = get_or_create_context_for(current_thread, state); + per_thread_context *current_thread_context = get_or_create_context_for(current_thread, state); long cpu_time_at_sample_start_for_current_thread = cpu_time_now_ns(current_thread_context); VALUE threads = thread_list(state); @@ -564,7 +589,7 @@ void thread_context_collector_sample(VALUE self_instance, long current_monotonic const long thread_count = RARRAY_LEN(threads); for (long i = 0; i < thread_count; i++) { VALUE thread = RARRAY_AREF(threads, i); - struct per_thread_context *thread_context = get_or_create_context_for(thread, state); + per_thread_context *thread_context = get_or_create_context_for(thread, state); // We account for cpu-time for the current thread in a different way -- we use the cpu-time at sampling start, to avoid // blaming the time the profiler took on whatever's running on the thread right now @@ -600,10 +625,10 @@ void thread_context_collector_sample(VALUE self_instance, long current_monotonic } static void update_metrics_and_sample( - struct thread_context_collector_state *state, + thread_context_collector_state *state, VALUE thread_being_sampled, VALUE stack_from_thread, // This can be different when attributing profiler overhead using a different stack - struct per_thread_context *thread_context, + per_thread_context *thread_context, sampling_buffer* sampling_buffer, long current_cpu_time_ns, long current_monotonic_wall_time_ns @@ -671,12 +696,12 @@ static void update_metrics_and_sample( // Assumption 1: This function is called in a thread that is holding the Global VM Lock. Caller is responsible for enforcing this. // Assumption 2: This function is called from the main Ractor (if Ruby has support for Ractors). void thread_context_collector_on_gc_start(VALUE self_instance) { - struct thread_context_collector_state *state; + thread_context_collector_state *state; if (!rb_typeddata_is_kind_of(self_instance, &thread_context_collector_typed_data)) return; // This should never fail the the above check passes - TypedData_Get_Struct(self_instance, struct thread_context_collector_state, &thread_context_collector_typed_data, state); + TypedData_Get_Struct(self_instance, thread_context_collector_state, &thread_context_collector_typed_data, state); - struct per_thread_context *thread_context = get_context_for(rb_thread_current(), state); + per_thread_context *thread_context = get_context_for(rb_thread_current(), state); // If there was no previously-existing context for this thread, we won't allocate one (see safety). For now we just drop // the GC sample, under the assumption that "a thread that is so new that we never sampled it even once before it triggers @@ -704,12 +729,12 @@ void thread_context_collector_on_gc_start(VALUE self_instance) { // Assumption 2: This function is called from the main Ractor (if Ruby has support for Ractors). __attribute__((warn_unused_result)) bool thread_context_collector_on_gc_finish(VALUE self_instance) { - struct thread_context_collector_state *state; + thread_context_collector_state *state; if (!rb_typeddata_is_kind_of(self_instance, &thread_context_collector_typed_data)) return false; // This should never fail the the above check passes - TypedData_Get_Struct(self_instance, struct thread_context_collector_state, &thread_context_collector_typed_data, state); + TypedData_Get_Struct(self_instance, thread_context_collector_state, &thread_context_collector_typed_data, state); - struct per_thread_context *thread_context = get_context_for(rb_thread_current(), state); + per_thread_context *thread_context = get_context_for(rb_thread_current(), state); // If there was no previously-existing context for this thread, we won't allocate one (see safety). We keep a metric for // how often this happens -- see on_gc_start. @@ -782,8 +807,8 @@ bool thread_context_collector_on_gc_finish(VALUE self_instance) { // Assumption 3: Unlike `on_gc_start` and `on_gc_finish`, this method is allowed to allocate memory as needed. // Assumption 4: This function is called from the main Ractor (if Ruby has support for Ractors). VALUE thread_context_collector_sample_after_gc(VALUE self_instance) { - struct thread_context_collector_state *state; - TypedData_Get_Struct(self_instance, struct thread_context_collector_state, &thread_context_collector_typed_data, state); + thread_context_collector_state *state; + TypedData_Get_Struct(self_instance, thread_context_collector_state, &thread_context_collector_typed_data, state); if (state->gc_tracking.wall_time_at_previous_gc_ns == INVALID_TIME) { rb_raise(rb_eRuntimeError, "BUG: Unexpected call to sample_after_gc without valid GC information available"); @@ -832,10 +857,10 @@ VALUE thread_context_collector_sample_after_gc(VALUE self_instance) { } static void trigger_sample_for_thread( - struct thread_context_collector_state *state, + thread_context_collector_state *state, VALUE thread, VALUE stack_from_thread, // This can be different when attributing profiler overhead using a different stack - struct per_thread_context *thread_context, + per_thread_context *thread_context, sampling_buffer* sampling_buffer, sample_values values, long current_monotonic_wall_time_ns, @@ -883,7 +908,7 @@ static void trigger_sample_for_thread( }; } - struct trace_identifiers trace_identifiers_result = {.valid = false, .trace_endpoint = Qnil}; + trace_identifiers trace_identifiers_result = {.valid = false, .trace_endpoint = Qnil}; trace_identifiers_for(state, thread, &trace_identifiers_result, is_safe_to_allocate_objects); if (!trace_identifiers_result.valid && state->otel_context_enabled != OTEL_CONTEXT_ENABLED_FALSE) { @@ -982,18 +1007,24 @@ static void trigger_sample_for_thread( // It SHOULD NOT be used for other purposes. static VALUE _native_thread_list(DDTRACE_UNUSED VALUE _self) { VALUE result = rb_ary_new(); + + debug_enter_unsafe_context(); + ddtrace_thread_list(result); + + debug_leave_unsafe_context(); + return result; } -static struct per_thread_context *get_or_create_context_for(VALUE thread, struct thread_context_collector_state *state) { - struct per_thread_context* thread_context = NULL; +static per_thread_context *get_or_create_context_for(VALUE thread, thread_context_collector_state *state) { + per_thread_context* thread_context = NULL; st_data_t value_context = 0; if (st_lookup(state->hash_map_per_thread_context, (st_data_t) thread, &value_context)) { - thread_context = (struct per_thread_context*) value_context; + thread_context = (per_thread_context*) value_context; } else { - thread_context = ruby_xcalloc(1, sizeof(struct per_thread_context)); + thread_context = ruby_xcalloc(1, sizeof(per_thread_context)); initialize_context(thread, thread_context, state); st_insert(state->hash_map_per_thread_context, (st_data_t) thread, (st_data_t) thread_context); } @@ -1001,12 +1032,12 @@ static struct per_thread_context *get_or_create_context_for(VALUE thread, struct return thread_context; } -static struct per_thread_context *get_context_for(VALUE thread, struct thread_context_collector_state *state) { - struct per_thread_context* thread_context = NULL; +static per_thread_context *get_context_for(VALUE thread, thread_context_collector_state *state) { + per_thread_context* thread_context = NULL; st_data_t value_context = 0; if (st_lookup(state->hash_map_per_thread_context, (st_data_t) thread, &value_context)) { - thread_context = (struct per_thread_context*) value_context; + thread_context = (per_thread_context*) value_context; } return thread_context; @@ -1033,7 +1064,7 @@ static bool is_logging_gem_monkey_patch(VALUE invoke_file_location) { return strncmp(invoke_file + invoke_file_len - logging_gem_path_len, LOGGING_GEM_PATH, logging_gem_path_len) == 0; } -static void initialize_context(VALUE thread, struct per_thread_context *thread_context, struct thread_context_collector_state *state) { +static void initialize_context(VALUE thread, per_thread_context *thread_context, thread_context_collector_state *state) { thread_context->sampling_buffer = sampling_buffer_new(state->max_frames, state->locations); snprintf(thread_context->thread_id, THREAD_ID_LIMIT_CHARS, "%"PRIu64" (%lu)", native_thread_id_for(thread), (unsigned long) thread_id_for(thread)); @@ -1090,14 +1121,14 @@ static void initialize_context(VALUE thread, struct per_thread_context *thread_c #endif } -static void free_context(struct per_thread_context* thread_context) { +static void free_context(per_thread_context* thread_context) { sampling_buffer_free(thread_context->sampling_buffer); ruby_xfree(thread_context); } static VALUE _native_inspect(DDTRACE_UNUSED VALUE _self, VALUE collector_instance) { - struct thread_context_collector_state *state; - TypedData_Get_Struct(collector_instance, struct thread_context_collector_state, &thread_context_collector_typed_data, state); + thread_context_collector_state *state; + TypedData_Get_Struct(collector_instance, thread_context_collector_state, &thread_context_collector_typed_data, state); VALUE result = rb_str_new2(" (native state)"); @@ -1125,7 +1156,7 @@ static VALUE _native_inspect(DDTRACE_UNUSED VALUE _self, VALUE collector_instanc return result; } -static VALUE per_thread_context_st_table_as_ruby_hash(struct thread_context_collector_state *state) { +static VALUE per_thread_context_st_table_as_ruby_hash(thread_context_collector_state *state) { VALUE result = rb_hash_new(); st_foreach(state->hash_map_per_thread_context, per_thread_context_as_ruby_hash, result); return result; @@ -1133,7 +1164,7 @@ static VALUE per_thread_context_st_table_as_ruby_hash(struct thread_context_coll static int per_thread_context_as_ruby_hash(st_data_t key_thread, st_data_t value_context, st_data_t result_hash) { VALUE thread = (VALUE) key_thread; - struct per_thread_context *thread_context = (struct per_thread_context*) value_context; + per_thread_context *thread_context = (per_thread_context*) value_context; VALUE result = (VALUE) result_hash; VALUE context_as_hash = rb_hash_new(); rb_hash_aset(result, thread, context_as_hash); @@ -1158,7 +1189,7 @@ static int per_thread_context_as_ruby_hash(st_data_t key_thread, st_data_t value return ST_CONTINUE; } -static VALUE stats_as_ruby_hash(struct thread_context_collector_state *state) { +static VALUE stats_as_ruby_hash(thread_context_collector_state *state) { // Update this when modifying state struct (stats inner struct) VALUE stats_as_hash = rb_hash_new(); VALUE arguments[] = { @@ -1169,7 +1200,7 @@ static VALUE stats_as_ruby_hash(struct thread_context_collector_state *state) { return stats_as_hash; } -static VALUE gc_tracking_as_ruby_hash(struct thread_context_collector_state *state) { +static VALUE gc_tracking_as_ruby_hash(thread_context_collector_state *state) { // Update this when modifying state struct (gc_tracking inner struct) VALUE result = rb_hash_new(); VALUE arguments[] = { @@ -1182,13 +1213,13 @@ static VALUE gc_tracking_as_ruby_hash(struct thread_context_collector_state *sta return result; } -static void remove_context_for_dead_threads(struct thread_context_collector_state *state) { +static void remove_context_for_dead_threads(thread_context_collector_state *state) { st_foreach(state->hash_map_per_thread_context, remove_if_dead_thread, 0 /* unused */); } static int remove_if_dead_thread(st_data_t key_thread, st_data_t value_context, DDTRACE_UNUSED st_data_t _argument) { VALUE thread = (VALUE) key_thread; - struct per_thread_context* thread_context = (struct per_thread_context*) value_context; + per_thread_context* thread_context = (per_thread_context*) value_context; if (is_thread_alive(thread)) return ST_CONTINUE; @@ -1201,8 +1232,8 @@ static int remove_if_dead_thread(st_data_t key_thread, st_data_t value_context, // // Returns the whole contents of the per_thread_context structs being tracked. static VALUE _native_per_thread_context(DDTRACE_UNUSED VALUE _self, VALUE collector_instance) { - struct thread_context_collector_state *state; - TypedData_Get_Struct(collector_instance, struct thread_context_collector_state, &thread_context_collector_typed_data, state); + thread_context_collector_state *state; + TypedData_Get_Struct(collector_instance, thread_context_collector_state, &thread_context_collector_typed_data, state); return per_thread_context_st_table_as_ruby_hash(state); } @@ -1247,7 +1278,7 @@ static long update_time_since_previous_sample(long *time_at_previous_sample_ns, } // Safety: This function is assumed never to raise exceptions by callers -static long cpu_time_now_ns(struct per_thread_context *thread_context) { +static long cpu_time_now_ns(per_thread_context *thread_context) { thread_cpu_time cpu_time = thread_cpu_time_for(thread_context->thread_cpu_time_id); if (!cpu_time.valid) { @@ -1285,8 +1316,8 @@ VALUE enforce_thread_context_collector_instance(VALUE object) { // This method exists only to enable testing Datadog::Profiling::Collectors::ThreadContext behavior using RSpec. // It SHOULD NOT be used for other purposes. static VALUE _native_stats(DDTRACE_UNUSED VALUE _self, VALUE collector_instance) { - struct thread_context_collector_state *state; - TypedData_Get_Struct(collector_instance, struct thread_context_collector_state, &thread_context_collector_typed_data, state); + thread_context_collector_state *state; + TypedData_Get_Struct(collector_instance, thread_context_collector_state, &thread_context_collector_typed_data, state); return stats_as_ruby_hash(state); } @@ -1294,17 +1325,17 @@ static VALUE _native_stats(DDTRACE_UNUSED VALUE _self, VALUE collector_instance) // This method exists only to enable testing Datadog::Profiling::Collectors::ThreadContext behavior using RSpec. // It SHOULD NOT be used for other purposes. static VALUE _native_gc_tracking(DDTRACE_UNUSED VALUE _self, VALUE collector_instance) { - struct thread_context_collector_state *state; - TypedData_Get_Struct(collector_instance, struct thread_context_collector_state, &thread_context_collector_typed_data, state); + thread_context_collector_state *state; + TypedData_Get_Struct(collector_instance, thread_context_collector_state, &thread_context_collector_typed_data, state); return gc_tracking_as_ruby_hash(state); } // Assumption 1: This function is called in a thread that is holding the Global VM Lock. Caller is responsible for enforcing this. static void trace_identifiers_for( - struct thread_context_collector_state *state, + thread_context_collector_state *state, VALUE thread, - struct trace_identifiers *trace_identifiers_result, + trace_identifiers *trace_identifiers_result, bool is_safe_to_allocate_objects ) { if (state->otel_context_enabled == OTEL_CONTEXT_ENABLED_ONLY) return; @@ -1384,8 +1415,8 @@ static bool should_collect_resource(VALUE root_span) { // Assumption: This method gets called BEFORE restarting profiling -- e.g. there are no components attempting to // trigger samples at the same time. static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE collector_instance) { - struct thread_context_collector_state *state; - TypedData_Get_Struct(collector_instance, struct thread_context_collector_state, &thread_context_collector_typed_data, state); + thread_context_collector_state *state; + TypedData_Get_Struct(collector_instance, thread_context_collector_state, &thread_context_collector_typed_data, state); // Release all context memory before clearing the existing context st_foreach(state->hash_map_per_thread_context, hash_map_per_thread_context_free_values, 0 /* unused */); @@ -1399,7 +1430,7 @@ static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE collector return Qtrue; } -static VALUE thread_list(struct thread_context_collector_state *state) { +static VALUE thread_list(thread_context_collector_state *state) { VALUE result = state->thread_list_buffer; rb_ary_clear(result); ddtrace_thread_list(result); @@ -1407,8 +1438,8 @@ static VALUE thread_list(struct thread_context_collector_state *state) { } void thread_context_collector_sample_allocation(VALUE self_instance, unsigned int sample_weight, VALUE new_object) { - struct thread_context_collector_state *state; - TypedData_Get_Struct(self_instance, struct thread_context_collector_state, &thread_context_collector_typed_data, state); + thread_context_collector_state *state; + TypedData_Get_Struct(self_instance, thread_context_collector_state, &thread_context_collector_typed_data, state); VALUE current_thread = rb_thread_current(); @@ -1481,7 +1512,7 @@ void thread_context_collector_sample_allocation(VALUE self_instance, unsigned in track_object(state->recorder_instance, new_object, sample_weight, optional_class_name); - struct per_thread_context *thread_context = get_or_create_context_for(current_thread, state); + per_thread_context *thread_context = get_or_create_context_for(current_thread, state); trigger_sample_for_thread( state, @@ -1501,7 +1532,12 @@ void thread_context_collector_sample_allocation(VALUE self_instance, unsigned in // This method exists only to enable testing Datadog::Profiling::Collectors::ThreadContext behavior using RSpec. // It SHOULD NOT be used for other purposes. static VALUE _native_sample_allocation(DDTRACE_UNUSED VALUE self, VALUE collector_instance, VALUE sample_weight, VALUE new_object) { + debug_enter_unsafe_context(); + thread_context_collector_sample_allocation(collector_instance, NUM2UINT(sample_weight), new_object); + + debug_leave_unsafe_context(); + return Qtrue; } @@ -1549,7 +1585,7 @@ static VALUE read_otel_current_span_key_const(DDTRACE_UNUSED VALUE _unused) { return rb_const_get(trace_module, rb_intern("CURRENT_SPAN_KEY")); } -static VALUE get_otel_current_span_key(struct thread_context_collector_state *state, bool is_safe_to_allocate_objects) { +static VALUE get_otel_current_span_key(thread_context_collector_state *state, bool is_safe_to_allocate_objects) { if (state->otel_current_span_key == Qtrue) { // Qtrue means we haven't tried to extract it yet if (!is_safe_to_allocate_objects) { // Calling read_otel_current_span_key_const below can trigger exceptions and arbitrary Ruby code running (e.g. @@ -1572,7 +1608,7 @@ static VALUE get_otel_current_span_key(struct thread_context_collector_state *st // This method gets used when ddtrace is being used indirectly via the opentelemetry APIs. Information gets stored slightly // differently, and this codepath handles it. static void ddtrace_otel_trace_identifiers_for( - struct thread_context_collector_state *state, + thread_context_collector_state *state, VALUE *active_trace, VALUE *root_span, VALUE *numeric_span_id, @@ -1597,7 +1633,7 @@ static void ddtrace_otel_trace_identifiers_for( // trace and span representing it. Each ddtrace trace is then connected to the previous otel span, forming a linked // list. The local root span is going to be the trace/span we find at the end of this linked list. while (otel_values != Qnil) { - VALUE otel_span = rb_hash_lookup(otel_values, otel_current_span_key); + VALUE otel_span = safely_lookup_hash_without_going_into_ruby_code(otel_values, otel_current_span_key); if (otel_span == Qnil) break; VALUE next_trace = rb_ivar_get(otel_span, at_datadog_trace_id); if (next_trace == Qnil) break; @@ -1616,8 +1652,8 @@ static void ddtrace_otel_trace_identifiers_for( } void thread_context_collector_sample_skipped_allocation_samples(VALUE self_instance, unsigned int skipped_samples) { - struct thread_context_collector_state *state; - TypedData_Get_Struct(self_instance, struct thread_context_collector_state, &thread_context_collector_typed_data, state); + thread_context_collector_state *state; + TypedData_Get_Struct(self_instance, thread_context_collector_state, &thread_context_collector_typed_data, state); ddog_prof_Label labels[] = { // Providing .num = 0 should not be needed but the tracer-2.7 docker image ships a buggy gcc that complains about this @@ -1640,7 +1676,12 @@ void thread_context_collector_sample_skipped_allocation_samples(VALUE self_insta } static VALUE _native_sample_skipped_allocation_samples(DDTRACE_UNUSED VALUE self, VALUE collector_instance, VALUE skipped_samples) { + debug_enter_unsafe_context(); + thread_context_collector_sample_skipped_allocation_samples(collector_instance, NUM2UINT(skipped_samples)); + + debug_leave_unsafe_context(); + return Qtrue; } @@ -1666,9 +1707,9 @@ static VALUE _native_sample_skipped_allocation_samples(DDTRACE_UNUSED VALUE self // root span id. // This matches the semantics of how ddtrace tracing creates a TraceOperation and assigns a local root span to it. static void otel_without_ddtrace_trace_identifiers_for( - struct thread_context_collector_state *state, + thread_context_collector_state *state, VALUE thread, - struct trace_identifiers *trace_identifiers_result, + trace_identifiers *trace_identifiers_result, bool is_safe_to_allocate_objects ) { VALUE context_storage = rb_thread_local_aref(thread, otel_context_storage_id /* __opentelemetry_context_storage__ */); @@ -1682,14 +1723,14 @@ static void otel_without_ddtrace_trace_identifiers_for( int active_context_index = RARRAY_LEN(context_storage) - 1; if (active_context_index < 0) return; - struct otel_span active_span = otel_span_from(rb_ary_entry(context_storage, active_context_index), otel_current_span_key); + otel_span active_span = otel_span_from(rb_ary_entry(context_storage, active_context_index), otel_current_span_key); if (active_span.span == Qnil) return; - struct otel_span local_root_span = active_span; + otel_span local_root_span = active_span; // Now find the oldest span starting from the active span that still has the same trace id as the active span for (int i = active_context_index - 1; i >= 0; i--) { - struct otel_span checking_span = otel_span_from(rb_ary_entry(context_storage, i), otel_current_span_key); + otel_span checking_span = otel_span_from(rb_ary_entry(context_storage, i), otel_current_span_key); if (checking_span.span == Qnil) return; if (rb_str_equal(active_span.trace_id, checking_span.trace_id) == Qfalse) break; @@ -1709,7 +1750,7 @@ static void otel_without_ddtrace_trace_identifiers_for( VALUE root_span_type = rb_ivar_get(local_root_span.span, at_kind_id /* @kind */); // We filter out spans that don't have `kind: :server` - if (root_span_type == Qnil || !RB_TYPE_P(root_span_type, T_SYMBOL) || SYM2ID(root_span_type) != server_id) return; + if (root_span_type == Qnil || !RB_TYPE_P(root_span_type, T_SYMBOL) || !RB_STATIC_SYM_P(root_span_type) || SYM2ID(root_span_type) != server_id) return; VALUE trace_resource = rb_ivar_get(local_root_span.span, at_name_id /* @name */); if (!RB_TYPE_P(trace_resource, T_STRING)) return; @@ -1717,8 +1758,8 @@ static void otel_without_ddtrace_trace_identifiers_for( trace_identifiers_result->trace_endpoint = trace_resource; } -static struct otel_span otel_span_from(VALUE otel_context, VALUE otel_current_span_key) { - struct otel_span failed = {.span = Qnil, .span_id = Qnil, .trace_id = Qnil}; +static otel_span otel_span_from(VALUE otel_context, VALUE otel_current_span_key) { + otel_span failed = {.span = Qnil, .span_id = Qnil, .trace_id = Qnil}; if (otel_context == Qnil) return failed; @@ -1726,7 +1767,7 @@ static struct otel_span otel_span_from(VALUE otel_context, VALUE otel_current_sp if (context_entries == Qnil || !RB_TYPE_P(context_entries, T_HASH)) return failed; // If it exists, context_entries is expected to be a Hash[OpenTelemetry::Context::Key, OpenTelemetry::Trace::Span] - VALUE span = rb_hash_lookup(context_entries, otel_current_span_key); + VALUE span = safely_lookup_hash_without_going_into_ruby_code(context_entries, otel_current_span_key); if (span == Qnil) return failed; // If it exists, span_context is expected to be a OpenTelemetry::Trace::SpanContext (don't confuse it with OpenTelemetry::Context) @@ -1737,7 +1778,7 @@ static struct otel_span otel_span_from(VALUE otel_context, VALUE otel_current_sp VALUE trace_id = rb_ivar_get(span_context, at_trace_id_id /* @trace_id */); if (span_id == Qnil || trace_id == Qnil || !RB_TYPE_P(span_id, T_STRING) || !RB_TYPE_P(trace_id, T_STRING)) return failed; - return (struct otel_span) {.span = span, .span_id = span_id, .trace_id = trace_id}; + return (otel_span) {.span = span, .span_id = span_id, .trace_id = trace_id}; } // Otel span ids are represented as a big-endian 8-byte string @@ -1839,8 +1880,8 @@ static uint64_t otel_span_id_to_uint(VALUE otel_span_id) { // NOTE: In normal use, current_thread is expected to be == rb_thread_current(); the `current_thread` parameter only // exists to enable testing. VALUE thread_context_collector_sample_after_gvl_running(VALUE self_instance, VALUE current_thread, long current_monotonic_wall_time_ns) { - struct thread_context_collector_state *state; - TypedData_Get_Struct(self_instance, struct thread_context_collector_state, &thread_context_collector_typed_data, state); + thread_context_collector_state *state; + TypedData_Get_Struct(self_instance, thread_context_collector_state, &thread_context_collector_typed_data, state); if (!state->timeline_enabled) rb_raise(rb_eRuntimeError, "GVL profiling requires timeline to be enabled"); @@ -1854,7 +1895,7 @@ static uint64_t otel_span_id_to_uint(VALUE otel_span_id) { return Qfalse; } - struct per_thread_context *thread_context = get_or_create_context_for(current_thread, state); + per_thread_context *thread_context = get_or_create_context_for(current_thread, state); // We don't actually account for cpu-time during Waiting for GVL. BUT, we may chose to push an // extra sample to represent the period prior to Waiting for GVL. To support that, we retrieve the current @@ -1880,10 +1921,10 @@ static uint64_t otel_span_id_to_uint(VALUE otel_span_id) { // need to take when sampling cpu/wall-time for a thread that's in the "Waiting for GVL" state. __attribute__((warn_unused_result)) static bool handle_gvl_waiting( - struct thread_context_collector_state *state, + thread_context_collector_state *state, VALUE thread_being_sampled, VALUE stack_from_thread, - struct per_thread_context *thread_context, + per_thread_context *thread_context, sampling_buffer* sampling_buffer, long current_cpu_time_ns ) { @@ -1979,40 +2020,62 @@ static uint64_t otel_span_id_to_uint(VALUE otel_span_id) { static VALUE _native_on_gvl_waiting(DDTRACE_UNUSED VALUE self, VALUE thread) { ENFORCE_THREAD(thread); + debug_enter_unsafe_context(); + thread_context_collector_on_gvl_waiting(thread_from_thread_object(thread)); + + debug_leave_unsafe_context(); + return Qnil; } static VALUE _native_gvl_waiting_at_for(DDTRACE_UNUSED VALUE self, VALUE thread) { ENFORCE_THREAD(thread); + debug_enter_unsafe_context(); + intptr_t gvl_waiting_at = gvl_profiling_state_thread_object_get(thread); + + debug_leave_unsafe_context(); + return LONG2NUM(gvl_waiting_at); } static VALUE _native_on_gvl_running(DDTRACE_UNUSED VALUE self, VALUE thread) { ENFORCE_THREAD(thread); - return thread_context_collector_on_gvl_running(thread_from_thread_object(thread)) == ON_GVL_RUNNING_SAMPLE ? Qtrue : Qfalse; + debug_enter_unsafe_context(); + + VALUE result = thread_context_collector_on_gvl_running(thread_from_thread_object(thread)) == ON_GVL_RUNNING_SAMPLE ? Qtrue : Qfalse; + + debug_leave_unsafe_context(); + + return result; } static VALUE _native_sample_after_gvl_running(DDTRACE_UNUSED VALUE self, VALUE collector_instance, VALUE thread) { ENFORCE_THREAD(thread); - return thread_context_collector_sample_after_gvl_running( + debug_enter_unsafe_context(); + + VALUE result = thread_context_collector_sample_after_gvl_running( collector_instance, thread, monotonic_wall_time_now_ns(RAISE_ON_FAILURE) ); + + debug_leave_unsafe_context(); + + return result; } static VALUE _native_apply_delta_to_cpu_time_at_previous_sample_ns(DDTRACE_UNUSED VALUE self, VALUE collector_instance, VALUE thread, VALUE delta_ns) { ENFORCE_THREAD(thread); - struct thread_context_collector_state *state; - TypedData_Get_Struct(collector_instance, struct thread_context_collector_state, &thread_context_collector_typed_data, state); + thread_context_collector_state *state; + TypedData_Get_Struct(collector_instance, thread_context_collector_state, &thread_context_collector_typed_data, state); - struct per_thread_context *thread_context = get_context_for(thread, state); + per_thread_context *thread_context = get_context_for(thread, state); if (thread_context == NULL) rb_raise(rb_eArgError, "Unexpected: This method cannot be used unless the per-thread context for the thread already exists"); thread_context->cpu_time_at_previous_sample_ns += NUM2LONG(delta_ns); @@ -2022,11 +2085,45 @@ static uint64_t otel_span_id_to_uint(VALUE otel_span_id) { #else static bool handle_gvl_waiting( - DDTRACE_UNUSED struct thread_context_collector_state *state, + DDTRACE_UNUSED thread_context_collector_state *state, DDTRACE_UNUSED VALUE thread_being_sampled, DDTRACE_UNUSED VALUE stack_from_thread, - DDTRACE_UNUSED struct per_thread_context *thread_context, + DDTRACE_UNUSED per_thread_context *thread_context, DDTRACE_UNUSED sampling_buffer* sampling_buffer, DDTRACE_UNUSED long current_cpu_time_ns ) { return false; } #endif // NO_GVL_INSTRUMENTATION + +#define MAX_SAFE_LOOKUP_SIZE 16 + +typedef struct { VALUE lookup_key; VALUE result; } safe_lookup_hash_state; + +static int safe_lookup_hash_iterate(VALUE key, VALUE value, VALUE state_ptr) { + safe_lookup_hash_state *state = (safe_lookup_hash_state *) state_ptr; + + if (key == state->lookup_key) { + state->result = value; + return ST_STOP; + } + + return ST_CONTINUE; +} + +// This method exists because we need to look up a hash during sampling, but we don't want to invoke any +// Ruby code as a side effect. To be able to look up by hash, `rb_hash_lookup` calls `#hash` on the key, +// which we want to avoid. +// Thus, instead, we opt to just iterate through the hash and check if we can find what we're looking for. +// +// To avoid having too much overhead here we only iterate in hashes up to MAX_SAFE_LOOKUP_SIZE. +// Note that we don't even try to iterate if the hash is bigger -- this is to avoid flaky behavior where +// depending on the internal storage order of the hash we may or not find the key, and instead we always +// enforce the size. +static VALUE safely_lookup_hash_without_going_into_ruby_code(VALUE hash, VALUE key) { + if (!RB_TYPE_P(hash, T_HASH) || RHASH_SIZE(hash) > MAX_SAFE_LOOKUP_SIZE) return Qnil; + + safe_lookup_hash_state state = {.lookup_key = key, .result = Qnil}; + + rb_hash_foreach(hash, safe_lookup_hash_iterate, (VALUE) &state); + + return state.result; +} diff --git a/ext/datadog_profiling_native_extension/heap_recorder.h b/ext/datadog_profiling_native_extension/heap_recorder.h index bd298464e35..e59bf7d0187 100644 --- a/ext/datadog_profiling_native_extension/heap_recorder.h +++ b/ext/datadog_profiling_native_extension/heap_recorder.h @@ -17,7 +17,7 @@ typedef struct heap_recorder heap_recorder; // Extra data associated with each live object being tracked. -typedef struct live_object_data { +typedef struct { // The weight of this object from a sampling perspective. // // A notion of weight is preserved for each tracked object to allow for an approximate diff --git a/ext/datadog_profiling_native_extension/http_transport.c b/ext/datadog_profiling_native_extension/http_transport.c index d41ab7a6b4c..0852e36d7b6 100644 --- a/ext/datadog_profiling_native_extension/http_transport.c +++ b/ext/datadog_profiling_native_extension/http_transport.c @@ -13,13 +13,13 @@ static VALUE error_symbol = Qnil; // :error in Ruby static VALUE library_version_string = Qnil; -struct call_exporter_without_gvl_arguments { +typedef struct { ddog_prof_Exporter *exporter; ddog_prof_Exporter_Request_BuildResult *build_result; ddog_CancellationToken *cancel_token; ddog_prof_Exporter_SendResult result; bool send_ran; -}; +} call_exporter_without_gvl_arguments; static inline ddog_ByteSlice byte_slice_from_ruby_string(VALUE string); static VALUE _native_validate_exporter(VALUE self, VALUE exporter_configuration); @@ -165,7 +165,7 @@ static VALUE perform_export( // We'll release the Global VM Lock while we're calling send, so that the Ruby VM can continue to work while this // is pending - struct call_exporter_without_gvl_arguments args = + call_exporter_without_gvl_arguments args = {.exporter = exporter, .build_result = &build_result, .cancel_token = cancel_token, .send_ran = false}; // We use rb_thread_call_without_gvl2 instead of rb_thread_call_without_gvl as the gvl2 variant never raises any @@ -300,7 +300,7 @@ static VALUE _native_do_export( } static void *call_exporter_without_gvl(void *call_args) { - struct call_exporter_without_gvl_arguments *args = (struct call_exporter_without_gvl_arguments*) call_args; + call_exporter_without_gvl_arguments *args = (call_exporter_without_gvl_arguments*) call_args; args->result = ddog_prof_Exporter_send(args->exporter, &args->build_result->ok, args->cancel_token); args->send_ran = true; diff --git a/ext/datadog_profiling_native_extension/private_vm_api_access.c b/ext/datadog_profiling_native_extension/private_vm_api_access.c index 59e5c644882..f7c188861d7 100644 --- a/ext/datadog_profiling_native_extension/private_vm_api_access.c +++ b/ext/datadog_profiling_native_extension/private_vm_api_access.c @@ -800,3 +800,6 @@ static inline int ddtrace_imemo_type(VALUE imemo) { return current_thread; } #endif + +// Is the VM smack in the middle of raising an exception? +bool is_raised_flag_set(VALUE thread) { return thread_struct_from_object(thread)->ec->raised_flag > 0; } diff --git a/ext/datadog_profiling_native_extension/private_vm_api_access.h b/ext/datadog_profiling_native_extension/private_vm_api_access.h index c40992274cb..030ff1b5757 100644 --- a/ext/datadog_profiling_native_extension/private_vm_api_access.h +++ b/ext/datadog_profiling_native_extension/private_vm_api_access.h @@ -18,7 +18,7 @@ typedef struct { rb_nativethread_id_t owner; } current_gvl_owner; -typedef struct frame_info { +typedef struct { union { struct { VALUE iseq; @@ -68,3 +68,5 @@ const char *imemo_kind(VALUE imemo); #define ENFORCE_THREAD(value) \ { if (RB_UNLIKELY(!rb_typeddata_is_kind_of(value, RTYPEDDATA_TYPE(rb_thread_current())))) raise_unexpected_type(value, ADD_QUOTES(value), "Thread", __FILE__, __LINE__, __func__); } + +bool is_raised_flag_set(VALUE thread); diff --git a/ext/datadog_profiling_native_extension/profiling.c b/ext/datadog_profiling_native_extension/profiling.c index 315ca0d2954..e26bbf897a3 100644 --- a/ext/datadog_profiling_native_extension/profiling.c +++ b/ext/datadog_profiling_native_extension/profiling.c @@ -11,6 +11,7 @@ #include "ruby_helpers.h" #include "setup_signal_handler.h" #include "time_helpers.h" +#include "unsafe_api_calls_check.h" // Each class/module here is implemented in their separate file void collectors_cpu_and_wall_time_worker_init(VALUE profiling_module); @@ -56,6 +57,7 @@ void DDTRACE_EXPORT Init_datadog_profiling_native_extension(void) { collectors_thread_context_init(profiling_module); http_transport_init(profiling_module); stack_recorder_init(profiling_module); + unsafe_api_calls_check_init(); // Hosts methods used for testing the native code using RSpec VALUE testing_module = rb_define_module_under(native_extension_module, "Testing"); @@ -83,16 +85,16 @@ static VALUE native_working_p(DDTRACE_UNUSED VALUE _self) { return Qtrue; } -struct trigger_grab_gvl_and_raise_arguments { +typedef struct { VALUE exception_class; char *test_message; int test_message_arg; -}; +} trigger_grab_gvl_and_raise_arguments; static VALUE _native_grab_gvl_and_raise(DDTRACE_UNUSED VALUE _self, VALUE exception_class, VALUE test_message, VALUE test_message_arg, VALUE release_gvl) { ENFORCE_TYPE(test_message, T_STRING); - struct trigger_grab_gvl_and_raise_arguments args; + trigger_grab_gvl_and_raise_arguments args; args.exception_class = exception_class; args.test_message = StringValueCStr(test_message); @@ -108,7 +110,7 @@ static VALUE _native_grab_gvl_and_raise(DDTRACE_UNUSED VALUE _self, VALUE except } static void *trigger_grab_gvl_and_raise(void *trigger_args) { - struct trigger_grab_gvl_and_raise_arguments *args = (struct trigger_grab_gvl_and_raise_arguments *) trigger_args; + trigger_grab_gvl_and_raise_arguments *args = (trigger_grab_gvl_and_raise_arguments *) trigger_args; if (args->test_message_arg >= 0) { grab_gvl_and_raise(args->exception_class, "%s%d", args->test_message, args->test_message_arg); @@ -119,16 +121,16 @@ static void *trigger_grab_gvl_and_raise(void *trigger_args) { return NULL; } -struct trigger_grab_gvl_and_raise_syserr_arguments { +typedef struct { int syserr_errno; char *test_message; int test_message_arg; -}; +} trigger_grab_gvl_and_raise_syserr_arguments; static VALUE _native_grab_gvl_and_raise_syserr(DDTRACE_UNUSED VALUE _self, VALUE syserr_errno, VALUE test_message, VALUE test_message_arg, VALUE release_gvl) { ENFORCE_TYPE(test_message, T_STRING); - struct trigger_grab_gvl_and_raise_syserr_arguments args; + trigger_grab_gvl_and_raise_syserr_arguments args; args.syserr_errno = NUM2INT(syserr_errno); args.test_message = StringValueCStr(test_message); @@ -144,7 +146,7 @@ static VALUE _native_grab_gvl_and_raise_syserr(DDTRACE_UNUSED VALUE _self, VALUE } static void *trigger_grab_gvl_and_raise_syserr(void *trigger_args) { - struct trigger_grab_gvl_and_raise_syserr_arguments *args = (struct trigger_grab_gvl_and_raise_syserr_arguments *) trigger_args; + trigger_grab_gvl_and_raise_syserr_arguments *args = (trigger_grab_gvl_and_raise_syserr_arguments *) trigger_args; if (args->test_message_arg >= 0) { grab_gvl_and_raise_syserr(args->syserr_errno, "%s%d", args->test_message, args->test_message_arg); diff --git a/ext/datadog_profiling_native_extension/ruby_helpers.c b/ext/datadog_profiling_native_extension/ruby_helpers.c index 09b14d20855..34e9fa61c77 100644 --- a/ext/datadog_profiling_native_extension/ruby_helpers.c +++ b/ext/datadog_profiling_native_extension/ruby_helpers.c @@ -23,18 +23,18 @@ void ruby_helpers_init(void) { #define MAX_RAISE_MESSAGE_SIZE 256 -struct raise_arguments { +typedef struct { VALUE exception_class; char exception_message[MAX_RAISE_MESSAGE_SIZE]; -}; +} raise_args; static void *trigger_raise(void *raise_arguments) { - struct raise_arguments *args = (struct raise_arguments *) raise_arguments; + raise_args *args = (raise_args *) raise_arguments; rb_raise(args->exception_class, "%s", args->exception_message); } void grab_gvl_and_raise(VALUE exception_class, const char *format_string, ...) { - struct raise_arguments args; + raise_args args; args.exception_class = exception_class; @@ -55,18 +55,18 @@ void grab_gvl_and_raise(VALUE exception_class, const char *format_string, ...) { rb_bug("[ddtrace] Unexpected: Reached the end of grab_gvl_and_raise while raising '%s'\n", args.exception_message); } -struct syserr_raise_arguments { +typedef struct { int syserr_errno; char exception_message[MAX_RAISE_MESSAGE_SIZE]; -}; +} syserr_raise_args; static void *trigger_syserr_raise(void *syserr_raise_arguments) { - struct syserr_raise_arguments *args = (struct syserr_raise_arguments *) syserr_raise_arguments; + syserr_raise_args *args = (syserr_raise_args *) syserr_raise_arguments; rb_syserr_fail(args->syserr_errno, args->exception_message); } void grab_gvl_and_raise_syserr(int syserr_errno, const char *format_string, ...) { - struct syserr_raise_arguments args; + syserr_raise_args args; args.syserr_errno = syserr_errno; diff --git a/ext/datadog_profiling_native_extension/stack_recorder.c b/ext/datadog_profiling_native_extension/stack_recorder.c index 710b17356e2..349a9df89dd 100644 --- a/ext/datadog_profiling_native_extension/stack_recorder.c +++ b/ext/datadog_profiling_native_extension/stack_recorder.c @@ -173,18 +173,18 @@ static const uint8_t all_value_types_positions[] = // Struct for storing stats related to a profile in a particular slot. // These stats will share the same lifetime as the data in that profile slot. -typedef struct slot_stats { +typedef struct { // How many individual samples were recorded into this slot (un-weighted) uint64_t recorded_samples; } stats_slot; -typedef struct profile_slot { +typedef struct { ddog_prof_Profile profile; stats_slot stats; } profile_slot; // Contains native state for each instance -struct stack_recorder_state { +typedef struct { // Heap recorder instance heap_recorder *heap_recorder; bool heap_clean_after_gc_enabled; @@ -210,17 +210,17 @@ struct stack_recorder_state { long serialization_time_ns_max; uint64_t serialization_time_ns_total; } stats_lifetime; -}; +} stack_recorder_state; // Used to group mutex and the corresponding profile slot for easy unlocking after work is done. -typedef struct locked_profile_slot { +typedef struct { pthread_mutex_t *mutex; profile_slot *data; } locked_profile_slot; -struct call_serialize_without_gvl_arguments { +typedef struct { // Set by caller - struct stack_recorder_state *state; + stack_recorder_state *state; ddog_Timespec finish_timestamp; // Set by callee @@ -231,26 +231,26 @@ struct call_serialize_without_gvl_arguments { // Set by both bool serialize_ran; -}; +} call_serialize_without_gvl_arguments; static VALUE _native_new(VALUE klass); -static void initialize_slot_concurrency_control(struct stack_recorder_state *state); -static void initialize_profiles(struct stack_recorder_state *state, ddog_prof_Slice_ValueType sample_types); +static void initialize_slot_concurrency_control(stack_recorder_state *state); +static void initialize_profiles(stack_recorder_state *state, ddog_prof_Slice_ValueType sample_types); static void stack_recorder_typed_data_free(void *data); static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self); static VALUE _native_serialize(VALUE self, VALUE recorder_instance); static VALUE ruby_time_from(ddog_Timespec ddprof_time); static void *call_serialize_without_gvl(void *call_args); -static locked_profile_slot sampler_lock_active_profile(struct stack_recorder_state *state); +static locked_profile_slot sampler_lock_active_profile(stack_recorder_state *state); static void sampler_unlock_active_profile(locked_profile_slot active_slot); -static profile_slot* serializer_flip_active_and_inactive_slots(struct stack_recorder_state *state); +static profile_slot* serializer_flip_active_and_inactive_slots(stack_recorder_state *state); static VALUE _native_active_slot(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance); static VALUE _native_is_slot_one_mutex_locked(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance); static VALUE _native_is_slot_two_mutex_locked(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance); static VALUE test_slot_mutex_state(VALUE recorder_instance, int slot); static ddog_Timespec system_epoch_now_timespec(void); static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE recorder_instance); -static void serializer_set_start_timestamp_for_next_profile(struct stack_recorder_state *state, ddog_Timespec start_time); +static void serializer_set_start_timestamp_for_next_profile(stack_recorder_state *state, ddog_Timespec start_time); static VALUE _native_record_endpoint(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE local_root_span_id, VALUE endpoint); static void reset_profile_slot(profile_slot *slot, ddog_Timespec *start_time /* Can be null */); static VALUE _native_track_object(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE new_obj, VALUE weight, VALUE alloc_class); @@ -316,7 +316,7 @@ static const rb_data_type_t stack_recorder_typed_data = { }; static VALUE _native_new(VALUE klass) { - struct stack_recorder_state *state = ruby_xcalloc(1, sizeof(struct stack_recorder_state)); + stack_recorder_state *state = ruby_xcalloc(1, sizeof(stack_recorder_state)); // Note: Any exceptions raised from this note until the TypedData_Wrap_Struct call will lead to the state memory // being leaked. @@ -354,7 +354,7 @@ static VALUE _native_new(VALUE klass) { return stack_recorder; } -static void initialize_slot_concurrency_control(struct stack_recorder_state *state) { +static void initialize_slot_concurrency_control(stack_recorder_state *state) { state->mutex_slot_one = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER; state->mutex_slot_two = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER; @@ -364,7 +364,7 @@ static void initialize_slot_concurrency_control(struct stack_recorder_state *sta state->active_slot = 1; } -static void initialize_profiles(struct stack_recorder_state *state, ddog_prof_Slice_ValueType sample_types) { +static void initialize_profiles(stack_recorder_state *state, ddog_prof_Slice_ValueType sample_types) { ddog_prof_Profile_NewResult slot_one_profile_result = ddog_prof_Profile_new(sample_types, NULL /* period is optional */, NULL /* start_time is optional */); @@ -391,7 +391,7 @@ static void initialize_profiles(struct stack_recorder_state *state, ddog_prof_Sl } static void stack_recorder_typed_data_free(void *state_ptr) { - struct stack_recorder_state *state = (struct stack_recorder_state *) state_ptr; + stack_recorder_state *state = (stack_recorder_state *) state_ptr; pthread_mutex_destroy(&state->mutex_slot_one); ddog_prof_Profile_drop(&state->profile_slot_one.profile); @@ -426,8 +426,8 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel ENFORCE_BOOLEAN(timeline_enabled); ENFORCE_BOOLEAN(heap_clean_after_gc_enabled); - struct stack_recorder_state *state; - TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state); + stack_recorder_state *state; + TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state); state->heap_clean_after_gc_enabled = (heap_clean_after_gc_enabled == Qtrue); @@ -517,8 +517,8 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel } static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) { - struct stack_recorder_state *state; - TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state); + stack_recorder_state *state; + TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state); ddog_Timespec finish_timestamp = system_epoch_now_timespec(); // Need to do this while still holding on to the Global VM Lock; see comments on method for why @@ -532,7 +532,7 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan // We'll release the Global VM Lock while we're calling serialize, so that the Ruby VM can continue to work while this // is pending - struct call_serialize_without_gvl_arguments args = { + call_serialize_without_gvl_arguments args = { .state = state, .finish_timestamp = finish_timestamp, .serialize_ran = false @@ -597,8 +597,8 @@ static VALUE ruby_time_from(ddog_Timespec ddprof_time) { } void record_sample(VALUE recorder_instance, ddog_prof_Slice_Location locations, sample_values values, sample_labels labels) { - struct stack_recorder_state *state; - TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state); + stack_recorder_state *state; + TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state); locked_profile_slot active_slot = sampler_lock_active_profile(state); @@ -652,8 +652,8 @@ void record_sample(VALUE recorder_instance, ddog_prof_Slice_Location locations, } void track_object(VALUE recorder_instance, VALUE new_object, unsigned int sample_weight, ddog_CharSlice *alloc_class) { - struct stack_recorder_state *state; - TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state); + stack_recorder_state *state; + TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state); // FIXME: Heap sampling currently has to be done in 2 parts because the construction of locations is happening // very late in the allocation-sampling path (which is shared with the cpu sampling path). This can // be fixed with some refactoring but for now this leads to a less impactful change. @@ -661,8 +661,8 @@ void track_object(VALUE recorder_instance, VALUE new_object, unsigned int sample } void record_endpoint(VALUE recorder_instance, uint64_t local_root_span_id, ddog_CharSlice endpoint) { - struct stack_recorder_state *state; - TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state); + stack_recorder_state *state; + TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state); locked_profile_slot active_slot = sampler_lock_active_profile(state); @@ -676,8 +676,8 @@ void record_endpoint(VALUE recorder_instance, uint64_t local_root_span_id, ddog_ } void recorder_after_gc_step(VALUE recorder_instance) { - struct stack_recorder_state *state; - TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state); + stack_recorder_state *state; + TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state); if (state->heap_clean_after_gc_enabled) heap_recorder_update_young_objects(state->heap_recorder); } @@ -687,7 +687,7 @@ void recorder_after_gc_step(VALUE recorder_instance) { // Heap recorder iteration context allows us access to stack recorder state and profile being serialized // during iteration of heap recorder live objects. typedef struct heap_recorder_iteration_context { - struct stack_recorder_state *state; + stack_recorder_state *state; profile_slot *slot; bool error; @@ -749,7 +749,7 @@ static bool add_heap_sample_to_active_profile_without_gvl(heap_recorder_iteratio return true; } -static void build_heap_profile_without_gvl(struct stack_recorder_state *state, profile_slot *slot) { +static void build_heap_profile_without_gvl(stack_recorder_state *state, profile_slot *slot) { heap_recorder_iteration_context iteration_context = { .state = state, .slot = slot, @@ -770,7 +770,7 @@ static void build_heap_profile_without_gvl(struct stack_recorder_state *state, p } static void *call_serialize_without_gvl(void *call_args) { - struct call_serialize_without_gvl_arguments *args = (struct call_serialize_without_gvl_arguments *) call_args; + call_serialize_without_gvl_arguments *args = (call_serialize_without_gvl_arguments *) call_args; long serialize_no_gvl_start_time_ns = monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE); @@ -796,7 +796,7 @@ VALUE enforce_recorder_instance(VALUE object) { return object; } -static locked_profile_slot sampler_lock_active_profile(struct stack_recorder_state *state) { +static locked_profile_slot sampler_lock_active_profile(stack_recorder_state *state) { int error; for (int attempts = 0; attempts < 2; attempts++) { @@ -823,7 +823,7 @@ static void sampler_unlock_active_profile(locked_profile_slot active_slot) { ENFORCE_SUCCESS_GVL(pthread_mutex_unlock(active_slot.mutex)); } -static profile_slot* serializer_flip_active_and_inactive_slots(struct stack_recorder_state *state) { +static profile_slot* serializer_flip_active_and_inactive_slots(stack_recorder_state *state) { int previously_active_slot = state->active_slot; if (previously_active_slot != 1 && previously_active_slot != 2) { @@ -849,8 +849,8 @@ static profile_slot* serializer_flip_active_and_inactive_slots(struct stack_reco // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec. // It SHOULD NOT be used for other purposes. static VALUE _native_active_slot(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) { - struct stack_recorder_state *state; - TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state); + stack_recorder_state *state; + TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state); return INT2NUM(state->active_slot); } @@ -864,8 +864,8 @@ static VALUE _native_is_slot_one_mutex_locked(DDTRACE_UNUSED VALUE _self, VALUE static VALUE _native_is_slot_two_mutex_locked(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) { return test_slot_mutex_state(recorder_instance, 2); } static VALUE test_slot_mutex_state(VALUE recorder_instance, int slot) { - struct stack_recorder_state *state; - TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state); + stack_recorder_state *state; + TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state); pthread_mutex_t *slot_mutex = (slot == 1) ? &state->mutex_slot_one : &state->mutex_slot_two; @@ -895,8 +895,8 @@ static ddog_Timespec system_epoch_now_timespec(void) { // Assumption: This method gets called BEFORE restarting profiling -- e.g. there are no components attempting to // trigger samples at the same time. static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE recorder_instance) { - struct stack_recorder_state *state; - TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state); + stack_recorder_state *state; + TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state); // In case the fork happened halfway through `serializer_flip_active_and_inactive_slots` execution and the // resulting state is inconsistent, we make sure to reset it back to the initial state. @@ -912,7 +912,7 @@ static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE recorder_ // Assumption 1: This method is called with the GVL being held, because `ddog_prof_Profile_reset` mutates the profile and must // not be interrupted part-way through by a VM fork. -static void serializer_set_start_timestamp_for_next_profile(struct stack_recorder_state *state, ddog_Timespec start_time) { +static void serializer_set_start_timestamp_for_next_profile(stack_recorder_state *state, ddog_Timespec start_time) { // Before making this profile active, we reset it so that it uses the correct start_time for its start profile_slot *next_profile_slot = (state->active_slot == 1) ? &state->profile_slot_two : &state->profile_slot_one; reset_profile_slot(next_profile_slot, &start_time); @@ -972,8 +972,8 @@ static void reset_profile_slot(profile_slot *slot, ddog_Timespec *start_time /* // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec. // It SHOULD NOT be used for other purposes. static VALUE _native_start_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) { - struct stack_recorder_state *state; - TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state); + stack_recorder_state *state; + TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state); heap_recorder_prepare_iteration(state->heap_recorder); @@ -983,8 +983,8 @@ static VALUE _native_start_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _se // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec. // It SHOULD NOT be used for other purposes. static VALUE _native_end_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) { - struct stack_recorder_state *state; - TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state); + stack_recorder_state *state; + TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state); heap_recorder_finish_iteration(state->heap_recorder); @@ -994,15 +994,15 @@ static VALUE _native_end_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _self // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec. // It SHOULD NOT be used for other purposes. static VALUE _native_debug_heap_recorder(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) { - struct stack_recorder_state *state; - TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state); + stack_recorder_state *state; + TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state); return heap_recorder_testonly_debug(state->heap_recorder); } static VALUE _native_stats(DDTRACE_UNUSED VALUE self, VALUE recorder_instance) { - struct stack_recorder_state *state; - TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state); + stack_recorder_state *state; + TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state); uint64_t total_serializations = state->stats_lifetime.serialization_successes + state->stats_lifetime.serialization_failures; @@ -1040,15 +1040,15 @@ static VALUE build_profile_stats(profile_slot *slot, long serialization_time_ns, static VALUE _native_is_object_recorded(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE obj_id) { ENFORCE_TYPE(obj_id, T_FIXNUM); - struct stack_recorder_state *state; - TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state); + stack_recorder_state *state; + TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state); return heap_recorder_testonly_is_object_recorded(state->heap_recorder, obj_id); } static VALUE _native_heap_recorder_reset_last_update(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) { - struct stack_recorder_state *state; - TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state); + stack_recorder_state *state; + TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state); heap_recorder_testonly_reset_last_update(state->heap_recorder); diff --git a/ext/datadog_profiling_native_extension/stack_recorder.h b/ext/datadog_profiling_native_extension/stack_recorder.h index 7a500c42c1b..38b228afc78 100644 --- a/ext/datadog_profiling_native_extension/stack_recorder.h +++ b/ext/datadog_profiling_native_extension/stack_recorder.h @@ -13,7 +13,7 @@ typedef struct { int64_t timeline_wall_time_ns; } sample_values; -typedef struct sample_labels { +typedef struct { ddog_prof_Slice_Label labels; // This is used to allow the `Collectors::Stack` to modify the existing label, if any. This MUST be NULL or point diff --git a/ext/datadog_profiling_native_extension/time_helpers.h b/ext/datadog_profiling_native_extension/time_helpers.h index 87bc5341fc9..08390cd8c11 100644 --- a/ext/datadog_profiling_native_extension/time_helpers.h +++ b/ext/datadog_profiling_native_extension/time_helpers.h @@ -39,7 +39,7 @@ static inline long system_epoch_time_now_ns(raise_on_failure_setting raise_on_fa // https://docs.redhat.com/en/documentation/red_hat_enterprise_linux_for_real_time/7/html/reference_guide/sect-posix_clocks#Using_clock_getres_to_compare_clock_resolution // We introduce here a separate type for it, so as to make it harder to misuse/more explicit when these timestamps are used -typedef struct coarse_instant { +typedef struct { long timestamp_ns; } coarse_instant; diff --git a/ext/datadog_profiling_native_extension/unsafe_api_calls_check.c b/ext/datadog_profiling_native_extension/unsafe_api_calls_check.c new file mode 100644 index 00000000000..c3c23b7f1c7 --- /dev/null +++ b/ext/datadog_profiling_native_extension/unsafe_api_calls_check.c @@ -0,0 +1,47 @@ +#include +#include +#include + +#include "datadog_ruby_common.h" +#include "unsafe_api_calls_check.h" +#include "extconf.h" + +static bool inside_unsafe_context = false; + +#ifndef NO_POSTPONED_TRIGGER + static rb_postponed_job_handle_t check_for_unsafe_api_calls_handle; +#endif + +static void check_for_unsafe_api_calls(DDTRACE_UNUSED void *_unused); + +void unsafe_api_calls_check_init(void) { + #ifndef NO_POSTPONED_TRIGGER + int unused_flags = 0; + + check_for_unsafe_api_calls_handle = rb_postponed_job_preregister(unused_flags, check_for_unsafe_api_calls, NULL); + + if (check_for_unsafe_api_calls_handle == POSTPONED_JOB_HANDLE_INVALID) { + rb_raise(rb_eRuntimeError, "Failed to register check_for_unsafe_api_calls_handle postponed job (got POSTPONED_JOB_HANDLE_INVALID)"); + } + #endif +} + +void debug_enter_unsafe_context(void) { + inside_unsafe_context = true; + + #ifndef NO_POSTPONED_TRIGGER + rb_postponed_job_trigger(check_for_unsafe_api_calls_handle); + #else + rb_postponed_job_register(0, check_for_unsafe_api_calls, NULL); + #endif +} + +void debug_leave_unsafe_context(void) { + inside_unsafe_context = false; +} + +static void check_for_unsafe_api_calls(DDTRACE_UNUSED void *_unused) { + if (inside_unsafe_context) rb_bug( + "Datadog Ruby profiler detected callback nested inside sample. Please report this at https://github.com/datadog/dd-trace-rb/blob/master/CONTRIBUTING.md#found-a-bug" + ); +} diff --git a/ext/datadog_profiling_native_extension/unsafe_api_calls_check.h b/ext/datadog_profiling_native_extension/unsafe_api_calls_check.h new file mode 100644 index 00000000000..c6c8dc56cf5 --- /dev/null +++ b/ext/datadog_profiling_native_extension/unsafe_api_calls_check.h @@ -0,0 +1,31 @@ +#pragma once + +// This checker is used to detect accidental thread scheduling switching points happening during profiling sampling. +// +// Specifically, when the profiler is sampling, we're never supposed to call into Ruby code (e.g. methods +// implemented using Ruby code) or allocate Ruby objects. +// That's because those events introduce thread switch points, and really we don't the VM switching between threads +// in the middle of the profiler sampling. +// This includes raising exceptions, unless we're trying to stop the profiler, and even then we must be careful. +// +// The above is especially true in situations such as GC profiling or allocation/heap profiling, as in those situations +// we can even crash the Ruby VM if we switch away at the wrong time. +// +// The below APIs can be used to detect these situations. They work by relying on the following observation: +// in most (all?) thread switch points, Ruby will check for interrupts and run the postponed jobs. +// +// Thus, if we set a flag while we're sampling (inside_unsafe_context), trigger the postponed job, and then only unset +// the flag after sampling, he correct thing to happen is that the postponed job should never see the flag. +// +// If, however, we have a bug and there's a thread switch point, our postponed job will see the flag and immediately +// stop the Ruby VM before further damage happens (and hopefully giving us a stack trace clearly pointing to the culprit). + +void unsafe_api_calls_check_init(void); + +// IMPORTANT: This method **MUST** only be called from test code, as it causes an immediate hard-crash on the Ruby VM +// when it detects a potential issue, and that's not something we want for production apps. +// +// In the future we may introduce some kind of setting (off by default) to also allow this to be safely be used +// in production code if needed. +void debug_enter_unsafe_context(void); +void debug_leave_unsafe_context(void); diff --git a/gemfiles/jruby_9.2_elasticsearch_7.gemfile.lock b/gemfiles/jruby_9.2_elasticsearch_7.gemfile.lock index 36fc02fbb05..5bb58b57c32 100644 --- a/gemfiles/jruby_9.2_elasticsearch_7.gemfile.lock +++ b/gemfiles/jruby_9.2_elasticsearch_7.gemfile.lock @@ -60,8 +60,8 @@ GEM faraday-em_synchrony (1.0.0) faraday-excon (1.1.0) faraday-httpclient (1.0.1) - faraday-multipart (1.0.4) - multipart-post (~> 2) + faraday-multipart (1.1.0) + multipart-post (~> 2.0) faraday-net_http (1.0.2) faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) diff --git a/gemfiles/jruby_9.2_elasticsearch_8.gemfile.lock b/gemfiles/jruby_9.2_elasticsearch_8.gemfile.lock index f81cb6e0c64..85899ece000 100644 --- a/gemfiles/jruby_9.2_elasticsearch_8.gemfile.lock +++ b/gemfiles/jruby_9.2_elasticsearch_8.gemfile.lock @@ -58,8 +58,8 @@ GEM faraday-em_synchrony (1.0.0) faraday-excon (1.1.0) faraday-httpclient (1.0.1) - faraday-multipart (1.0.4) - multipart-post (~> 2) + faraday-multipart (1.1.0) + multipart-post (~> 2.0) faraday-net_http (1.0.2) faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) diff --git a/gemfiles/jruby_9.2_elasticsearch_latest.gemfile.lock b/gemfiles/jruby_9.2_elasticsearch_latest.gemfile.lock index 5e50b504953..c36be87792e 100644 --- a/gemfiles/jruby_9.2_elasticsearch_latest.gemfile.lock +++ b/gemfiles/jruby_9.2_elasticsearch_latest.gemfile.lock @@ -60,8 +60,8 @@ GEM faraday-em_synchrony (1.0.0) faraday-excon (1.1.0) faraday-httpclient (1.0.1) - faraday-multipart (1.0.4) - multipart-post (~> 2) + faraday-multipart (1.1.0) + multipart-post (~> 2.0) faraday-net_http (1.0.2) faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) diff --git a/gemfiles/jruby_9.2_opensearch_2.gemfile.lock b/gemfiles/jruby_9.2_opensearch_2.gemfile.lock index aeb13ed3efe..2b780aa3b94 100644 --- a/gemfiles/jruby_9.2_opensearch_2.gemfile.lock +++ b/gemfiles/jruby_9.2_opensearch_2.gemfile.lock @@ -50,8 +50,8 @@ GEM faraday-em_synchrony (1.0.0) faraday-excon (1.1.0) faraday-httpclient (1.0.1) - faraday-multipart (1.0.4) - multipart-post (~> 2) + faraday-multipart (1.1.0) + multipart-post (~> 2.0) faraday-net_http (1.0.2) faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) diff --git a/gemfiles/jruby_9.2_opensearch_3.gemfile.lock b/gemfiles/jruby_9.2_opensearch_3.gemfile.lock index 8370df63724..e96582e849c 100644 --- a/gemfiles/jruby_9.2_opensearch_3.gemfile.lock +++ b/gemfiles/jruby_9.2_opensearch_3.gemfile.lock @@ -50,8 +50,8 @@ GEM faraday-em_synchrony (1.0.0) faraday-excon (1.1.0) faraday-httpclient (1.0.1) - faraday-multipart (1.0.4) - multipart-post (~> 2) + faraday-multipart (1.1.0) + multipart-post (~> 2.0) faraday-net_http (1.0.2) faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) diff --git a/gemfiles/jruby_9.2_opensearch_latest.gemfile.lock b/gemfiles/jruby_9.2_opensearch_latest.gemfile.lock index 79e21f4af9e..c3ed52188b3 100644 --- a/gemfiles/jruby_9.2_opensearch_latest.gemfile.lock +++ b/gemfiles/jruby_9.2_opensearch_latest.gemfile.lock @@ -52,8 +52,8 @@ GEM faraday-em_synchrony (1.0.0) faraday-excon (1.1.0) faraday-httpclient (1.0.1) - faraday-multipart (1.0.4) - multipart-post (~> 2) + faraday-multipart (1.1.0) + multipart-post (~> 2.0) faraday-net_http (1.0.2) faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) diff --git a/gemfiles/jruby_9.2_stripe_latest.gemfile.lock b/gemfiles/jruby_9.2_stripe_latest.gemfile.lock index 8ef169b22c1..b6802cce920 100644 --- a/gemfiles/jruby_9.2_stripe_latest.gemfile.lock +++ b/gemfiles/jruby_9.2_stripe_latest.gemfile.lock @@ -87,7 +87,7 @@ GEM simplecov_json_formatter (0.1.4) spoon (0.0.6) ffi - stripe (13.2.0) + stripe (13.3.0) warning (1.4.0) webmock (3.23.1) addressable (>= 2.8.0) diff --git a/gemfiles/jruby_9.3_stripe_latest.gemfile.lock b/gemfiles/jruby_9.3_stripe_latest.gemfile.lock index b419d95c301..be48d6015ac 100644 --- a/gemfiles/jruby_9.3_stripe_latest.gemfile.lock +++ b/gemfiles/jruby_9.3_stripe_latest.gemfile.lock @@ -119,7 +119,7 @@ GEM simplecov_json_formatter (0.1.4) spoon (0.0.6) ffi - stripe (13.2.0) + stripe (13.3.0) unicode-display_width (2.6.0) warning (1.4.0) webmock (3.23.1) diff --git a/gemfiles/jruby_9.4_elasticsearch_7.gemfile.lock b/gemfiles/jruby_9.4_elasticsearch_7.gemfile.lock index 1cadcdf0064..d3da187035b 100644 --- a/gemfiles/jruby_9.4_elasticsearch_7.gemfile.lock +++ b/gemfiles/jruby_9.4_elasticsearch_7.gemfile.lock @@ -53,13 +53,13 @@ GEM net-http (>= 0.5.0) ffi (1.17.0-java) hashdiff (1.0.1) - json (2.9.0-java) + json (2.9.1-java) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0) libddwaf (1.18.0.0.0-java) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.0.0) msgpack (1.7.5-java) diff --git a/gemfiles/jruby_9.4_elasticsearch_8.gemfile.lock b/gemfiles/jruby_9.4_elasticsearch_8.gemfile.lock index 37e369bfcdb..99944c060cc 100644 --- a/gemfiles/jruby_9.4_elasticsearch_8.gemfile.lock +++ b/gemfiles/jruby_9.4_elasticsearch_8.gemfile.lock @@ -51,13 +51,13 @@ GEM net-http (>= 0.5.0) ffi (1.17.0-java) hashdiff (1.0.1) - json (2.9.0-java) + json (2.9.1-java) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0) libddwaf (1.18.0.0.0-java) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.0.0) msgpack (1.7.5-java) diff --git a/gemfiles/jruby_9.4_elasticsearch_latest.gemfile.lock b/gemfiles/jruby_9.4_elasticsearch_latest.gemfile.lock index b9f454f99d5..2523b28c887 100644 --- a/gemfiles/jruby_9.4_elasticsearch_latest.gemfile.lock +++ b/gemfiles/jruby_9.4_elasticsearch_latest.gemfile.lock @@ -53,13 +53,13 @@ GEM net-http (>= 0.5.0) ffi (1.17.0-java) hashdiff (1.1.1) - json (2.9.0-java) + json (2.9.1-java) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0) libddwaf (1.18.0.0.0-java) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.1.0) msgpack (1.7.5-java) diff --git a/gemfiles/jruby_9.4_opensearch_2.gemfile.lock b/gemfiles/jruby_9.4_opensearch_2.gemfile.lock index 21cc1a9afa7..dab25836ebc 100644 --- a/gemfiles/jruby_9.4_opensearch_2.gemfile.lock +++ b/gemfiles/jruby_9.4_opensearch_2.gemfile.lock @@ -43,13 +43,13 @@ GEM net-http (>= 0.5.0) ffi (1.17.0-java) hashdiff (1.0.1) - json (2.9.0-java) + json (2.9.1-java) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0) libddwaf (1.18.0.0.0-java) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.0.0) msgpack (1.7.5-java) diff --git a/gemfiles/jruby_9.4_opensearch_3.gemfile.lock b/gemfiles/jruby_9.4_opensearch_3.gemfile.lock index 40b987b2e71..aee58dbad8f 100644 --- a/gemfiles/jruby_9.4_opensearch_3.gemfile.lock +++ b/gemfiles/jruby_9.4_opensearch_3.gemfile.lock @@ -43,13 +43,13 @@ GEM net-http (>= 0.5.0) ffi (1.17.0-java) hashdiff (1.0.1) - json (2.9.0-java) + json (2.9.1-java) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0) libddwaf (1.18.0.0.0-java) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.0.0) msgpack (1.7.5-java) diff --git a/gemfiles/jruby_9.4_opensearch_latest.gemfile.lock b/gemfiles/jruby_9.4_opensearch_latest.gemfile.lock index 978e087574b..baa665b1de5 100644 --- a/gemfiles/jruby_9.4_opensearch_latest.gemfile.lock +++ b/gemfiles/jruby_9.4_opensearch_latest.gemfile.lock @@ -45,13 +45,13 @@ GEM net-http (>= 0.5.0) ffi (1.17.0-java) hashdiff (1.1.1) - json (2.9.0-java) + json (2.9.1-java) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0) libddwaf (1.18.0.0.0-java) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.1.0) msgpack (1.7.5-java) diff --git a/gemfiles/jruby_9.4_stripe_latest.gemfile.lock b/gemfiles/jruby_9.4_stripe_latest.gemfile.lock index 5d17b7942e0..2f28c1ff44e 100644 --- a/gemfiles/jruby_9.4_stripe_latest.gemfile.lock +++ b/gemfiles/jruby_9.4_stripe_latest.gemfile.lock @@ -119,7 +119,7 @@ GEM simplecov_json_formatter (0.1.4) spoon (0.0.6) ffi - stripe (13.2.0) + stripe (13.3.0) unicode-display_width (2.6.0) warning (1.4.0) webmock (3.23.1) diff --git a/gemfiles/ruby_2.5_elasticsearch_7.gemfile.lock b/gemfiles/ruby_2.5_elasticsearch_7.gemfile.lock index 5a30d602034..1dcdb60f488 100644 --- a/gemfiles/ruby_2.5_elasticsearch_7.gemfile.lock +++ b/gemfiles/ruby_2.5_elasticsearch_7.gemfile.lock @@ -64,8 +64,8 @@ GEM faraday-em_synchrony (1.0.0) faraday-excon (1.1.0) faraday-httpclient (1.0.1) - faraday-multipart (1.0.4) - multipart-post (~> 2) + faraday-multipart (1.1.0) + multipart-post (~> 2.0) faraday-net_http (1.0.2) faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) diff --git a/gemfiles/ruby_2.5_elasticsearch_8.gemfile.lock b/gemfiles/ruby_2.5_elasticsearch_8.gemfile.lock index 39182347aa0..33dfdea8b25 100644 --- a/gemfiles/ruby_2.5_elasticsearch_8.gemfile.lock +++ b/gemfiles/ruby_2.5_elasticsearch_8.gemfile.lock @@ -62,8 +62,8 @@ GEM faraday-em_synchrony (1.0.0) faraday-excon (1.1.0) faraday-httpclient (1.0.1) - faraday-multipart (1.0.4) - multipart-post (~> 2) + faraday-multipart (1.1.0) + multipart-post (~> 2.0) faraday-net_http (1.0.2) faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) diff --git a/gemfiles/ruby_2.5_elasticsearch_latest.gemfile.lock b/gemfiles/ruby_2.5_elasticsearch_latest.gemfile.lock index 04c386a3d86..c712643c1a1 100644 --- a/gemfiles/ruby_2.5_elasticsearch_latest.gemfile.lock +++ b/gemfiles/ruby_2.5_elasticsearch_latest.gemfile.lock @@ -64,8 +64,8 @@ GEM faraday-em_synchrony (1.0.0) faraday-excon (1.1.0) faraday-httpclient (1.0.1) - faraday-multipart (1.0.4) - multipart-post (~> 2) + faraday-multipart (1.1.0) + multipart-post (~> 2.0) faraday-net_http (1.0.2) faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) diff --git a/gemfiles/ruby_2.5_opensearch_2.gemfile.lock b/gemfiles/ruby_2.5_opensearch_2.gemfile.lock index de1d0e21eb4..faf171fa0ed 100644 --- a/gemfiles/ruby_2.5_opensearch_2.gemfile.lock +++ b/gemfiles/ruby_2.5_opensearch_2.gemfile.lock @@ -54,8 +54,8 @@ GEM faraday-em_synchrony (1.0.0) faraday-excon (1.1.0) faraday-httpclient (1.0.1) - faraday-multipart (1.0.4) - multipart-post (~> 2) + faraday-multipart (1.1.0) + multipart-post (~> 2.0) faraday-net_http (1.0.2) faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) diff --git a/gemfiles/ruby_2.5_opensearch_3.gemfile.lock b/gemfiles/ruby_2.5_opensearch_3.gemfile.lock index 3adaf4b0b67..536089c8374 100644 --- a/gemfiles/ruby_2.5_opensearch_3.gemfile.lock +++ b/gemfiles/ruby_2.5_opensearch_3.gemfile.lock @@ -54,8 +54,8 @@ GEM faraday-em_synchrony (1.0.0) faraday-excon (1.1.0) faraday-httpclient (1.0.1) - faraday-multipart (1.0.4) - multipart-post (~> 2) + faraday-multipart (1.1.0) + multipart-post (~> 2.0) faraday-net_http (1.0.2) faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) diff --git a/gemfiles/ruby_2.5_opensearch_latest.gemfile.lock b/gemfiles/ruby_2.5_opensearch_latest.gemfile.lock index 2893ac69698..da610b4504b 100644 --- a/gemfiles/ruby_2.5_opensearch_latest.gemfile.lock +++ b/gemfiles/ruby_2.5_opensearch_latest.gemfile.lock @@ -56,8 +56,8 @@ GEM faraday-em_synchrony (1.0.0) faraday-excon (1.1.0) faraday-httpclient (1.0.1) - faraday-multipart (1.0.4) - multipart-post (~> 2) + faraday-multipart (1.1.0) + multipart-post (~> 2.0) faraday-net_http (1.0.2) faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) diff --git a/gemfiles/ruby_2.5_stripe_latest.gemfile.lock b/gemfiles/ruby_2.5_stripe_latest.gemfile.lock index 83e8793fc5d..a7beba6ef22 100644 --- a/gemfiles/ruby_2.5_stripe_latest.gemfile.lock +++ b/gemfiles/ruby_2.5_stripe_latest.gemfile.lock @@ -95,7 +95,7 @@ GEM simplecov (~> 0.19) simplecov-html (0.13.1) simplecov_json_formatter (0.1.4) - stripe (13.2.0) + stripe (13.3.0) warning (1.4.0) webmock (3.23.1) addressable (>= 2.8.0) diff --git a/gemfiles/ruby_2.6_stripe_latest.gemfile.lock b/gemfiles/ruby_2.6_stripe_latest.gemfile.lock index 5a02efd9ce8..129e917d21e 100644 --- a/gemfiles/ruby_2.6_stripe_latest.gemfile.lock +++ b/gemfiles/ruby_2.6_stripe_latest.gemfile.lock @@ -129,7 +129,7 @@ GEM simplecov (~> 0.19) simplecov-html (0.13.1) simplecov_json_formatter (0.1.4) - stripe (13.2.0) + stripe (13.3.0) unicode-display_width (2.6.0) warning (1.4.0) webmock (3.23.1) diff --git a/gemfiles/ruby_2.7_stripe_latest.gemfile.lock b/gemfiles/ruby_2.7_stripe_latest.gemfile.lock index 312e78df324..83c9c3305ed 100644 --- a/gemfiles/ruby_2.7_stripe_latest.gemfile.lock +++ b/gemfiles/ruby_2.7_stripe_latest.gemfile.lock @@ -128,7 +128,7 @@ GEM simplecov (~> 0.19) simplecov-html (0.13.1) simplecov_json_formatter (0.1.4) - stripe (13.2.0) + stripe (13.3.0) unicode-display_width (2.6.0) warning (1.4.0) webmock (3.23.1) diff --git a/gemfiles/ruby_3.0_elasticsearch_7.gemfile.lock b/gemfiles/ruby_3.0_elasticsearch_7.gemfile.lock index 178b8e8548e..c30113156d8 100644 --- a/gemfiles/ruby_3.0_elasticsearch_7.gemfile.lock +++ b/gemfiles/ruby_3.0_elasticsearch_7.gemfile.lock @@ -61,7 +61,7 @@ GEM google-protobuf (3.24.4-aarch64-linux) google-protobuf (3.24.4-x86_64-linux) hashdiff (1.0.1) - json (2.9.0) + json (2.9.1) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0-aarch64-linux) @@ -70,7 +70,7 @@ GEM ffi (~> 1.0) libddwaf (1.18.0.0.0-x86_64-linux) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.0.0) msgpack (1.7.5) diff --git a/gemfiles/ruby_3.0_elasticsearch_8.gemfile.lock b/gemfiles/ruby_3.0_elasticsearch_8.gemfile.lock index b3405b341f1..99690f81464 100644 --- a/gemfiles/ruby_3.0_elasticsearch_8.gemfile.lock +++ b/gemfiles/ruby_3.0_elasticsearch_8.gemfile.lock @@ -59,7 +59,7 @@ GEM google-protobuf (3.24.4-aarch64-linux) google-protobuf (3.24.4-x86_64-linux) hashdiff (1.0.1) - json (2.9.0) + json (2.9.1) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0-aarch64-linux) @@ -68,7 +68,7 @@ GEM ffi (~> 1.0) libddwaf (1.18.0.0.0-x86_64-linux) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.0.0) msgpack (1.7.5) diff --git a/gemfiles/ruby_3.0_elasticsearch_latest.gemfile.lock b/gemfiles/ruby_3.0_elasticsearch_latest.gemfile.lock index 0590ab252cb..8bf6fb97f7b 100644 --- a/gemfiles/ruby_3.0_elasticsearch_latest.gemfile.lock +++ b/gemfiles/ruby_3.0_elasticsearch_latest.gemfile.lock @@ -61,7 +61,7 @@ GEM google-protobuf (3.25.4-aarch64-linux) google-protobuf (3.25.4-x86_64-linux) hashdiff (1.1.1) - json (2.9.0) + json (2.9.1) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0-aarch64-linux) @@ -70,7 +70,7 @@ GEM ffi (~> 1.0) libddwaf (1.18.0.0.0-x86_64-linux) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.1.0) msgpack (1.7.5) diff --git a/gemfiles/ruby_3.0_opensearch_2.gemfile.lock b/gemfiles/ruby_3.0_opensearch_2.gemfile.lock index a3a78ac3118..ee84248d798 100644 --- a/gemfiles/ruby_3.0_opensearch_2.gemfile.lock +++ b/gemfiles/ruby_3.0_opensearch_2.gemfile.lock @@ -51,7 +51,7 @@ GEM google-protobuf (3.24.4-aarch64-linux) google-protobuf (3.24.4-x86_64-linux) hashdiff (1.0.1) - json (2.9.0) + json (2.9.1) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0-aarch64-linux) @@ -60,7 +60,7 @@ GEM ffi (~> 1.0) libddwaf (1.18.0.0.0-x86_64-linux) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.0.0) msgpack (1.7.5) diff --git a/gemfiles/ruby_3.0_opensearch_3.gemfile.lock b/gemfiles/ruby_3.0_opensearch_3.gemfile.lock index a2b9840594a..b73385f5a00 100644 --- a/gemfiles/ruby_3.0_opensearch_3.gemfile.lock +++ b/gemfiles/ruby_3.0_opensearch_3.gemfile.lock @@ -51,7 +51,7 @@ GEM google-protobuf (3.24.4-aarch64-linux) google-protobuf (3.24.4-x86_64-linux) hashdiff (1.0.1) - json (2.9.0) + json (2.9.1) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0-aarch64-linux) @@ -60,7 +60,7 @@ GEM ffi (~> 1.0) libddwaf (1.18.0.0.0-x86_64-linux) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.0.0) msgpack (1.7.5) diff --git a/gemfiles/ruby_3.0_opensearch_latest.gemfile.lock b/gemfiles/ruby_3.0_opensearch_latest.gemfile.lock index 0e385a9c837..e8582b89645 100644 --- a/gemfiles/ruby_3.0_opensearch_latest.gemfile.lock +++ b/gemfiles/ruby_3.0_opensearch_latest.gemfile.lock @@ -53,7 +53,7 @@ GEM google-protobuf (3.25.4-aarch64-linux) google-protobuf (3.25.4-x86_64-linux) hashdiff (1.1.1) - json (2.9.0) + json (2.9.1) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0-aarch64-linux) @@ -62,7 +62,7 @@ GEM ffi (~> 1.0) libddwaf (1.18.0.0.0-x86_64-linux) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.1.0) msgpack (1.7.5) diff --git a/gemfiles/ruby_3.0_stripe_latest.gemfile.lock b/gemfiles/ruby_3.0_stripe_latest.gemfile.lock index c170bdfdb74..bd9ce9f0f2e 100644 --- a/gemfiles/ruby_3.0_stripe_latest.gemfile.lock +++ b/gemfiles/ruby_3.0_stripe_latest.gemfile.lock @@ -129,7 +129,7 @@ GEM simplecov (~> 0.19) simplecov-html (0.13.1) simplecov_json_formatter (0.1.4) - stripe (13.2.0) + stripe (13.3.0) unicode-display_width (2.6.0) warning (1.4.0) webmock (3.23.1) diff --git a/gemfiles/ruby_3.1_elasticsearch_7.gemfile.lock b/gemfiles/ruby_3.1_elasticsearch_7.gemfile.lock index 178b8e8548e..c30113156d8 100644 --- a/gemfiles/ruby_3.1_elasticsearch_7.gemfile.lock +++ b/gemfiles/ruby_3.1_elasticsearch_7.gemfile.lock @@ -61,7 +61,7 @@ GEM google-protobuf (3.24.4-aarch64-linux) google-protobuf (3.24.4-x86_64-linux) hashdiff (1.0.1) - json (2.9.0) + json (2.9.1) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0-aarch64-linux) @@ -70,7 +70,7 @@ GEM ffi (~> 1.0) libddwaf (1.18.0.0.0-x86_64-linux) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.0.0) msgpack (1.7.5) diff --git a/gemfiles/ruby_3.1_elasticsearch_8.gemfile.lock b/gemfiles/ruby_3.1_elasticsearch_8.gemfile.lock index b3405b341f1..99690f81464 100644 --- a/gemfiles/ruby_3.1_elasticsearch_8.gemfile.lock +++ b/gemfiles/ruby_3.1_elasticsearch_8.gemfile.lock @@ -59,7 +59,7 @@ GEM google-protobuf (3.24.4-aarch64-linux) google-protobuf (3.24.4-x86_64-linux) hashdiff (1.0.1) - json (2.9.0) + json (2.9.1) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0-aarch64-linux) @@ -68,7 +68,7 @@ GEM ffi (~> 1.0) libddwaf (1.18.0.0.0-x86_64-linux) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.0.0) msgpack (1.7.5) diff --git a/gemfiles/ruby_3.1_elasticsearch_latest.gemfile.lock b/gemfiles/ruby_3.1_elasticsearch_latest.gemfile.lock index 0590ab252cb..8bf6fb97f7b 100644 --- a/gemfiles/ruby_3.1_elasticsearch_latest.gemfile.lock +++ b/gemfiles/ruby_3.1_elasticsearch_latest.gemfile.lock @@ -61,7 +61,7 @@ GEM google-protobuf (3.25.4-aarch64-linux) google-protobuf (3.25.4-x86_64-linux) hashdiff (1.1.1) - json (2.9.0) + json (2.9.1) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0-aarch64-linux) @@ -70,7 +70,7 @@ GEM ffi (~> 1.0) libddwaf (1.18.0.0.0-x86_64-linux) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.1.0) msgpack (1.7.5) diff --git a/gemfiles/ruby_3.1_opensearch_2.gemfile.lock b/gemfiles/ruby_3.1_opensearch_2.gemfile.lock index a3a78ac3118..ee84248d798 100644 --- a/gemfiles/ruby_3.1_opensearch_2.gemfile.lock +++ b/gemfiles/ruby_3.1_opensearch_2.gemfile.lock @@ -51,7 +51,7 @@ GEM google-protobuf (3.24.4-aarch64-linux) google-protobuf (3.24.4-x86_64-linux) hashdiff (1.0.1) - json (2.9.0) + json (2.9.1) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0-aarch64-linux) @@ -60,7 +60,7 @@ GEM ffi (~> 1.0) libddwaf (1.18.0.0.0-x86_64-linux) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.0.0) msgpack (1.7.5) diff --git a/gemfiles/ruby_3.1_opensearch_3.gemfile.lock b/gemfiles/ruby_3.1_opensearch_3.gemfile.lock index a2b9840594a..b73385f5a00 100644 --- a/gemfiles/ruby_3.1_opensearch_3.gemfile.lock +++ b/gemfiles/ruby_3.1_opensearch_3.gemfile.lock @@ -51,7 +51,7 @@ GEM google-protobuf (3.24.4-aarch64-linux) google-protobuf (3.24.4-x86_64-linux) hashdiff (1.0.1) - json (2.9.0) + json (2.9.1) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0-aarch64-linux) @@ -60,7 +60,7 @@ GEM ffi (~> 1.0) libddwaf (1.18.0.0.0-x86_64-linux) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.0.0) msgpack (1.7.5) diff --git a/gemfiles/ruby_3.1_opensearch_latest.gemfile.lock b/gemfiles/ruby_3.1_opensearch_latest.gemfile.lock index 0e385a9c837..e8582b89645 100644 --- a/gemfiles/ruby_3.1_opensearch_latest.gemfile.lock +++ b/gemfiles/ruby_3.1_opensearch_latest.gemfile.lock @@ -53,7 +53,7 @@ GEM google-protobuf (3.25.4-aarch64-linux) google-protobuf (3.25.4-x86_64-linux) hashdiff (1.1.1) - json (2.9.0) + json (2.9.1) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0-aarch64-linux) @@ -62,7 +62,7 @@ GEM ffi (~> 1.0) libddwaf (1.18.0.0.0-x86_64-linux) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.1.0) msgpack (1.7.5) diff --git a/gemfiles/ruby_3.1_stripe_latest.gemfile.lock b/gemfiles/ruby_3.1_stripe_latest.gemfile.lock index c170bdfdb74..bd9ce9f0f2e 100644 --- a/gemfiles/ruby_3.1_stripe_latest.gemfile.lock +++ b/gemfiles/ruby_3.1_stripe_latest.gemfile.lock @@ -129,7 +129,7 @@ GEM simplecov (~> 0.19) simplecov-html (0.13.1) simplecov_json_formatter (0.1.4) - stripe (13.2.0) + stripe (13.3.0) unicode-display_width (2.6.0) warning (1.4.0) webmock (3.23.1) diff --git a/gemfiles/ruby_3.2_elasticsearch_7.gemfile.lock b/gemfiles/ruby_3.2_elasticsearch_7.gemfile.lock index 5ca511d6ba4..a001fb09347 100644 --- a/gemfiles/ruby_3.2_elasticsearch_7.gemfile.lock +++ b/gemfiles/ruby_3.2_elasticsearch_7.gemfile.lock @@ -60,7 +60,7 @@ GEM google-protobuf (3.24.4-aarch64-linux) google-protobuf (3.24.4-x86_64-linux) hashdiff (1.0.1) - json (2.9.0) + json (2.9.1) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0-aarch64-linux) @@ -69,7 +69,7 @@ GEM ffi (~> 1.0) libddwaf (1.18.0.0.0-x86_64-linux) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.0.0) msgpack (1.7.5) diff --git a/gemfiles/ruby_3.2_elasticsearch_8.gemfile.lock b/gemfiles/ruby_3.2_elasticsearch_8.gemfile.lock index 7c8f594a851..9c75f510fce 100644 --- a/gemfiles/ruby_3.2_elasticsearch_8.gemfile.lock +++ b/gemfiles/ruby_3.2_elasticsearch_8.gemfile.lock @@ -58,7 +58,7 @@ GEM google-protobuf (3.24.4-aarch64-linux) google-protobuf (3.24.4-x86_64-linux) hashdiff (1.0.1) - json (2.9.0) + json (2.9.1) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0-aarch64-linux) @@ -67,7 +67,7 @@ GEM ffi (~> 1.0) libddwaf (1.18.0.0.0-x86_64-linux) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.0.0) msgpack (1.7.5) diff --git a/gemfiles/ruby_3.2_elasticsearch_latest.gemfile.lock b/gemfiles/ruby_3.2_elasticsearch_latest.gemfile.lock index 5c04d100810..cf64d7f6180 100644 --- a/gemfiles/ruby_3.2_elasticsearch_latest.gemfile.lock +++ b/gemfiles/ruby_3.2_elasticsearch_latest.gemfile.lock @@ -60,7 +60,7 @@ GEM google-protobuf (3.25.4-aarch64-linux) google-protobuf (3.25.4-x86_64-linux) hashdiff (1.1.1) - json (2.9.0) + json (2.9.1) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0-aarch64-linux) @@ -69,7 +69,7 @@ GEM ffi (~> 1.0) libddwaf (1.18.0.0.0-x86_64-linux) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.1.0) msgpack (1.7.5) diff --git a/gemfiles/ruby_3.2_opensearch_2.gemfile.lock b/gemfiles/ruby_3.2_opensearch_2.gemfile.lock index c5d3a53678f..d7d755b15a2 100644 --- a/gemfiles/ruby_3.2_opensearch_2.gemfile.lock +++ b/gemfiles/ruby_3.2_opensearch_2.gemfile.lock @@ -50,7 +50,7 @@ GEM google-protobuf (3.24.4-aarch64-linux) google-protobuf (3.24.4-x86_64-linux) hashdiff (1.0.1) - json (2.9.0) + json (2.9.1) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0-aarch64-linux) @@ -59,7 +59,7 @@ GEM ffi (~> 1.0) libddwaf (1.18.0.0.0-x86_64-linux) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.0.0) msgpack (1.7.5) diff --git a/gemfiles/ruby_3.2_opensearch_3.gemfile.lock b/gemfiles/ruby_3.2_opensearch_3.gemfile.lock index 82328650579..9eb57c54a8c 100644 --- a/gemfiles/ruby_3.2_opensearch_3.gemfile.lock +++ b/gemfiles/ruby_3.2_opensearch_3.gemfile.lock @@ -50,7 +50,7 @@ GEM google-protobuf (3.24.4-aarch64-linux) google-protobuf (3.24.4-x86_64-linux) hashdiff (1.0.1) - json (2.9.0) + json (2.9.1) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0-aarch64-linux) @@ -59,7 +59,7 @@ GEM ffi (~> 1.0) libddwaf (1.18.0.0.0-x86_64-linux) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.0.0) msgpack (1.7.5) diff --git a/gemfiles/ruby_3.2_opensearch_latest.gemfile.lock b/gemfiles/ruby_3.2_opensearch_latest.gemfile.lock index 12ccbee1a8e..d2bb8cf8d5f 100644 --- a/gemfiles/ruby_3.2_opensearch_latest.gemfile.lock +++ b/gemfiles/ruby_3.2_opensearch_latest.gemfile.lock @@ -52,7 +52,7 @@ GEM google-protobuf (3.25.4-aarch64-linux) google-protobuf (3.25.4-x86_64-linux) hashdiff (1.1.1) - json (2.9.0) + json (2.9.1) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0-aarch64-linux) @@ -61,7 +61,7 @@ GEM ffi (~> 1.0) libddwaf (1.18.0.0.0-x86_64-linux) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.1.0) msgpack (1.7.5) diff --git a/gemfiles/ruby_3.2_stripe_latest.gemfile.lock b/gemfiles/ruby_3.2_stripe_latest.gemfile.lock index 6c6ba3d7569..e236ddad855 100644 --- a/gemfiles/ruby_3.2_stripe_latest.gemfile.lock +++ b/gemfiles/ruby_3.2_stripe_latest.gemfile.lock @@ -125,7 +125,7 @@ GEM simplecov (~> 0.19) simplecov-html (0.13.1) simplecov_json_formatter (0.1.4) - stripe (13.2.0) + stripe (13.3.0) unicode-display_width (2.6.0) warning (1.4.0) webmock (3.23.1) diff --git a/gemfiles/ruby_3.3_contrib_old.gemfile b/gemfiles/ruby_3.3_contrib_old.gemfile index 69c05bfa60b..2caa7bfff9a 100644 --- a/gemfiles/ruby_3.3_contrib_old.gemfile +++ b/gemfiles/ruby_3.3_contrib_old.gemfile @@ -33,7 +33,6 @@ gem "webrick", ">= 1.7.0" gem "dalli", "< 3.0.0" gem "presto-client", ">= 0.5.14" gem "qless", "0.12.0" -gem "racc" group :check do diff --git a/gemfiles/ruby_3.3_contrib_old.gemfile.lock b/gemfiles/ruby_3.3_contrib_old.gemfile.lock index 7ca64ec33a0..2b8fcbe894f 100644 --- a/gemfiles/ruby_3.3_contrib_old.gemfile.lock +++ b/gemfiles/ruby_3.3_contrib_old.gemfile.lock @@ -97,7 +97,6 @@ GEM thin (~> 1.6) thor (~> 0.19.1) vegas (~> 0.1.11) - racc (1.7.1) rack (2.2.7) rack-protection (2.0.8.1) rack @@ -205,7 +204,6 @@ DEPENDENCIES pry pry-stack_explorer qless (= 0.12.0) - racc rake (>= 10.5) rake-compiler (~> 1.1, >= 1.1.1) rspec (~> 3.13) diff --git a/gemfiles/ruby_3.3_elasticsearch_7.gemfile.lock b/gemfiles/ruby_3.3_elasticsearch_7.gemfile.lock index f663a007ff7..86429ca171f 100644 --- a/gemfiles/ruby_3.3_elasticsearch_7.gemfile.lock +++ b/gemfiles/ruby_3.3_elasticsearch_7.gemfile.lock @@ -59,7 +59,7 @@ GEM ffi (1.17.0-x86_64-linux-gnu) google-protobuf (3.24.4) hashdiff (1.0.1) - json (2.9.0) + json (2.9.1) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0-aarch64-linux) @@ -68,7 +68,7 @@ GEM ffi (~> 1.0) libddwaf (1.18.0.0.0-x86_64-linux) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.0.0) msgpack (1.7.5) diff --git a/gemfiles/ruby_3.3_elasticsearch_8.gemfile.lock b/gemfiles/ruby_3.3_elasticsearch_8.gemfile.lock index fe257f87701..fdd54302dc4 100644 --- a/gemfiles/ruby_3.3_elasticsearch_8.gemfile.lock +++ b/gemfiles/ruby_3.3_elasticsearch_8.gemfile.lock @@ -57,7 +57,7 @@ GEM ffi (1.17.0-x86_64-linux-gnu) google-protobuf (3.24.4) hashdiff (1.0.1) - json (2.9.0) + json (2.9.1) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0-aarch64-linux) @@ -66,7 +66,7 @@ GEM ffi (~> 1.0) libddwaf (1.18.0.0.0-x86_64-linux) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.0.0) msgpack (1.7.5) diff --git a/gemfiles/ruby_3.3_elasticsearch_latest.gemfile.lock b/gemfiles/ruby_3.3_elasticsearch_latest.gemfile.lock index 5c04d100810..cf64d7f6180 100644 --- a/gemfiles/ruby_3.3_elasticsearch_latest.gemfile.lock +++ b/gemfiles/ruby_3.3_elasticsearch_latest.gemfile.lock @@ -60,7 +60,7 @@ GEM google-protobuf (3.25.4-aarch64-linux) google-protobuf (3.25.4-x86_64-linux) hashdiff (1.1.1) - json (2.9.0) + json (2.9.1) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0-aarch64-linux) @@ -69,7 +69,7 @@ GEM ffi (~> 1.0) libddwaf (1.18.0.0.0-x86_64-linux) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.1.0) msgpack (1.7.5) diff --git a/gemfiles/ruby_3.3_opensearch_2.gemfile.lock b/gemfiles/ruby_3.3_opensearch_2.gemfile.lock index d2a569d2a0f..e8b86074744 100644 --- a/gemfiles/ruby_3.3_opensearch_2.gemfile.lock +++ b/gemfiles/ruby_3.3_opensearch_2.gemfile.lock @@ -49,7 +49,7 @@ GEM ffi (1.17.0-x86_64-linux-gnu) google-protobuf (3.24.4) hashdiff (1.0.1) - json (2.9.0) + json (2.9.1) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0-aarch64-linux) @@ -58,7 +58,7 @@ GEM ffi (~> 1.0) libddwaf (1.18.0.0.0-x86_64-linux) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.0.0) msgpack (1.7.5) diff --git a/gemfiles/ruby_3.3_opensearch_3.gemfile.lock b/gemfiles/ruby_3.3_opensearch_3.gemfile.lock index e8dc68a0736..4ea021ef1d3 100644 --- a/gemfiles/ruby_3.3_opensearch_3.gemfile.lock +++ b/gemfiles/ruby_3.3_opensearch_3.gemfile.lock @@ -49,7 +49,7 @@ GEM ffi (1.17.0-x86_64-linux-gnu) google-protobuf (3.24.4) hashdiff (1.0.1) - json (2.9.0) + json (2.9.1) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0-aarch64-linux) @@ -58,7 +58,7 @@ GEM ffi (~> 1.0) libddwaf (1.18.0.0.0-x86_64-linux) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.0.0) msgpack (1.7.5) diff --git a/gemfiles/ruby_3.3_opensearch_latest.gemfile.lock b/gemfiles/ruby_3.3_opensearch_latest.gemfile.lock index 12ccbee1a8e..d2bb8cf8d5f 100644 --- a/gemfiles/ruby_3.3_opensearch_latest.gemfile.lock +++ b/gemfiles/ruby_3.3_opensearch_latest.gemfile.lock @@ -52,7 +52,7 @@ GEM google-protobuf (3.25.4-aarch64-linux) google-protobuf (3.25.4-x86_64-linux) hashdiff (1.1.1) - json (2.9.0) + json (2.9.1) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0-aarch64-linux) @@ -61,7 +61,7 @@ GEM ffi (~> 1.0) libddwaf (1.18.0.0.0-x86_64-linux) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.1.0) msgpack (1.7.5) diff --git a/gemfiles/ruby_3.3_stripe_latest.gemfile.lock b/gemfiles/ruby_3.3_stripe_latest.gemfile.lock index 6c6ba3d7569..e236ddad855 100644 --- a/gemfiles/ruby_3.3_stripe_latest.gemfile.lock +++ b/gemfiles/ruby_3.3_stripe_latest.gemfile.lock @@ -125,7 +125,7 @@ GEM simplecov (~> 0.19) simplecov-html (0.13.1) simplecov_json_formatter (0.1.4) - stripe (13.2.0) + stripe (13.3.0) unicode-display_width (2.6.0) warning (1.4.0) webmock (3.23.1) diff --git a/gemfiles/ruby_3.4_activesupport.gemfile b/gemfiles/ruby_3.4_activesupport.gemfile index 9c6d7cf607d..b9efe74db8f 100644 --- a/gemfiles/ruby_3.4_activesupport.gemfile +++ b/gemfiles/ruby_3.4_activesupport.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_activesupport.gemfile.lock b/gemfiles/ruby_3.4_activesupport.gemfile.lock index c93111f5ec2..c4a46291810 100644 --- a/gemfiles/ruby_3.4_activesupport.gemfile.lock +++ b/gemfiles/ruby_3.4_activesupport.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -263,6 +256,7 @@ GEM simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) stringio (3.1.1) + strscan (3.1.1) thor (1.3.1) tzinfo (2.0.6) concurrent-ruby (~> 1.0) @@ -317,7 +311,6 @@ DEPENDENCIES ruby-kafka (>= 0.7.10) simplecov! simplecov-cobertura (~> 2.1.0) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_aws.gemfile b/gemfiles/ruby_3.4_aws.gemfile index 1d0ffa5ece1..85239ef89ed 100644 --- a/gemfiles/ruby_3.4_aws.gemfile +++ b/gemfiles/ruby_3.4_aws.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_aws.gemfile.lock b/gemfiles/ruby_3.4_aws.gemfile.lock index c651a539845..1a68c8be039 100644 --- a/gemfiles/ruby_3.4_aws.gemfile.lock +++ b/gemfiles/ruby_3.4_aws.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -1686,6 +1679,7 @@ GEM simplecov (~> 0.19) simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) + strscan (3.1.1) thor (1.3.1) unicode-display_width (2.5.0) warning (1.4.0) @@ -1731,7 +1725,6 @@ DEPENDENCIES shoryuken simplecov! simplecov-cobertura (~> 2.1.0) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_contrib.gemfile b/gemfiles/ruby_3.4_contrib.gemfile index 6b918e37619..4d6897b4608 100644 --- a/gemfiles/ruby_3.4_contrib.gemfile +++ b/gemfiles/ruby_3.4_contrib.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_contrib.gemfile.lock b/gemfiles/ruby_3.4_contrib.gemfile.lock index 94793d838e6..df998e8e4bf 100644 --- a/gemfiles/ruby_3.4_contrib.gemfile.lock +++ b/gemfiles/ruby_3.4_contrib.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -203,6 +196,7 @@ GEM sorted_set (1.0.3) rbtree set (~> 1.0) + strscan (3.1.1) sucker_punch (3.2.0) concurrent-ruby (~> 1.0) thor (1.3.1) @@ -260,7 +254,6 @@ DEPENDENCIES simplecov! simplecov-cobertura (~> 2.1.0) sneakers (>= 2.12.0) - strscan! sucker_punch warning (~> 1) webmock (>= 3.10.0) diff --git a/gemfiles/ruby_3.4_contrib_old.gemfile b/gemfiles/ruby_3.4_contrib_old.gemfile index 21050379892..a49d7a0f057 100644 --- a/gemfiles/ruby_3.4_contrib_old.gemfile +++ b/gemfiles/ruby_3.4_contrib_old.gemfile @@ -30,14 +30,12 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" gem "dalli", "< 3.0.0" gem "presto-client", ">= 0.5.14" gem "qless", "0.12.0" -gem "racc" group :check do diff --git a/gemfiles/ruby_3.4_contrib_old.gemfile.lock b/gemfiles/ruby_3.4_contrib_old.gemfile.lock index 79aaafe972f..a47f824e3d3 100644 --- a/gemfiles/ruby_3.4_contrib_old.gemfile.lock +++ b/gemfiles/ruby_3.4_contrib_old.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -179,6 +172,7 @@ GEM rack-protection (= 2.0.8.1) tilt (~> 2.0) statsd-ruby (1.5.0) + strscan (3.1.1) thin (1.8.2) daemons (~> 1.0, >= 1.0.9) eventmachine (~> 1.0, >= 1.0.4) @@ -220,7 +214,6 @@ DEPENDENCIES pry pry-stack_explorer qless (= 0.12.0) - racc rake (>= 10.5) rake-compiler (~> 1.1, >= 1.1.1) rspec (~> 3.13) @@ -233,7 +226,6 @@ DEPENDENCIES rubocop-rspec (~> 2.20, < 2.21) simplecov! simplecov-cobertura (~> 2.1.0) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_core_old.gemfile b/gemfiles/ruby_3.4_core_old.gemfile index 547f67430e4..7212c4c6b31 100644 --- a/gemfiles/ruby_3.4_core_old.gemfile +++ b/gemfiles/ruby_3.4_core_old.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_core_old.gemfile.lock b/gemfiles/ruby_3.4_core_old.gemfile.lock index 9b0963022f9..84b9fb016eb 100644 --- a/gemfiles/ruby_3.4_core_old.gemfile.lock +++ b/gemfiles/ruby_3.4_core_old.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -133,6 +126,7 @@ GEM simplecov (~> 0.19) simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) + strscan (3.1.1) unicode-display_width (2.5.0) warning (1.4.0) webmock (3.23.1) @@ -175,7 +169,6 @@ DEPENDENCIES rubocop-rspec (~> 2.20, < 2.21) simplecov! simplecov-cobertura (~> 2.1.0) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_elasticsearch_7.gemfile b/gemfiles/ruby_3.4_elasticsearch_7.gemfile index ca0a57a3b86..0daf60388b5 100644 --- a/gemfiles/ruby_3.4_elasticsearch_7.gemfile +++ b/gemfiles/ruby_3.4_elasticsearch_7.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_elasticsearch_7.gemfile.lock b/gemfiles/ruby_3.4_elasticsearch_7.gemfile.lock index ec7a180f57a..518ba2bd4ea 100644 --- a/gemfiles/ruby_3.4_elasticsearch_7.gemfile.lock +++ b/gemfiles/ruby_3.4_elasticsearch_7.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -67,7 +60,7 @@ GEM ffi (1.17.0) google-protobuf (3.25.3) hashdiff (1.1.0) - json (2.9.0) + json (2.9.1) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0-aarch64-linux) @@ -76,7 +69,7 @@ GEM ffi (~> 1.0) libddwaf (1.18.0.0.0-x86_64-linux) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.1.0) msgpack (1.7.5) @@ -152,6 +145,7 @@ GEM simplecov (~> 0.19) simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) + strscan (3.1.1) unicode-display_width (2.5.0) uri (1.0.2) warning (1.4.0) @@ -196,7 +190,6 @@ DEPENDENCIES rubocop-rspec (~> 2.20, < 2.21) simplecov! simplecov-cobertura (~> 2.1.0) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_elasticsearch_8.gemfile b/gemfiles/ruby_3.4_elasticsearch_8.gemfile index e206077209e..c72e5234d71 100644 --- a/gemfiles/ruby_3.4_elasticsearch_8.gemfile +++ b/gemfiles/ruby_3.4_elasticsearch_8.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_elasticsearch_8.gemfile.lock b/gemfiles/ruby_3.4_elasticsearch_8.gemfile.lock index c2ab47d2bf0..dd39d2036fb 100644 --- a/gemfiles/ruby_3.4_elasticsearch_8.gemfile.lock +++ b/gemfiles/ruby_3.4_elasticsearch_8.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -66,7 +59,7 @@ GEM ffi (1.17.0) google-protobuf (3.25.3) hashdiff (1.1.0) - json (2.9.0) + json (2.9.1) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0-aarch64-linux) @@ -75,7 +68,7 @@ GEM ffi (~> 1.0) libddwaf (1.18.0.0.0-x86_64-linux) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.1.0) msgpack (1.7.5) @@ -151,6 +144,7 @@ GEM simplecov (~> 0.19) simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) + strscan (3.1.1) unicode-display_width (2.5.0) uri (1.0.2) warning (1.4.0) @@ -195,7 +189,6 @@ DEPENDENCIES rubocop-rspec (~> 2.20, < 2.21) simplecov! simplecov-cobertura (~> 2.1.0) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_elasticsearch_latest.gemfile b/gemfiles/ruby_3.4_elasticsearch_latest.gemfile index 617eece269d..9ef8143ea77 100644 --- a/gemfiles/ruby_3.4_elasticsearch_latest.gemfile +++ b/gemfiles/ruby_3.4_elasticsearch_latest.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_elasticsearch_latest.gemfile.lock b/gemfiles/ruby_3.4_elasticsearch_latest.gemfile.lock index 13b09675a46..a8efec5d19c 100644 --- a/gemfiles/ruby_3.4_elasticsearch_latest.gemfile.lock +++ b/gemfiles/ruby_3.4_elasticsearch_latest.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -66,7 +59,7 @@ GEM ffi (1.17.0) google-protobuf (3.25.4) hashdiff (1.1.1) - json (2.9.0) + json (2.9.1) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0-aarch64-linux) @@ -75,7 +68,7 @@ GEM ffi (~> 1.0) libddwaf (1.18.0.0.0-x86_64-linux) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.1.0) msgpack (1.7.5) @@ -194,7 +187,6 @@ DEPENDENCIES rubocop-rspec (~> 2.20, < 2.21) simplecov! simplecov-cobertura (~> 2.1.0) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_graphql_1.13.gemfile b/gemfiles/ruby_3.4_graphql_1.13.gemfile index bed7165479a..bfd55a09fa2 100644 --- a/gemfiles/ruby_3.4_graphql_1.13.gemfile +++ b/gemfiles/ruby_3.4_graphql_1.13.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_graphql_1.13.gemfile.lock b/gemfiles/ruby_3.4_graphql_1.13.gemfile.lock index 59529d9c968..41bc5e725dc 100644 --- a/gemfiles/ruby_3.4_graphql_1.13.gemfile.lock +++ b/gemfiles/ruby_3.4_graphql_1.13.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -272,6 +265,7 @@ GEM actionpack (>= 6.1) activesupport (>= 6.1) sprockets (>= 3.0.0) + strscan (3.1.1) thor (1.3.1) timeout (0.4.1) tzinfo (2.0.6) @@ -326,7 +320,6 @@ DEPENDENCIES simplecov! simplecov-cobertura (~> 2.1.0) sprockets (< 4) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_graphql_2.0.gemfile b/gemfiles/ruby_3.4_graphql_2.0.gemfile index 86a7af994d9..fc6b049dd44 100644 --- a/gemfiles/ruby_3.4_graphql_2.0.gemfile +++ b/gemfiles/ruby_3.4_graphql_2.0.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_graphql_2.0.gemfile.lock b/gemfiles/ruby_3.4_graphql_2.0.gemfile.lock index 6292fc3244c..ab0390ad394 100644 --- a/gemfiles/ruby_3.4_graphql_2.0.gemfile.lock +++ b/gemfiles/ruby_3.4_graphql_2.0.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -272,6 +265,7 @@ GEM actionpack (>= 6.1) activesupport (>= 6.1) sprockets (>= 3.0.0) + strscan (3.1.1) thor (1.3.1) timeout (0.4.1) tzinfo (2.0.6) @@ -326,7 +320,6 @@ DEPENDENCIES simplecov! simplecov-cobertura (~> 2.1.0) sprockets (< 4) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_graphql_2.1.gemfile b/gemfiles/ruby_3.4_graphql_2.1.gemfile index 7910e1feec2..f5fe40a7add 100644 --- a/gemfiles/ruby_3.4_graphql_2.1.gemfile +++ b/gemfiles/ruby_3.4_graphql_2.1.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_graphql_2.1.gemfile.lock b/gemfiles/ruby_3.4_graphql_2.1.gemfile.lock index 5b7705eefdd..954ed12a904 100644 --- a/gemfiles/ruby_3.4_graphql_2.1.gemfile.lock +++ b/gemfiles/ruby_3.4_graphql_2.1.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -272,6 +265,7 @@ GEM actionpack (>= 6.1) activesupport (>= 6.1) sprockets (>= 3.0.0) + strscan (3.1.1) thor (1.3.1) timeout (0.4.1) tzinfo (2.0.6) @@ -326,7 +320,6 @@ DEPENDENCIES simplecov! simplecov-cobertura (~> 2.1.0) sprockets (< 4) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_graphql_2.2.gemfile b/gemfiles/ruby_3.4_graphql_2.2.gemfile index 10c6d255c33..2c7558e0998 100644 --- a/gemfiles/ruby_3.4_graphql_2.2.gemfile +++ b/gemfiles/ruby_3.4_graphql_2.2.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_graphql_2.2.gemfile.lock b/gemfiles/ruby_3.4_graphql_2.2.gemfile.lock index fba40f152eb..abbb5921da2 100644 --- a/gemfiles/ruby_3.4_graphql_2.2.gemfile.lock +++ b/gemfiles/ruby_3.4_graphql_2.2.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -272,6 +265,7 @@ GEM actionpack (>= 6.1) activesupport (>= 6.1) sprockets (>= 3.0.0) + strscan (3.1.1) thor (1.3.1) timeout (0.4.1) tzinfo (2.0.6) @@ -326,7 +320,6 @@ DEPENDENCIES simplecov! simplecov-cobertura (~> 2.1.0) sprockets (< 4) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_graphql_2.3.gemfile b/gemfiles/ruby_3.4_graphql_2.3.gemfile index f775428fe71..85c824645e9 100644 --- a/gemfiles/ruby_3.4_graphql_2.3.gemfile +++ b/gemfiles/ruby_3.4_graphql_2.3.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_graphql_2.3.gemfile.lock b/gemfiles/ruby_3.4_graphql_2.3.gemfile.lock index ab9dd543d85..9fd62652b3d 100644 --- a/gemfiles/ruby_3.4_graphql_2.3.gemfile.lock +++ b/gemfiles/ruby_3.4_graphql_2.3.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -272,6 +265,7 @@ GEM actionpack (>= 6.1) activesupport (>= 6.1) sprockets (>= 3.0.0) + strscan (3.1.1) thor (1.3.1) timeout (0.4.1) tzinfo (2.0.6) @@ -326,7 +320,6 @@ DEPENDENCIES simplecov! simplecov-cobertura (~> 2.1.0) sprockets (< 4) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_http.gemfile b/gemfiles/ruby_3.4_http.gemfile index 9013f09cfca..823cd07ba5a 100644 --- a/gemfiles/ruby_3.4_http.gemfile +++ b/gemfiles/ruby_3.4_http.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_http.gemfile.lock b/gemfiles/ruby_3.4_http.gemfile.lock index fb8a0aef4cc..e3ccb3ab6a6 100644 --- a/gemfiles/ruby_3.4_http.gemfile.lock +++ b/gemfiles/ruby_3.4_http.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -169,6 +162,7 @@ GEM simplecov (~> 0.19) simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) + strscan (3.1.1) typhoeus (1.4.1) ethon (>= 0.9.0) unicode-display_width (2.5.0) @@ -220,7 +214,6 @@ DEPENDENCIES rubocop-rspec (~> 2.20, < 2.21) simplecov! simplecov-cobertura (~> 2.1.0) - strscan! typhoeus warning (~> 1) webmock (>= 3.10.0) diff --git a/gemfiles/ruby_3.4_opensearch_2.gemfile b/gemfiles/ruby_3.4_opensearch_2.gemfile index 8487af6f277..b9f5dd06ab1 100644 --- a/gemfiles/ruby_3.4_opensearch_2.gemfile +++ b/gemfiles/ruby_3.4_opensearch_2.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_opensearch_2.gemfile.lock b/gemfiles/ruby_3.4_opensearch_2.gemfile.lock index 645a89f9dd0..fbe94e88416 100644 --- a/gemfiles/ruby_3.4_opensearch_2.gemfile.lock +++ b/gemfiles/ruby_3.4_opensearch_2.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -58,7 +51,7 @@ GEM ffi (1.17.0) google-protobuf (3.25.3) hashdiff (1.1.0) - json (2.9.0) + json (2.9.1) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0-aarch64-linux) @@ -67,7 +60,7 @@ GEM ffi (~> 1.0) libddwaf (1.18.0.0.0-x86_64-linux) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.1.0) msgpack (1.7.5) @@ -151,6 +144,7 @@ GEM simplecov (~> 0.19) simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) + strscan (3.1.1) unicode-display_width (2.5.0) uri (1.0.2) warning (1.4.0) @@ -195,7 +189,6 @@ DEPENDENCIES rubocop-rspec (~> 2.20, < 2.21) simplecov! simplecov-cobertura (~> 2.1.0) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_opensearch_3.gemfile b/gemfiles/ruby_3.4_opensearch_3.gemfile index 1a928a4a7c8..c6b73fbb534 100644 --- a/gemfiles/ruby_3.4_opensearch_3.gemfile +++ b/gemfiles/ruby_3.4_opensearch_3.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_opensearch_3.gemfile.lock b/gemfiles/ruby_3.4_opensearch_3.gemfile.lock index a4980f955bd..bd49940dd79 100644 --- a/gemfiles/ruby_3.4_opensearch_3.gemfile.lock +++ b/gemfiles/ruby_3.4_opensearch_3.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -58,7 +51,7 @@ GEM ffi (1.17.0) google-protobuf (3.25.3) hashdiff (1.1.0) - json (2.9.0) + json (2.9.1) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0-aarch64-linux) @@ -67,7 +60,7 @@ GEM ffi (~> 1.0) libddwaf (1.18.0.0.0-x86_64-linux) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.1.0) msgpack (1.7.5) @@ -146,6 +139,7 @@ GEM simplecov (~> 0.19) simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) + strscan (3.1.1) unicode-display_width (2.5.0) uri (1.0.2) warning (1.4.0) @@ -190,7 +184,6 @@ DEPENDENCIES rubocop-rspec (~> 2.20, < 2.21) simplecov! simplecov-cobertura (~> 2.1.0) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_opensearch_latest.gemfile b/gemfiles/ruby_3.4_opensearch_latest.gemfile index 4bdc9cd1ec5..d7ee68961b8 100644 --- a/gemfiles/ruby_3.4_opensearch_latest.gemfile +++ b/gemfiles/ruby_3.4_opensearch_latest.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_opensearch_latest.gemfile.lock b/gemfiles/ruby_3.4_opensearch_latest.gemfile.lock index a4ab79a92af..b5252634c3f 100644 --- a/gemfiles/ruby_3.4_opensearch_latest.gemfile.lock +++ b/gemfiles/ruby_3.4_opensearch_latest.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -58,7 +51,7 @@ GEM ffi (1.17.0) google-protobuf (3.25.4) hashdiff (1.1.1) - json (2.9.0) + json (2.9.1) json-schema (2.8.1) addressable (>= 2.4) libdatadog (14.3.1.1.0-aarch64-linux) @@ -67,7 +60,7 @@ GEM ffi (~> 1.0) libddwaf (1.18.0.0.0-x86_64-linux) ffi (~> 1.0) - logger (1.6.3) + logger (1.6.4) memory_profiler (0.9.14) method_source (1.1.0) msgpack (1.7.5) @@ -189,7 +182,6 @@ DEPENDENCIES rubocop-rspec (~> 2.20, < 2.21) simplecov! simplecov-cobertura (~> 2.1.0) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_opentelemetry.gemfile b/gemfiles/ruby_3.4_opentelemetry.gemfile index 13f8c87ba04..2b1ee29481c 100644 --- a/gemfiles/ruby_3.4_opentelemetry.gemfile +++ b/gemfiles/ruby_3.4_opentelemetry.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_opentelemetry.gemfile.lock b/gemfiles/ruby_3.4_opentelemetry.gemfile.lock index b3ab9d1ec70..c8aef7ddd35 100644 --- a/gemfiles/ruby_3.4_opentelemetry.gemfile.lock +++ b/gemfiles/ruby_3.4_opentelemetry.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -145,6 +138,7 @@ GEM simplecov (~> 0.19) simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) + strscan (3.1.1) unicode-display_width (2.5.0) warning (1.4.0) webmock (3.23.1) @@ -188,7 +182,6 @@ DEPENDENCIES rubocop-rspec (~> 2.20, < 2.21) simplecov! simplecov-cobertura (~> 2.1.0) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_opentelemetry_otlp.gemfile b/gemfiles/ruby_3.4_opentelemetry_otlp.gemfile index dcef28884e0..cd64e4e680b 100644 --- a/gemfiles/ruby_3.4_opentelemetry_otlp.gemfile +++ b/gemfiles/ruby_3.4_opentelemetry_otlp.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_opentelemetry_otlp.gemfile.lock b/gemfiles/ruby_3.4_opentelemetry_otlp.gemfile.lock index ffabe185890..78db044daa4 100644 --- a/gemfiles/ruby_3.4_opentelemetry_otlp.gemfile.lock +++ b/gemfiles/ruby_3.4_opentelemetry_otlp.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -197,7 +190,6 @@ DEPENDENCIES rubocop-rspec (~> 2.20, < 2.21) simplecov! simplecov-cobertura (~> 2.1.0) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_rack_2.gemfile b/gemfiles/ruby_3.4_rack_2.gemfile index 1471d0b6b31..f9b1fda874c 100644 --- a/gemfiles/ruby_3.4_rack_2.gemfile +++ b/gemfiles/ruby_3.4_rack_2.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_rack_2.gemfile.lock b/gemfiles/ruby_3.4_rack_2.gemfile.lock index 7418d027cce..bcfa63671f1 100644 --- a/gemfiles/ruby_3.4_rack_2.gemfile.lock +++ b/gemfiles/ruby_3.4_rack_2.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -138,6 +131,7 @@ GEM simplecov (~> 0.19) simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) + strscan (3.1.1) unicode-display_width (2.5.0) warning (1.4.0) webmock (3.23.1) @@ -183,7 +177,6 @@ DEPENDENCIES rubocop-rspec (~> 2.20, < 2.21) simplecov! simplecov-cobertura (~> 2.1.0) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_rack_3.gemfile b/gemfiles/ruby_3.4_rack_3.gemfile index 7c8b1e43db9..6483683c9cb 100644 --- a/gemfiles/ruby_3.4_rack_3.gemfile +++ b/gemfiles/ruby_3.4_rack_3.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_rack_3.gemfile.lock b/gemfiles/ruby_3.4_rack_3.gemfile.lock index 56041730327..9af02fb4158 100644 --- a/gemfiles/ruby_3.4_rack_3.gemfile.lock +++ b/gemfiles/ruby_3.4_rack_3.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -138,6 +131,7 @@ GEM simplecov (~> 0.19) simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) + strscan (3.1.1) unicode-display_width (2.5.0) warning (1.4.0) webmock (3.23.1) @@ -183,7 +177,6 @@ DEPENDENCIES rubocop-rspec (~> 2.20, < 2.21) simplecov! simplecov-cobertura (~> 2.1.0) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_rack_latest.gemfile b/gemfiles/ruby_3.4_rack_latest.gemfile index 9f705bee167..675b9e26fd3 100644 --- a/gemfiles/ruby_3.4_rack_latest.gemfile +++ b/gemfiles/ruby_3.4_rack_latest.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_rack_latest.gemfile.lock b/gemfiles/ruby_3.4_rack_latest.gemfile.lock index 4ff59f8edd1..ddbe1a2a65e 100644 --- a/gemfiles/ruby_3.4_rack_latest.gemfile.lock +++ b/gemfiles/ruby_3.4_rack_latest.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -182,7 +175,6 @@ DEPENDENCIES rubocop-rspec (~> 2.20, < 2.21) simplecov! simplecov-cobertura (~> 2.1.0) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_rails61_mysql2.gemfile b/gemfiles/ruby_3.4_rails61_mysql2.gemfile index 88849759a64..b0259c8f84d 100644 --- a/gemfiles/ruby_3.4_rails61_mysql2.gemfile +++ b/gemfiles/ruby_3.4_rails61_mysql2.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_rails61_mysql2.gemfile.lock b/gemfiles/ruby_3.4_rails61_mysql2.gemfile.lock index a2c1144b087..7f4dcac9b39 100644 --- a/gemfiles/ruby_3.4_rails61_mysql2.gemfile.lock +++ b/gemfiles/ruby_3.4_rails61_mysql2.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -271,6 +264,7 @@ GEM actionpack (>= 6.1) activesupport (>= 6.1) sprockets (>= 3.0.0) + strscan (3.1.1) thor (1.3.1) timeout (0.4.1) tzinfo (2.0.6) @@ -326,7 +320,6 @@ DEPENDENCIES simplecov! simplecov-cobertura (~> 2.1.0) sprockets (< 4) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_rails61_postgres.gemfile b/gemfiles/ruby_3.4_rails61_postgres.gemfile index 017c1a501db..b7792f10cbc 100644 --- a/gemfiles/ruby_3.4_rails61_postgres.gemfile +++ b/gemfiles/ruby_3.4_rails61_postgres.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_rails61_postgres.gemfile.lock b/gemfiles/ruby_3.4_rails61_postgres.gemfile.lock index 9e54602c501..d6472b2a812 100644 --- a/gemfiles/ruby_3.4_rails61_postgres.gemfile.lock +++ b/gemfiles/ruby_3.4_rails61_postgres.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -271,6 +264,7 @@ GEM actionpack (>= 6.1) activesupport (>= 6.1) sprockets (>= 3.0.0) + strscan (3.1.1) thor (1.3.1) timeout (0.4.1) tzinfo (2.0.6) @@ -326,7 +320,6 @@ DEPENDENCIES simplecov! simplecov-cobertura (~> 2.1.0) sprockets (< 4) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_rails61_postgres_redis.gemfile b/gemfiles/ruby_3.4_rails61_postgres_redis.gemfile index 5227ff1a053..952e9a6f865 100644 --- a/gemfiles/ruby_3.4_rails61_postgres_redis.gemfile +++ b/gemfiles/ruby_3.4_rails61_postgres_redis.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_rails61_postgres_redis.gemfile.lock b/gemfiles/ruby_3.4_rails61_postgres_redis.gemfile.lock index fa5d9163b5a..853fe2afe0b 100644 --- a/gemfiles/ruby_3.4_rails61_postgres_redis.gemfile.lock +++ b/gemfiles/ruby_3.4_rails61_postgres_redis.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -272,6 +265,7 @@ GEM actionpack (>= 6.1) activesupport (>= 6.1) sprockets (>= 3.0.0) + strscan (3.1.1) thor (1.3.1) timeout (0.4.1) tzinfo (2.0.6) @@ -328,7 +322,6 @@ DEPENDENCIES simplecov! simplecov-cobertura (~> 2.1.0) sprockets (< 4) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_rails61_postgres_sidekiq.gemfile b/gemfiles/ruby_3.4_rails61_postgres_sidekiq.gemfile index e36430d98c7..69cf36345bc 100644 --- a/gemfiles/ruby_3.4_rails61_postgres_sidekiq.gemfile +++ b/gemfiles/ruby_3.4_rails61_postgres_sidekiq.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_rails61_postgres_sidekiq.gemfile.lock b/gemfiles/ruby_3.4_rails61_postgres_sidekiq.gemfile.lock index 083f02824e6..a3795dddbcb 100644 --- a/gemfiles/ruby_3.4_rails61_postgres_sidekiq.gemfile.lock +++ b/gemfiles/ruby_3.4_rails61_postgres_sidekiq.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -285,6 +278,7 @@ GEM actionpack (>= 6.1) activesupport (>= 6.1) sprockets (>= 3.0.0) + strscan (3.1.1) thor (1.3.1) timeout (0.4.1) tzinfo (2.0.6) @@ -342,7 +336,6 @@ DEPENDENCIES simplecov! simplecov-cobertura (~> 2.1.0) sprockets (< 4) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_rails61_semantic_logger.gemfile b/gemfiles/ruby_3.4_rails61_semantic_logger.gemfile index eb3d09a2613..6842d8876ea 100644 --- a/gemfiles/ruby_3.4_rails61_semantic_logger.gemfile +++ b/gemfiles/ruby_3.4_rails61_semantic_logger.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_rails61_semantic_logger.gemfile.lock b/gemfiles/ruby_3.4_rails61_semantic_logger.gemfile.lock index 739d739d381..29776284dd4 100644 --- a/gemfiles/ruby_3.4_rails61_semantic_logger.gemfile.lock +++ b/gemfiles/ruby_3.4_rails61_semantic_logger.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -270,6 +263,7 @@ GEM actionpack (>= 6.1) activesupport (>= 6.1) sprockets (>= 3.0.0) + strscan (3.1.1) thor (1.3.1) timeout (0.4.1) tzinfo (2.0.6) @@ -325,7 +319,6 @@ DEPENDENCIES simplecov! simplecov-cobertura (~> 2.1.0) sprockets (< 4) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_rails61_trilogy.gemfile b/gemfiles/ruby_3.4_rails61_trilogy.gemfile index ebb99bceb42..f5aa9ddf483 100644 --- a/gemfiles/ruby_3.4_rails61_trilogy.gemfile +++ b/gemfiles/ruby_3.4_rails61_trilogy.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_rails61_trilogy.gemfile.lock b/gemfiles/ruby_3.4_rails61_trilogy.gemfile.lock index 0f3d03e4eb8..3417f522d57 100644 --- a/gemfiles/ruby_3.4_rails61_trilogy.gemfile.lock +++ b/gemfiles/ruby_3.4_rails61_trilogy.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -273,6 +266,7 @@ GEM actionpack (>= 6.1) activesupport (>= 6.1) sprockets (>= 3.0.0) + strscan (3.1.1) thor (1.3.1) timeout (0.4.1) trilogy (2.8.1) @@ -329,7 +323,6 @@ DEPENDENCIES simplecov! simplecov-cobertura (~> 2.1.0) sprockets (< 4) - strscan! trilogy warning (~> 1) webmock (>= 3.10.0) diff --git a/gemfiles/ruby_3.4_rails7.gemfile b/gemfiles/ruby_3.4_rails7.gemfile index ce59672af11..182edfe9da3 100644 --- a/gemfiles/ruby_3.4_rails7.gemfile +++ b/gemfiles/ruby_3.4_rails7.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_rails7.gemfile.lock b/gemfiles/ruby_3.4_rails7.gemfile.lock index cadeb0f339a..23e47c46e81 100644 --- a/gemfiles/ruby_3.4_rails7.gemfile.lock +++ b/gemfiles/ruby_3.4_rails7.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -264,6 +257,7 @@ GEM simplecov (~> 0.19) simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) + strscan (3.1.1) thor (1.3.1) timeout (0.4.1) tzinfo (2.0.6) @@ -316,7 +310,6 @@ DEPENDENCIES rubocop-rspec (~> 2.20, < 2.21) simplecov! simplecov-cobertura (~> 2.1.0) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_rails71.gemfile b/gemfiles/ruby_3.4_rails71.gemfile index d62f469a994..a3c36b665b3 100644 --- a/gemfiles/ruby_3.4_rails71.gemfile +++ b/gemfiles/ruby_3.4_rails71.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_rails71.gemfile.lock b/gemfiles/ruby_3.4_rails71.gemfile.lock index 1176a752d43..3bf31d83ce7 100644 --- a/gemfiles/ruby_3.4_rails71.gemfile.lock +++ b/gemfiles/ruby_3.4_rails71.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -292,6 +285,7 @@ GEM simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) stringio (3.1.1) + strscan (3.1.1) thor (1.3.1) timeout (0.4.1) tzinfo (2.0.6) @@ -344,7 +338,6 @@ DEPENDENCIES rubocop-rspec (~> 2.20, < 2.21) simplecov! simplecov-cobertura (~> 2.1.0) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_rails_old_redis.gemfile b/gemfiles/ruby_3.4_rails_old_redis.gemfile index 3b67a2fe8da..27a681c7644 100644 --- a/gemfiles/ruby_3.4_rails_old_redis.gemfile +++ b/gemfiles/ruby_3.4_rails_old_redis.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_redis_3.gemfile b/gemfiles/ruby_3.4_redis_3.gemfile index 58da84c1f65..c12e260ce06 100644 --- a/gemfiles/ruby_3.4_redis_3.gemfile +++ b/gemfiles/ruby_3.4_redis_3.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_redis_3.gemfile.lock b/gemfiles/ruby_3.4_redis_3.gemfile.lock index a3996881bdc..379c806e722 100644 --- a/gemfiles/ruby_3.4_redis_3.gemfile.lock +++ b/gemfiles/ruby_3.4_redis_3.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -134,6 +127,7 @@ GEM simplecov (~> 0.19) simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) + strscan (3.1.1) unicode-display_width (2.5.0) warning (1.4.0) webmock (3.23.1) @@ -177,7 +171,6 @@ DEPENDENCIES rubocop-rspec (~> 2.20, < 2.21) simplecov! simplecov-cobertura (~> 2.1.0) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_redis_4.gemfile b/gemfiles/ruby_3.4_redis_4.gemfile index 9abbb22f0f9..4720c68ece2 100644 --- a/gemfiles/ruby_3.4_redis_4.gemfile +++ b/gemfiles/ruby_3.4_redis_4.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_redis_4.gemfile.lock b/gemfiles/ruby_3.4_redis_4.gemfile.lock index e64ed262a78..8786579f576 100644 --- a/gemfiles/ruby_3.4_redis_4.gemfile.lock +++ b/gemfiles/ruby_3.4_redis_4.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -134,6 +127,7 @@ GEM simplecov (~> 0.19) simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) + strscan (3.1.1) unicode-display_width (2.5.0) warning (1.4.0) webmock (3.23.1) @@ -177,7 +171,6 @@ DEPENDENCIES rubocop-rspec (~> 2.20, < 2.21) simplecov! simplecov-cobertura (~> 2.1.0) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_redis_5.gemfile b/gemfiles/ruby_3.4_redis_5.gemfile index d7d32251619..a68bb653459 100644 --- a/gemfiles/ruby_3.4_redis_5.gemfile +++ b/gemfiles/ruby_3.4_redis_5.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_redis_5.gemfile.lock b/gemfiles/ruby_3.4_redis_5.gemfile.lock index e372400cdf2..1d0286608d0 100644 --- a/gemfiles/ruby_3.4_redis_5.gemfile.lock +++ b/gemfiles/ruby_3.4_redis_5.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -138,6 +131,7 @@ GEM simplecov (~> 0.19) simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) + strscan (3.1.1) unicode-display_width (2.5.0) warning (1.4.0) webmock (3.23.1) @@ -181,7 +175,6 @@ DEPENDENCIES rubocop-rspec (~> 2.20, < 2.21) simplecov! simplecov-cobertura (~> 2.1.0) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_relational_db.gemfile b/gemfiles/ruby_3.4_relational_db.gemfile index 1edd7a29e13..15035f00277 100644 --- a/gemfiles/ruby_3.4_relational_db.gemfile +++ b/gemfiles/ruby_3.4_relational_db.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_relational_db.gemfile.lock b/gemfiles/ruby_3.4_relational_db.gemfile.lock index 3afe5e5e690..0f9c10999b0 100644 --- a/gemfiles/ruby_3.4_relational_db.gemfile.lock +++ b/gemfiles/ruby_3.4_relational_db.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -212,7 +205,6 @@ DEPENDENCIES simplecov! simplecov-cobertura (~> 2.1.0) sqlite3 (~> 1.4) - strscan! trilogy warning (~> 1) webmock (>= 3.10.0) diff --git a/gemfiles/ruby_3.4_resque2_redis3.gemfile b/gemfiles/ruby_3.4_resque2_redis3.gemfile index 441d2cec014..11a44bd90ea 100644 --- a/gemfiles/ruby_3.4_resque2_redis3.gemfile +++ b/gemfiles/ruby_3.4_resque2_redis3.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_resque2_redis3.gemfile.lock b/gemfiles/ruby_3.4_resque2_redis3.gemfile.lock index fa349354fab..2181d0b81d1 100644 --- a/gemfiles/ruby_3.4_resque2_redis3.gemfile.lock +++ b/gemfiles/ruby_3.4_resque2_redis3.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -158,6 +151,7 @@ GEM rack-protection (= 4.0.0) rack-session (>= 2.0.0, < 3) tilt (~> 2.0) + strscan (3.1.1) tilt (2.4.0) unicode-display_width (2.5.0) warning (1.4.0) @@ -203,7 +197,6 @@ DEPENDENCIES rubocop-rspec (~> 2.20, < 2.21) simplecov! simplecov-cobertura (~> 2.1.0) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_resque2_redis4.gemfile b/gemfiles/ruby_3.4_resque2_redis4.gemfile index 71b690f141b..1d97a21787a 100644 --- a/gemfiles/ruby_3.4_resque2_redis4.gemfile +++ b/gemfiles/ruby_3.4_resque2_redis4.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_resque2_redis4.gemfile.lock b/gemfiles/ruby_3.4_resque2_redis4.gemfile.lock index 8a64dc9b6e4..8480cc29f1e 100644 --- a/gemfiles/ruby_3.4_resque2_redis4.gemfile.lock +++ b/gemfiles/ruby_3.4_resque2_redis4.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -162,6 +155,7 @@ GEM rack-protection (= 4.0.0) rack-session (>= 2.0.0, < 3) tilt (~> 2.0) + strscan (3.1.1) tilt (2.4.0) unicode-display_width (2.5.0) warning (1.4.0) @@ -207,7 +201,6 @@ DEPENDENCIES rubocop-rspec (~> 2.20, < 2.21) simplecov! simplecov-cobertura (~> 2.1.0) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_sinatra_2.gemfile b/gemfiles/ruby_3.4_sinatra_2.gemfile index 5c157ea5e77..41fda663a9f 100644 --- a/gemfiles/ruby_3.4_sinatra_2.gemfile +++ b/gemfiles/ruby_3.4_sinatra_2.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_sinatra_2.gemfile.lock b/gemfiles/ruby_3.4_sinatra_2.gemfile.lock index 0ae275e47d7..7dd32ba1e29 100644 --- a/gemfiles/ruby_3.4_sinatra_2.gemfile.lock +++ b/gemfiles/ruby_3.4_sinatra_2.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -148,6 +141,7 @@ GEM rack (~> 2.2) rack-protection (= 2.2.4) tilt (~> 2.0) + strscan (3.1.1) tilt (2.4.0) unicode-display_width (2.5.0) warning (1.4.0) @@ -194,7 +188,6 @@ DEPENDENCIES simplecov! simplecov-cobertura (~> 2.1.0) sinatra (~> 2) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_sinatra_3.gemfile b/gemfiles/ruby_3.4_sinatra_3.gemfile index 808a0a071a8..f0a164eb69b 100644 --- a/gemfiles/ruby_3.4_sinatra_3.gemfile +++ b/gemfiles/ruby_3.4_sinatra_3.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_sinatra_3.gemfile.lock b/gemfiles/ruby_3.4_sinatra_3.gemfile.lock index 5ac70a1ed5b..31412a6cf53 100644 --- a/gemfiles/ruby_3.4_sinatra_3.gemfile.lock +++ b/gemfiles/ruby_3.4_sinatra_3.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -149,6 +142,7 @@ GEM rack (~> 2.2, >= 2.2.4) rack-protection (= 3.2.0) tilt (~> 2.0) + strscan (3.1.1) tilt (2.4.0) unicode-display_width (2.5.0) warning (1.4.0) @@ -195,7 +189,6 @@ DEPENDENCIES simplecov! simplecov-cobertura (~> 2.1.0) sinatra (~> 3) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_sinatra_4.gemfile b/gemfiles/ruby_3.4_sinatra_4.gemfile index dce6bd501f4..6a26ce80c7c 100644 --- a/gemfiles/ruby_3.4_sinatra_4.gemfile +++ b/gemfiles/ruby_3.4_sinatra_4.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_sinatra_4.gemfile.lock b/gemfiles/ruby_3.4_sinatra_4.gemfile.lock index aa6745e09aa..e85be404281 100644 --- a/gemfiles/ruby_3.4_sinatra_4.gemfile.lock +++ b/gemfiles/ruby_3.4_sinatra_4.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -152,6 +145,7 @@ GEM rack-protection (= 4.0.0) rack-session (>= 2.0.0, < 3) tilt (~> 2.0) + strscan (3.1.1) tilt (2.4.0) unicode-display_width (2.5.0) warning (1.4.0) @@ -198,7 +192,6 @@ DEPENDENCIES simplecov! simplecov-cobertura (~> 2.1.0) sinatra (~> 4) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_stripe_10.gemfile b/gemfiles/ruby_3.4_stripe_10.gemfile index 564e99d4354..73f9288292b 100644 --- a/gemfiles/ruby_3.4_stripe_10.gemfile +++ b/gemfiles/ruby_3.4_stripe_10.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_stripe_10.gemfile.lock b/gemfiles/ruby_3.4_stripe_10.gemfile.lock index 1152fca6317..6bb9b782b1b 100644 --- a/gemfiles/ruby_3.4_stripe_10.gemfile.lock +++ b/gemfiles/ruby_3.4_stripe_10.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -134,6 +127,7 @@ GEM simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) stripe (10.15.0) + strscan (3.1.1) unicode-display_width (2.5.0) warning (1.4.0) webmock (3.23.1) @@ -177,7 +171,6 @@ DEPENDENCIES simplecov! simplecov-cobertura (~> 2.1.0) stripe (~> 10) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_stripe_11.gemfile b/gemfiles/ruby_3.4_stripe_11.gemfile index 8744f24ffd2..549cf4f0f28 100644 --- a/gemfiles/ruby_3.4_stripe_11.gemfile +++ b/gemfiles/ruby_3.4_stripe_11.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_stripe_11.gemfile.lock b/gemfiles/ruby_3.4_stripe_11.gemfile.lock index 9a6bdc16caf..090dc7b61d3 100644 --- a/gemfiles/ruby_3.4_stripe_11.gemfile.lock +++ b/gemfiles/ruby_3.4_stripe_11.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -134,6 +127,7 @@ GEM simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) stripe (11.7.0) + strscan (3.1.1) unicode-display_width (2.5.0) warning (1.4.0) webmock (3.23.1) @@ -177,7 +171,6 @@ DEPENDENCIES simplecov! simplecov-cobertura (~> 2.1.0) stripe (~> 11) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_stripe_12.gemfile b/gemfiles/ruby_3.4_stripe_12.gemfile index 8a5eefa2e33..8040f2e5afe 100644 --- a/gemfiles/ruby_3.4_stripe_12.gemfile +++ b/gemfiles/ruby_3.4_stripe_12.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_stripe_12.gemfile.lock b/gemfiles/ruby_3.4_stripe_12.gemfile.lock index 511dde8abf7..cad39c3e5f5 100644 --- a/gemfiles/ruby_3.4_stripe_12.gemfile.lock +++ b/gemfiles/ruby_3.4_stripe_12.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -134,6 +127,7 @@ GEM simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) stripe (12.6.0) + strscan (3.1.1) unicode-display_width (2.5.0) warning (1.4.0) webmock (3.23.1) @@ -177,7 +171,6 @@ DEPENDENCIES simplecov! simplecov-cobertura (~> 2.1.0) stripe (~> 12) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_stripe_7.gemfile b/gemfiles/ruby_3.4_stripe_7.gemfile index aa0580743a2..f5212922ca1 100644 --- a/gemfiles/ruby_3.4_stripe_7.gemfile +++ b/gemfiles/ruby_3.4_stripe_7.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_stripe_7.gemfile.lock b/gemfiles/ruby_3.4_stripe_7.gemfile.lock index 8bf4aaf86fd..058c1577101 100644 --- a/gemfiles/ruby_3.4_stripe_7.gemfile.lock +++ b/gemfiles/ruby_3.4_stripe_7.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -134,6 +127,7 @@ GEM simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) stripe (7.1.0) + strscan (3.1.1) unicode-display_width (2.5.0) warning (1.4.0) webmock (3.23.1) @@ -177,7 +171,6 @@ DEPENDENCIES simplecov! simplecov-cobertura (~> 2.1.0) stripe (~> 7) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_stripe_8.gemfile b/gemfiles/ruby_3.4_stripe_8.gemfile index bf483a884d8..d589321c320 100644 --- a/gemfiles/ruby_3.4_stripe_8.gemfile +++ b/gemfiles/ruby_3.4_stripe_8.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_stripe_8.gemfile.lock b/gemfiles/ruby_3.4_stripe_8.gemfile.lock index acd8dd37ed8..a81bba9fae0 100644 --- a/gemfiles/ruby_3.4_stripe_8.gemfile.lock +++ b/gemfiles/ruby_3.4_stripe_8.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -134,6 +127,7 @@ GEM simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) stripe (8.7.0) + strscan (3.1.1) unicode-display_width (2.5.0) warning (1.4.0) webmock (3.23.1) @@ -177,7 +171,6 @@ DEPENDENCIES simplecov! simplecov-cobertura (~> 2.1.0) stripe (~> 8) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_stripe_9.gemfile b/gemfiles/ruby_3.4_stripe_9.gemfile index 555bae6e9ce..338036c8081 100644 --- a/gemfiles/ruby_3.4_stripe_9.gemfile +++ b/gemfiles/ruby_3.4_stripe_9.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_stripe_9.gemfile.lock b/gemfiles/ruby_3.4_stripe_9.gemfile.lock index 9e3ec1b1f0f..e62a943ea07 100644 --- a/gemfiles/ruby_3.4_stripe_9.gemfile.lock +++ b/gemfiles/ruby_3.4_stripe_9.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -134,6 +127,7 @@ GEM simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) stripe (9.4.0) + strscan (3.1.1) unicode-display_width (2.5.0) warning (1.4.0) webmock (3.23.1) @@ -177,7 +171,6 @@ DEPENDENCIES simplecov! simplecov-cobertura (~> 2.1.0) stripe (~> 9) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_stripe_latest.gemfile b/gemfiles/ruby_3.4_stripe_latest.gemfile index 32fde1e0507..dcf18e7238c 100644 --- a/gemfiles/ruby_3.4_stripe_latest.gemfile +++ b/gemfiles/ruby_3.4_stripe_latest.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_stripe_latest.gemfile.lock b/gemfiles/ruby_3.4_stripe_latest.gemfile.lock index 8673ec338da..1aca6905be3 100644 --- a/gemfiles/ruby_3.4_stripe_latest.gemfile.lock +++ b/gemfiles/ruby_3.4_stripe_latest.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -132,7 +125,7 @@ GEM simplecov (~> 0.19) simplecov-html (0.13.1) simplecov_json_formatter (0.1.4) - stripe (13.2.0) + stripe (13.3.0) unicode-display_width (2.6.0) warning (1.4.0) webmock (3.23.1) @@ -176,7 +169,6 @@ DEPENDENCIES simplecov! simplecov-cobertura (~> 2.1.0) stripe - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/gemfiles/ruby_3.4_stripe_min.gemfile b/gemfiles/ruby_3.4_stripe_min.gemfile index 7082d9f9cfd..bd90818d9c2 100644 --- a/gemfiles/ruby_3.4_stripe_min.gemfile +++ b/gemfiles/ruby_3.4_stripe_min.gemfile @@ -30,7 +30,6 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "simplecov", git: "https://github.com/DataDog/simplecov", ref: "3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db" gem "simplecov-cobertura", "~> 2.1.0" -gem "strscan", git: "https://github.com/ruby/strscan", ref: "041b15df4ccc067deabd85fd489b2c15961d0e2f" gem "warning", "~> 1" gem "webmock", ">= 3.10.0" gem "webrick", ">= 1.8.2" diff --git a/gemfiles/ruby_3.4_stripe_min.gemfile.lock b/gemfiles/ruby_3.4_stripe_min.gemfile.lock index e3c6d1caa72..a0db08d178c 100644 --- a/gemfiles/ruby_3.4_stripe_min.gemfile.lock +++ b/gemfiles/ruby_3.4_stripe_min.gemfile.lock @@ -8,13 +8,6 @@ GIT simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) -GIT - remote: https://github.com/ruby/strscan - revision: 041b15df4ccc067deabd85fd489b2c15961d0e2f - ref: 041b15df4ccc067deabd85fd489b2c15961d0e2f - specs: - strscan (3.1.1) - PATH remote: .. specs: @@ -176,7 +169,6 @@ DEPENDENCIES simplecov! simplecov-cobertura (~> 2.1.0) stripe (= 5.15.0) - strscan! warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.8.2) diff --git a/integration/images/ruby/3.4/Dockerfile b/integration/images/ruby/3.4/Dockerfile index 3cc6648d99f..96500f1c668 100644 --- a/integration/images/ruby/3.4/Dockerfile +++ b/integration/images/ruby/3.4/Dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.4.0-preview2 +FROM ruby:3.4 ENV DEBIAN_FRONTEND=noninteractive diff --git a/integration/script/build-images b/integration/script/build-images index 9a98f4f9516..d3a0f633a25 100755 --- a/integration/script/build-images +++ b/integration/script/build-images @@ -14,7 +14,7 @@ while getopts ":hv:" opt; do echo "Usage: ./script/build-images [-v RUBY_VERSION]" echo echo "If no Ruby version is specified, images are built for each of the" - echo "supported versions (currently 2.1 through 3.3)." + echo "supported versions (currently 2.5 through 3.4)." exit 0 ;; v) @@ -39,10 +39,6 @@ docker build -t datadog/dd-apm-demo:agent -f $INTEGRATION_DIR/images/agent/Docke if test -n "$APP_RUBY_VERSION"; then docker build -t datadog/dd-apm-demo:rb-$APP_RUBY_VERSION -f $INTEGRATION_DIR/images/ruby/$APP_RUBY_VERSION/Dockerfile $INTEGRATION_DIR/images else - docker build -t datadog/dd-apm-demo:rb-2.1 -f $INTEGRATION_DIR/images/ruby/2.1/Dockerfile $INTEGRATION_DIR/images - docker build -t datadog/dd-apm-demo:rb-2.2 -f $INTEGRATION_DIR/images/ruby/2.2/Dockerfile $INTEGRATION_DIR/images - docker build -t datadog/dd-apm-demo:rb-2.3 -f $INTEGRATION_DIR/images/ruby/2.3/Dockerfile $INTEGRATION_DIR/images - docker build -t datadog/dd-apm-demo:rb-2.4 -f $INTEGRATION_DIR/images/ruby/2.4/Dockerfile $INTEGRATION_DIR/images docker build -t datadog/dd-apm-demo:rb-2.5 -f $INTEGRATION_DIR/images/ruby/2.5/Dockerfile $INTEGRATION_DIR/images docker build -t datadog/dd-apm-demo:rb-2.6 -f $INTEGRATION_DIR/images/ruby/2.6/Dockerfile $INTEGRATION_DIR/images docker build -t datadog/dd-apm-demo:rb-2.7 -f $INTEGRATION_DIR/images/ruby/2.7/Dockerfile $INTEGRATION_DIR/images diff --git a/lib/datadog/core/configuration.rb b/lib/datadog/core/configuration.rb index 826a3bb414a..4b2b21d6ee7 100644 --- a/lib/datadog/core/configuration.rb +++ b/lib/datadog/core/configuration.rb @@ -236,7 +236,7 @@ def safely_synchronize rescue ThreadError => e logger_without_components.error( 'Detected deadlock during datadog initialization. ' \ - 'Please report this at https://github.com/DataDog/dd-trace-rb/blob/master/CONTRIBUTING.md#found-a-bug' \ + 'Please report this at https://github.com/datadog/dd-trace-rb/blob/master/CONTRIBUTING.md#found-a-bug' \ "\n\tSource:\n\t#{Array(e.backtrace).join("\n\t")}" ) nil diff --git a/lib/datadog/core/configuration/agent_settings_resolver.rb b/lib/datadog/core/configuration/agent_settings_resolver.rb index 7d7c048f553..5ced057274a 100644 --- a/lib/datadog/core/configuration/agent_settings_resolver.rb +++ b/lib/datadog/core/configuration/agent_settings_resolver.rb @@ -19,21 +19,49 @@ module Configuration # Whenever there is a conflict (different configurations are provided in different orders), it MUST warn the users # about it and pick a value based on the following priority: code > environment variable > defaults. class AgentSettingsResolver - AgentSettings = Struct.new( - :adapter, - :ssl, - :hostname, - :port, - :uds_path, - :timeout_seconds, - keyword_init: true - ) do - def initialize(*) - super + # Immutable container for the resulting settings + class AgentSettings + attr_reader :adapter, :ssl, :hostname, :port, :uds_path, :timeout_seconds + + def initialize(adapter: nil, ssl: nil, hostname: nil, port: nil, uds_path: nil, timeout_seconds: nil) + @adapter = adapter + @ssl = ssl + @hostname = hostname + @port = port + @uds_path = uds_path + @timeout_seconds = timeout_seconds freeze end + + def url + case adapter + when Datadog::Core::Configuration::Ext::Agent::HTTP::ADAPTER + hostname = self.hostname + hostname = "[#{hostname}]" if hostname =~ IPV6_REGEXP + "#{ssl ? 'https' : 'http'}://#{hostname}:#{port}/" + when Datadog::Core::Configuration::Ext::Agent::UnixSocket::ADAPTER + "unix://#{uds_path}" + else + raise ArgumentError, "Unexpected adapter: #{adapter}" + end + end + + def ==(other) + self.class == other.class && + adapter == other.adapter && + ssl == other.ssl && + hostname == other.hostname && + port == other.port && + uds_path == other.uds_path && + timeout_seconds == other.timeout_seconds + end end + # IPv6 regular expression from + # https://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses + # Does not match IPv4 addresses. + 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 + def self.call(settings, logger: Datadog.logger) new(settings, logger: logger).send(:call) end diff --git a/lib/datadog/core/crashtracking/agent_base_url.rb b/lib/datadog/core/crashtracking/agent_base_url.rb deleted file mode 100644 index 74b59a1cda5..00000000000 --- a/lib/datadog/core/crashtracking/agent_base_url.rb +++ /dev/null @@ -1,28 +0,0 @@ -# frozen_string_literal: true - -require_relative '../configuration/ext' - -module Datadog - module Core - module Crashtracking - # This module provides a method to resolve the base URL of the agent - module AgentBaseUrl - # IPv6 regular expression from - # https://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses - # Does not match IPv4 addresses. - 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 - - def self.resolve(agent_settings) - case agent_settings.adapter - when Datadog::Core::Configuration::Ext::Agent::HTTP::ADAPTER - hostname = agent_settings.hostname - hostname = "[#{hostname}]" if hostname =~ IPV6_REGEXP - "#{agent_settings.ssl ? 'https' : 'http'}://#{hostname}:#{agent_settings.port}/" - when Datadog::Core::Configuration::Ext::Agent::UnixSocket::ADAPTER - "unix://#{agent_settings.uds_path}" - end - end - end - end - end -end diff --git a/lib/datadog/core/crashtracking/component.rb b/lib/datadog/core/crashtracking/component.rb index ee04e1c5cc8..460a7974bc5 100644 --- a/lib/datadog/core/crashtracking/component.rb +++ b/lib/datadog/core/crashtracking/component.rb @@ -3,7 +3,6 @@ require 'libdatadog' require_relative 'tag_builder' -require_relative 'agent_base_url' require_relative '../utils/only_once' require_relative '../utils/at_fork_monkey_patch' @@ -31,8 +30,7 @@ class Component def self.build(settings, agent_settings, logger:) tags = TagBuilder.call(settings) - agent_base_url = AgentBaseUrl.resolve(agent_settings) - logger.warn('Missing agent base URL; cannot enable crash tracking') unless agent_base_url + agent_base_url = agent_settings.url ld_library_path = ::Libdatadog.ld_library_path logger.warn('Missing ld_library_path; cannot enable crash tracking') unless ld_library_path diff --git a/lib/datadog/profiling/http_transport.rb b/lib/datadog/profiling/http_transport.rb index 2c89c6548b7..9de76899494 100644 --- a/lib/datadog/profiling/http_transport.rb +++ b/lib/datadog/profiling/http_transport.rb @@ -13,13 +13,11 @@ class HttpTransport def initialize(agent_settings:, site:, api_key:, upload_timeout_seconds:) @upload_timeout_milliseconds = (upload_timeout_seconds * 1_000).to_i - validate_agent_settings(agent_settings) - @exporter_configuration = if agentless?(site, api_key) [:agentless, site, api_key].freeze else - [:agent, base_url_from(agent_settings)].freeze + [:agent, agent_settings.url].freeze end status, result = validate_exporter(exporter_configuration) @@ -75,29 +73,6 @@ def export(flush) private - def base_url_from(agent_settings) - case agent_settings.adapter - when Datadog::Core::Configuration::Ext::Agent::HTTP::ADAPTER - "#{agent_settings.ssl ? "https" : "http"}://#{agent_settings.hostname}:#{agent_settings.port}/" - when Datadog::Core::Configuration::Ext::Agent::UnixSocket::ADAPTER - "unix://#{agent_settings.uds_path}" - else - raise ArgumentError, "Unexpected adapter: #{agent_settings.adapter}" - end - end - - def validate_agent_settings(agent_settings) - supported_adapters = [ - Datadog::Core::Configuration::Ext::Agent::UnixSocket::ADAPTER, - Datadog::Core::Configuration::Ext::Agent::HTTP::ADAPTER - ] - unless supported_adapters.include?(agent_settings.adapter) - raise ArgumentError, - "Unsupported transport configuration for profiling: Adapter #{agent_settings.adapter} " \ - " is not supported" - end - end - def agentless?(site, api_key) site && api_key && Core::Environment::VariableHelpers.env_to_bool(Profiling::Ext::ENV_AGENTLESS, false) end diff --git a/ruby-3.4.gemfile b/ruby-3.4.gemfile index 73960422f46..29e8b57e240 100644 --- a/ruby-3.4.gemfile +++ b/ruby-3.4.gemfile @@ -49,15 +49,6 @@ gem 'rubocop-rspec', ['~> 2.20', '< 2.21'], require: false # but given it only affects unsupported version of Ruby, it might not get merged. gem 'simplecov', git: 'https://github.com/DataDog/simplecov', ref: '3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db' gem 'simplecov-cobertura', '~> 2.1.0' # Used by codecov - -# Ruby 3.4 should be supported by strscan v3.1.1. However, the latest release of strscan is v3.1.0. -# Pin strscan to the latest commit sha. -# -# TODO: Remove once v3.1.1 is released. -gem 'strscan', - git: 'https://github.com/ruby/strscan', - ref: '041b15df4ccc067deabd85fd489b2c15961d0e2f' - gem 'warning', '~> 1' # NOTE: Used in spec_helper.rb gem 'webmock', '>= 3.10.0' gem 'webrick', '>= 1.8.2' diff --git a/ruby-3.5.gemfile b/ruby-3.5.gemfile new file mode 100644 index 00000000000..ce83d653fc6 --- /dev/null +++ b/ruby-3.5.gemfile @@ -0,0 +1,67 @@ +source 'https://rubygems.org' + +gemspec + +gem 'base64' +gem 'benchmark-ips', '~> 2.8' +gem 'benchmark-memory', '< 0.2' # V0.2 only works with 2.5+ +gem 'bigdecimal' +gem 'climate_control', '~> 0.2.0' +gem 'concurrent-ruby' + +# Optional extensions +# TODO: Move this to Appraisals? +# dogstatsd v5, but lower than 5.2, has possible memory leak with datadog. +# @see https://github.com/DataDog/dogstatsd-ruby/issues/182 +gem 'dogstatsd-ruby', '>= 3.3.0', '!= 5.0.0', '!= 5.0.1', '!= 5.1.0' + +gem 'extlz4', '~> 0.3', '>= 0.3.3' + +# Profiler testing dependencies +# NOTE: We're excluding versions 3.7.0 and 3.7.1 for the reasons documented in #1424. +# Since most of our customers won't have BUNDLE_FORCE_RUBY_PLATFORM=true, it's not something we want to add +# to our CI, so we just shortcut and exclude specific versions that were affecting our CI. +gem 'google-protobuf', ['~> 3.0', '!= 3.7.0', '!= 3.7.1'] + +gem 'json-schema', '< 3' # V3 only works with 2.5+ +gem 'memory_profiler', '~> 0.9' +gem 'mutex_m' +gem 'os', '~> 1.1' +gem 'pimpmychangelog', '>= 0.1.2' +gem 'pry' +gem 'pry-stack_explorer' +gem 'rake', '>= 10.5' +gem 'rake-compiler', '~> 1.1', '>= 1.1.1' # To compile native extensions +gem 'rspec', '~> 3.13' +gem 'rspec-collection_matchers', '~> 1.1' +gem 'rspec-wait', '~> 0' +gem 'rspec_junit_formatter', '>= 0.5.1' + +# 1.50 is the last version to support Ruby 2.6 +gem 'rubocop', '~> 1.50.0', require: false +gem 'rubocop-packaging', '~> 0.5.2', require: false +gem 'rubocop-performance', '~> 1.9', require: false +# 2.20 is the last version to support Ruby 2.6 +gem 'rubocop-rspec', ['~> 2.20', '< 2.21'], require: false + +# Merging branch coverage results does not work for old, unsupported rubies and JRuby +# We have a fix up for review, https://github.com/simplecov-ruby/simplecov/pull/972, +# but given it only affects unsupported version of Ruby, it might not get merged. +gem 'simplecov', git: 'https://github.com/DataDog/simplecov', ref: '3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db' +gem 'simplecov-cobertura', '~> 2.1.0' # Used by codecov + +gem 'warning', '~> 1' # NOTE: Used in spec_helper.rb +gem 'webmock', '>= 3.10.0' +gem 'webrick', '>= 1.8.2' + +group :check do + gem 'rbs', '~> 3.7', require: false + gem 'steep', '~> 1', '>= 1.9.1', require: false + gem 'ruby_memcheck', '>= 3' + gem 'standard', require: false +end + +group :dev do + gem 'ruby-lsp', require: false + gem 'appraisal', '~> 2.4.0', require: false +end diff --git a/sig/datadog/core/configuration/agent_settings_resolver.rbs b/sig/datadog/core/configuration/agent_settings_resolver.rbs index 040a9aa960a..e3a2472abf4 100644 --- a/sig/datadog/core/configuration/agent_settings_resolver.rbs +++ b/sig/datadog/core/configuration/agent_settings_resolver.rbs @@ -2,9 +2,8 @@ module Datadog module Core module Configuration class AgentSettingsResolver - class AgentSettings < ::Struct[untyped] + class AgentSettings def initialize: (adapter: untyped, ssl: untyped, hostname: untyped, port: untyped, uds_path: untyped, timeout_seconds: untyped) -> void - def merge: (**::Hash[untyped, untyped] member_values) -> AgentSettingsResolver attr_reader adapter: untyped attr_reader ssl: untyped @@ -12,8 +11,26 @@ module Datadog attr_reader port: untyped attr_reader uds_path: untyped attr_reader timeout_seconds: untyped + + def url: () -> ::String end + @settings: untyped + @logger: untyped + @configured_hostname: untyped + @configured_port: untyped + @configured_ssl: untyped + @configured_timeout_seconds: untyped + @configured_uds_path: untyped + @uds_fallback: untyped + @mixed_http_and_uds: untyped + @parsed_url: untyped + + # IPv6 regular expression from + # https://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses + # Does not match IPv4 addresses. + IPV6_REGEXP: ::Regexp + def self.call: (untyped settings, ?logger: untyped) -> untyped private @@ -38,33 +55,31 @@ module Datadog def configured_uds_path: () -> untyped - def try_parsing_as_integer: (value: untyped, friendly_name: untyped) -> untyped + def parsed_url_ssl?: () -> (nil | untyped) - def try_parsing_as_boolean: (value: untyped, friendly_name: untyped) -> untyped + def try_parsing_as_integer: (value: untyped, friendly_name: untyped) -> untyped - def ssl?: () -> bool + def ssl?: () -> (false | untyped) def hostname: () -> untyped def port: () -> untyped - def uds_path: () -> untyped - def timeout_seconds: () -> untyped - def uds_fallback: () -> untyped + def parsed_url_uds_path: () -> (nil | untyped) - def should_use_uds_fallback?: () -> untyped + def uds_path: () -> (nil | untyped) - def should_use_uds?: () -> bool + def uds_fallback: () -> untyped - def can_use_uds?: () -> bool + def should_use_uds?: () -> untyped - def parsed_url: () -> untyped + def mixed_http_and_uds: () -> untyped - def parsed_url_ssl?: () -> untyped + def can_use_uds?: () -> untyped - def parsed_url_uds_path: () -> untyped + def parsed_url: () -> untyped def pick_from: (*untyped configurations_in_priority_order) -> untyped @@ -72,7 +87,17 @@ module Datadog def log_warning: (untyped message) -> (untyped | nil) + def http_scheme?: (untyped uri) -> untyped + + def parsed_http_url: () -> (untyped | nil) + + def unix_scheme?: (untyped uri) -> untyped + class DetectedConfiguration + @friendly_name: untyped + + @value: untyped + attr_reader friendly_name: untyped attr_reader value: untyped diff --git a/sig/datadog/core/configuration/ext.rbs b/sig/datadog/core/configuration/ext.rbs index 71b7acc0951..77f9eae8265 100644 --- a/sig/datadog/core/configuration/ext.rbs +++ b/sig/datadog/core/configuration/ext.rbs @@ -15,6 +15,7 @@ module Datadog end module Agent + ENV_DEFAULT_HOST: 'DD_AGENT_HOST' ENV_DEFAULT_PORT: 'DD_TRACE_AGENT_PORT' ENV_DEFAULT_URL: 'DD_TRACE_AGENT_URL' ENV_DEFAULT_TIMEOUT_SECONDS: 'DD_TRACE_AGENT_TIMEOUT_SECONDS' diff --git a/sig/datadog/core/crashtracking/agent_base_url.rbs b/sig/datadog/core/crashtracking/agent_base_url.rbs deleted file mode 100644 index 3a2c77f8e85..00000000000 --- a/sig/datadog/core/crashtracking/agent_base_url.rbs +++ /dev/null @@ -1,10 +0,0 @@ -module Datadog - module Core - module Crashtracking - module AgentBaseUrl - IPV6_REGEXP: Regexp - def self.resolve: (Datadog::Core::Configuration::AgentSettingsResolver::AgentSettings) -> ::String? - end - end - end -end diff --git a/sig/datadog/profiling/http_transport.rbs b/sig/datadog/profiling/http_transport.rbs index 8c58ea8180e..af663a225b7 100644 --- a/sig/datadog/profiling/http_transport.rbs +++ b/sig/datadog/profiling/http_transport.rbs @@ -19,10 +19,6 @@ module Datadog private - def base_url_from: (Datadog::Core::Configuration::AgentSettingsResolver::AgentSettings agent_settings) -> ::String - - def validate_agent_settings: (Datadog::Core::Configuration::AgentSettingsResolver::AgentSettings agent_settings) -> void - def agentless?: (::String? site, ::String? api_key) -> bool def validate_exporter: (exporter_configuration_array exporter_configuration) -> [:ok | :error, ::String?] diff --git a/spec/datadog/core/configuration/agent_settings_resolver_spec.rb b/spec/datadog/core/configuration/agent_settings_resolver_spec.rb index ef2a6766ea1..c057e520739 100644 --- a/spec/datadog/core/configuration/agent_settings_resolver_spec.rb +++ b/spec/datadog/core/configuration/agent_settings_resolver_spec.rb @@ -803,4 +803,61 @@ end end end + + describe 'url' do + context 'when using HTTP adapter' do + before do + datadog_settings.agent.host = 'example.com' + datadog_settings.agent.port = 8080 + end + + context 'when SSL is enabled' do + before { datadog_settings.agent.use_ssl = true } + + it 'returns the correct base URL' do + expect(resolver.url).to eq('https://example.com:8080/') + end + end + + context 'when SSL is disabled' do + before { datadog_settings.agent.use_ssl = false } + + it 'returns the correct base URL' do + expect(resolver.url).to eq('http://example.com:8080/') + end + end + + context 'when hostname is an IPv4 address' do + before { datadog_settings.agent.host = '1.2.3.4' } + + it 'returns the correct base URL' do + expect(resolver.url).to eq('http://1.2.3.4:8080/') + end + end + + context 'when hostname is an IPv6 address' do + before { datadog_settings.agent.host = '1234:1234::1' } + + it 'returns the correct base URL' do + expect(resolver.url).to eq('http://[1234:1234::1]:8080/') + end + end + end + + context 'when using UnixSocket adapter' do + before { datadog_settings.agent.uds_path = '/var/run/datadog.sock' } + + it 'returns the correct base URL' do + expect(resolver.url).to eq('unix:///var/run/datadog.sock') + end + end + + context 'when using an unknown adapter' do + it 'raises an exception' do + agent_settings = Datadog::Core::Configuration::AgentSettingsResolver::AgentSettings.new(adapter: :unknown) + + expect { agent_settings.url }.to raise_error(ArgumentError, /Unexpected adapter/) + end + end + end end diff --git a/spec/datadog/core/crashtracking/agent_base_url_spec.rb b/spec/datadog/core/crashtracking/agent_base_url_spec.rb deleted file mode 100644 index 407b74daf26..00000000000 --- a/spec/datadog/core/crashtracking/agent_base_url_spec.rb +++ /dev/null @@ -1,98 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require 'datadog/core/crashtracking/agent_base_url' - -RSpec.describe Datadog::Core::Crashtracking::AgentBaseUrl do - describe '.resolve' do - context 'when using HTTP adapter' do - context 'when SSL is enabled' do - let(:agent_settings) do - instance_double( - Datadog::Core::Configuration::AgentSettingsResolver::AgentSettings, - adapter: Datadog::Core::Configuration::Ext::Agent::HTTP::ADAPTER, - ssl: true, - hostname: 'example.com', - port: 8080 - ) - end - - it 'returns the correct base URL' do - expect(described_class.resolve(agent_settings)).to eq('https://example.com:8080/') - end - end - - context 'when SSL is disabled' do - let(:agent_settings) do - instance_double( - Datadog::Core::Configuration::AgentSettingsResolver::AgentSettings, - adapter: Datadog::Core::Configuration::Ext::Agent::HTTP::ADAPTER, - ssl: false, - hostname: 'example.com', - port: 8080 - ) - end - - it 'returns the correct base URL' do - expect(described_class.resolve(agent_settings)).to eq('http://example.com:8080/') - end - end - - context 'when hostname is an IPv4 address' do - let(:agent_settings) do - instance_double( - Datadog::Core::Configuration::AgentSettingsResolver::AgentSettings, - adapter: Datadog::Core::Configuration::Ext::Agent::HTTP::ADAPTER, - ssl: false, - hostname: '1.2.3.4', - port: 8080 - ) - end - - it 'returns the correct base URL' do - expect(described_class.resolve(agent_settings)).to eq('http://1.2.3.4:8080/') - end - end - - context 'when hostname is an IPv6 address' do - let(:agent_settings) do - instance_double( - Datadog::Core::Configuration::AgentSettingsResolver::AgentSettings, - adapter: Datadog::Core::Configuration::Ext::Agent::HTTP::ADAPTER, - ssl: false, - hostname: '1234:1234::1', - port: 8080 - ) - end - - it 'returns the correct base URL' do - expect(described_class.resolve(agent_settings)).to eq('http://[1234:1234::1]:8080/') - end - end - end - - context 'when using UnixSocket adapter' do - let(:agent_settings) do - instance_double( - Datadog::Core::Configuration::AgentSettingsResolver::AgentSettings, - adapter: Datadog::Core::Configuration::Ext::Agent::UnixSocket::ADAPTER, - uds_path: '/var/run/datadog.sock' - ) - end - - it 'returns the correct base URL' do - expect(described_class.resolve(agent_settings)).to eq('unix:///var/run/datadog.sock') - end - end - - context 'when using unknownm adapter' do - let(:agent_settings) do - instance_double(Datadog::Core::Configuration::AgentSettingsResolver::AgentSettings, adapter: 'unknown') - end - - it 'returns nil' do - expect(described_class.resolve(agent_settings)).to be_nil - end - end - end -end diff --git a/spec/datadog/core/crashtracking/component_spec.rb b/spec/datadog/core/crashtracking/component_spec.rb index 034bd5f441e..fcbef942d43 100644 --- a/spec/datadog/core/crashtracking/component_spec.rb +++ b/spec/datadog/core/crashtracking/component_spec.rb @@ -9,7 +9,9 @@ describe '.build' do let(:settings) { Datadog::Core::Configuration::Settings.new } - let(:agent_settings) { double('agent_settings') } + let(:agent_settings) do + instance_double(Datadog::Core::Configuration::AgentSettingsResolver::AgentSettings) + end let(:tags) { { 'tag1' => 'value1' } } let(:agent_base_url) { 'agent_base_url' } let(:ld_library_path) { 'ld_library_path' } @@ -19,8 +21,7 @@ it 'creates a new instance of Component and starts it' do expect(Datadog::Core::Crashtracking::TagBuilder).to receive(:call).with(settings) .and_return(tags) - expect(Datadog::Core::Crashtracking::AgentBaseUrl).to receive(:resolve).with(agent_settings) - .and_return(agent_base_url) + expect(agent_settings).to receive(:url).and_return(agent_base_url) expect(::Libdatadog).to receive(:ld_library_path) .and_return(ld_library_path) expect(::Libdatadog).to receive(:path_to_crashtracking_receiver_binary) @@ -42,32 +43,13 @@ end end - context 'when missing `agent_base_url`' do - let(:agent_base_url) { nil } - - it 'returns nil' do - expect(Datadog::Core::Crashtracking::TagBuilder).to receive(:call).with(settings) - .and_return(tags) - expect(Datadog::Core::Crashtracking::AgentBaseUrl).to receive(:resolve).with(agent_settings) - .and_return(agent_base_url) - expect(::Libdatadog).to receive(:ld_library_path) - .and_return(ld_library_path) - expect(::Libdatadog).to receive(:path_to_crashtracking_receiver_binary) - .and_return(path_to_crashtracking_receiver_binary) - expect(logger).to receive(:warn).with(/cannot enable crash tracking/) - - expect(described_class.build(settings, agent_settings, logger: logger)).to be_nil - end - end - context 'when missing `ld_library_path`' do let(:ld_library_path) { nil } it 'returns nil' do expect(Datadog::Core::Crashtracking::TagBuilder).to receive(:call).with(settings) .and_return(tags) - expect(Datadog::Core::Crashtracking::AgentBaseUrl).to receive(:resolve).with(agent_settings) - .and_return(agent_base_url) + expect(agent_settings).to receive(:url).and_return(agent_base_url) expect(::Libdatadog).to receive(:ld_library_path) .and_return(ld_library_path) expect(::Libdatadog).to receive(:path_to_crashtracking_receiver_binary) @@ -84,8 +66,7 @@ it 'returns nil' do expect(Datadog::Core::Crashtracking::TagBuilder).to receive(:call).with(settings) .and_return(tags) - expect(Datadog::Core::Crashtracking::AgentBaseUrl).to receive(:resolve).with(agent_settings) - .and_return(agent_base_url) + expect(agent_settings).to receive(:url).and_return(agent_base_url) expect(::Libdatadog).to receive(:ld_library_path) .and_return(ld_library_path) expect(::Libdatadog).to receive(:path_to_crashtracking_receiver_binary) @@ -102,8 +83,7 @@ it 'returns an instance of Component that failed to start' do expect(Datadog::Core::Crashtracking::TagBuilder).to receive(:call).with(settings) .and_return(tags) - expect(Datadog::Core::Crashtracking::AgentBaseUrl).to receive(:resolve).with(agent_settings) - .and_return(agent_base_url) + expect(agent_settings).to receive(:url).and_return(agent_base_url) expect(::Libdatadog).to receive(:ld_library_path) .and_return(ld_library_path) expect(::Libdatadog).to receive(:path_to_crashtracking_receiver_binary) diff --git a/spec/datadog/profiling/collectors/thread_context_spec.rb b/spec/datadog/profiling/collectors/thread_context_spec.rb index e7b1bd28ba0..0296be0ff72 100644 --- a/spec/datadog/profiling/collectors/thread_context_spec.rb +++ b/spec/datadog/profiling/collectors/thread_context_spec.rb @@ -66,8 +66,8 @@ end end - def sample(profiler_overhead_stack_thread: Thread.current) - described_class::Testing._native_sample(cpu_and_wall_time_collector, profiler_overhead_stack_thread) + def sample(profiler_overhead_stack_thread: Thread.current, allow_exception: false) + described_class::Testing._native_sample(cpu_and_wall_time_collector, profiler_overhead_stack_thread, allow_exception) end def on_gc_start @@ -78,8 +78,12 @@ def on_gc_finish described_class::Testing._native_on_gc_finish(cpu_and_wall_time_collector) end - def sample_after_gc(reset_monotonic_to_system_state: false) - described_class::Testing._native_sample_after_gc(cpu_and_wall_time_collector, reset_monotonic_to_system_state) + def sample_after_gc(reset_monotonic_to_system_state: false, allow_exception: false) + described_class::Testing._native_sample_after_gc( + cpu_and_wall_time_collector, + reset_monotonic_to_system_state, + allow_exception, + ) end def sample_allocation(weight:, new_object: Object.new) @@ -584,6 +588,7 @@ def self.otel_otlp_exporter_available? false end + # When opentelemetry-sdk is on the Gemfile, but not opentelemetry-exporter-otlp context "when trace comes from otel sdk", if: otel_sdk_available? && !otel_otlp_exporter_available? do let(:otel_tracer) do require "datadog/opentelemetry" @@ -618,6 +623,31 @@ def self.otel_otlp_exporter_available? expect(t1_sample.labels).to_not include("trace endpoint": anything) end + describe 'accessing the current span' do + before do + allow(Datadog.logger).to receive(:error) + + # initialize otel context reading + sample + # clear samples + recorder.serialize! + end + + it 'does not try to hash the CURRENT_SPAN_KEY' do + inner_check_ran = false + + otel_tracer.in_span("profiler.test") do |_span| + expect(OpenTelemetry::Trace.const_get(:CURRENT_SPAN_KEY)).to_not receive(:hash) + + sample_allocation(weight: 1) + + inner_check_ran = true + end + + expect(inner_check_ran).to be true + end + end + context "when there are multiple otel spans nested" do let(:t1) do Thread.new(ready_queue, otel_tracer) do |ready_queue, otel_tracer| @@ -717,6 +747,7 @@ def self.otel_otlp_exporter_available? end end + # When opentelemetry-sdk AND opentelemetry-exporter-otlp are on the Gemfile context( "when trace comes from otel sdk and the ddtrace otel support is not loaded", if: otel_sdk_available? && otel_otlp_exporter_available? @@ -765,7 +796,7 @@ def otel_span_id_to_i(span_id) expect(t1_sample.labels).to_not include("trace endpoint": anything) end - context 'reading CURRENT_SPAN_KEY' do + describe 'reading CURRENT_SPAN_KEY into otel_current_span_key' do let!(:ran_log) { [] } let(:setup_failure) do @@ -782,18 +813,18 @@ def otel_span_id_to_i(span_id) ) end - context 'raises an exception' do + context 'when an exception is raised' do before { setup_failure } after { expect(ran_log).to eq [:ran_code] } it 'does not leave the exception pending' do - sample + sample(allow_exception: true) expect($!).to be nil end it 'omits the "local root span id" and "span id" labels in the sample' do - sample + sample(allow_exception: true) expect(t1_sample.labels.keys).to_not include(:"local root span id", :"span id") end @@ -814,6 +845,61 @@ def otel_span_id_to_i(span_id) end end + describe 'accessing the current span' do + before do + allow(OpenTelemetry.logger).to receive(:error) + + # initialize otel context reading + sample + # clear samples + recorder.serialize! + end + + it 'does not try to hash the CURRENT_SPAN_KEY' do + inner_check_ran = false + + otel_tracer.in_span("profiler.test") do |_span| + expect(OpenTelemetry::Trace.const_get(:CURRENT_SPAN_KEY)).to_not receive(:hash) + + sample_allocation(weight: 1) + + inner_check_ran = true + end + + expect(inner_check_ran).to be true + end + + context 'when there are more than MAX_SAFE_LOOKUP_SIZE entries in the otel context' do + let(:max_safe_lookup_size) { 16 } # Value of MAX_SAFE_LOOKUP_SIZE in C code + + it 'does not try to look up the context' do + otel_tracer.in_span("profiler.test") do |_span| + current_size = OpenTelemetry::Context.current.instance_variable_get(:@entries).size + + OpenTelemetry::Context.with_values( + Array.new((max_safe_lookup_size + 1 - current_size)) { |it| ["key_#{it}", it] }.to_h + ) do + sample_allocation(weight: 12) + end + + OpenTelemetry::Context.with_values( + Array.new((max_safe_lookup_size - current_size)) { |it| ["key_#{it}", it] }.to_h + ) do + sample_allocation(weight: 34) + end + end + + result = samples_for_thread(samples, Thread.current) + + expect(result.size).to be 2 + expect(result.find { |it| it.values.fetch(:"alloc-samples") == 12 }.labels.keys) + .to_not include(:"local root span id", :"span id") + expect(result.find { |it| it.values.fetch(:"alloc-samples") == 34 }.labels.keys) + .to include(:"local root span id", :"span id") + end + end + end + context 'when otel_context_enabled is false' do let(:otel_context_enabled) { false } @@ -1433,7 +1519,7 @@ def sample_and_check(expected_state:) context "when called before on_gc_start/on_gc_finish" do it do - expect { sample_after_gc }.to raise_error(RuntimeError, /Unexpected call to sample_after_gc/) + expect { sample_after_gc(allow_exception: true) }.to raise_error(RuntimeError, /Unexpected call to sample_after_gc/) end end @@ -1451,7 +1537,8 @@ def sample_and_check(expected_state:) it do sample_after_gc - expect { sample_after_gc }.to raise_error(RuntimeError, /Unexpected call to sample_after_gc/) + expect { sample_after_gc(allow_exception: true) } + .to raise_error(RuntimeError, /Unexpected call to sample_after_gc/) end end diff --git a/spec/datadog/profiling/http_transport_spec.rb b/spec/datadog/profiling/http_transport_spec.rb index 44423984fab..0cd98ba09e3 100644 --- a/spec/datadog/profiling/http_transport_spec.rb +++ b/spec/datadog/profiling/http_transport_spec.rb @@ -127,6 +127,19 @@ http_transport end end + + context "when hostname is an ipv6 address" do + let(:hostname) { "1234:1234::1" } + + it "provides the correct ipv6 address-safe url to the exporter" do + expect(described_class) + .to receive(:_native_validate_exporter) + .with([:agent, "http://[1234:1234::1]:12345/"]) + .and_return([:ok, nil]) + + http_transport + end + end end context "when additionally site and api_key are provided" do diff --git a/suppressions/ruby-3.4.supp b/suppressions/ruby-3.4.supp index 646151fa9fb..71af0c40baa 100644 --- a/suppressions/ruby-3.4.supp +++ b/suppressions/ruby-3.4.supp @@ -77,3 +77,19 @@ obj:/usr/bin/tr ... } + +# When a Ruby process forks, it looks like Ruby doesn't clean up the memory of old threads? +{ + ruby-native-thread-memory-4 + Memcheck:Leak + fun:calloc + fun:calloc1 + fun:rb_gc_impl_calloc + fun:ruby_xcalloc_body + fun:ruby_xcalloc + fun:native_thread_alloc + fun:native_thread_create_dedicated + fun:native_thread_create + fun:thread_create_core + ... +}