datadog 2.30.0 → 2.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +450 -1
- data/README.md +3 -0
- data/bin/ddprofrb +4 -4
- data/ext/datadog_profiling_native_extension/NativeExtensionDesign.md +12 -24
- data/ext/datadog_profiling_native_extension/clock_id.h +9 -1
- data/ext/datadog_profiling_native_extension/clock_id_from_mach.c +66 -0
- data/ext/datadog_profiling_native_extension/clock_id_from_pthread.c +1 -1
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +368 -151
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +2 -6
- data/ext/datadog_profiling_native_extension/collectors_gc_profiling_helper.c +0 -2
- data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +29 -16
- data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.h +5 -1
- data/ext/datadog_profiling_native_extension/collectors_stack.c +263 -170
- data/ext/datadog_profiling_native_extension/collectors_stack.h +24 -5
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +909 -552
- data/ext/datadog_profiling_native_extension/collectors_thread_context.h +25 -9
- data/ext/datadog_profiling_native_extension/crashtracking_runtime_stacks.c +5 -4
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +44 -19
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +7 -12
- data/ext/datadog_profiling_native_extension/extconf.rb +86 -104
- data/ext/datadog_profiling_native_extension/gvl_profiling_helper.c +4 -43
- data/ext/datadog_profiling_native_extension/gvl_profiling_helper.h +15 -47
- data/ext/datadog_profiling_native_extension/heap_recorder.c +393 -279
- data/ext/datadog_profiling_native_extension/heap_recorder.h +50 -31
- data/ext/datadog_profiling_native_extension/http_transport.c +10 -5
- data/ext/datadog_profiling_native_extension/macos_sampler_thread.h +55 -0
- data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +3 -27
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +847 -510
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +38 -14
- data/ext/datadog_profiling_native_extension/profiling.c +65 -27
- data/ext/datadog_profiling_native_extension/ruby_helpers.c +37 -107
- data/ext/datadog_profiling_native_extension/ruby_helpers.h +4 -7
- data/ext/datadog_profiling_native_extension/stack_recorder.c +130 -93
- data/ext/datadog_profiling_native_extension/stack_recorder.h +12 -4
- data/ext/datadog_profiling_native_extension/time_helpers.c +2 -4
- data/ext/datadog_profiling_native_extension/time_helpers.h +25 -19
- data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.h +4 -2
- data/ext/libdatadog_api/crashtracker.c +7 -8
- data/ext/libdatadog_api/datadog_ruby_common.c +44 -19
- data/ext/libdatadog_api/datadog_ruby_common.h +7 -12
- data/ext/libdatadog_api/di.c +218 -0
- data/ext/libdatadog_api/extconf.rb +40 -26
- data/ext/libdatadog_api/feature_flags.c +34 -0
- data/ext/libdatadog_api/init.c +13 -2
- data/ext/libdatadog_api/otel_thread_context.c +268 -0
- data/ext/libdatadog_api/otel_thread_context.h +5 -0
- data/ext/libdatadog_api/trace_exporter.c +1998 -0
- data/ext/libdatadog_api/trace_exporter.h +5 -0
- data/ext/libdatadog_extconf_helpers.rb +63 -13
- data/lib/datadog/ai_guard/autoload.rb +10 -0
- data/lib/datadog/ai_guard/component.rb +24 -13
- data/lib/datadog/ai_guard/configuration/ext.rb +2 -0
- data/lib/datadog/ai_guard/configuration.rb +119 -2
- data/lib/datadog/ai_guard/contrib/auto_instrument.rb +24 -0
- data/lib/datadog/ai_guard/contrib/rack/integration.rb +42 -0
- data/lib/datadog/ai_guard/contrib/rack/patcher.rb +26 -0
- data/lib/datadog/ai_guard/contrib/rack/request_middleware.rb +97 -0
- data/lib/datadog/ai_guard/contrib/rails/integration.rb +41 -0
- data/lib/datadog/ai_guard/contrib/rails/patcher.rb +97 -0
- data/lib/datadog/ai_guard/contrib/ruby_llm/chat_instrumentation.rb +54 -23
- data/lib/datadog/ai_guard/contrib/ruby_llm/integration.rb +1 -1
- data/lib/datadog/ai_guard/contrib/ruby_llm/message_adapter.rb +76 -0
- data/lib/datadog/ai_guard/contrib/ruby_llm/patcher.rb +1 -0
- data/lib/datadog/ai_guard/contrib/ruby_llm/redaction_change_set.rb +135 -0
- data/lib/datadog/ai_guard/evaluation/client.rb +50 -0
- data/lib/datadog/ai_guard/evaluation/content_part.rb +48 -0
- data/lib/datadog/ai_guard/evaluation/message.rb +25 -7
- data/lib/datadog/ai_guard/evaluation/message_builder.rb +31 -0
- data/lib/datadog/ai_guard/evaluation/no_op_result.rb +8 -6
- data/lib/datadog/ai_guard/evaluation/outcome.rb +24 -0
- data/lib/datadog/ai_guard/evaluation/request.rb +8 -59
- data/lib/datadog/ai_guard/evaluation/response.rb +33 -0
- data/lib/datadog/ai_guard/evaluation/result.rb +11 -16
- data/lib/datadog/ai_guard/evaluation/tool_call.rb +15 -2
- data/lib/datadog/ai_guard/evaluation.rb +75 -17
- data/lib/datadog/ai_guard/ext.rb +16 -0
- data/lib/datadog/ai_guard/{api_client.rb → http_client.rb} +15 -11
- data/lib/datadog/ai_guard/metrics/telemetry.rb +43 -0
- data/lib/datadog/ai_guard/redaction/replacements.rb +97 -0
- data/lib/datadog/ai_guard/redaction/result.rb +29 -0
- data/lib/datadog/ai_guard/redaction.rb +80 -0
- data/lib/datadog/ai_guard.rb +70 -43
- data/lib/datadog/appsec/actions_handler/serializable_backtrace.rb +22 -43
- data/lib/datadog/appsec/actions_handler.rb +6 -6
- data/lib/datadog/appsec/anonymizer.rb +1 -1
- data/lib/datadog/appsec/api_security/endpoint_collection/grape_route_serializer.rb +2 -2
- data/lib/datadog/appsec/api_security/endpoint_collection/rails_collector.rb +6 -6
- data/lib/datadog/appsec/api_security/endpoint_collection/rails_route_serializer.rb +1 -1
- data/lib/datadog/appsec/api_security/endpoint_collection/sinatra_route_serializer.rb +2 -2
- data/lib/datadog/appsec/api_security/route_extractor.rb +26 -14
- data/lib/datadog/appsec/api_security/sampler.rb +5 -5
- data/lib/datadog/appsec/api_security.rb +1 -1
- data/lib/datadog/appsec/assets/blocked.html +1 -108
- data/lib/datadog/appsec/assets.rb +7 -7
- data/lib/datadog/appsec/autoload.rb +4 -4
- data/lib/datadog/appsec/component.rb +29 -22
- data/lib/datadog/appsec/compressed_json.rb +7 -7
- data/lib/datadog/appsec/configuration.rb +436 -1
- data/lib/datadog/appsec/context.rb +10 -8
- data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +6 -6
- data/lib/datadog/appsec/contrib/active_record/integration.rb +4 -4
- data/lib/datadog/appsec/contrib/active_record/patcher.rb +4 -4
- data/lib/datadog/appsec/contrib/aws_lambda/gateway/watcher.rb +75 -0
- data/lib/datadog/appsec/contrib/aws_lambda/integration.rb +39 -0
- data/lib/datadog/appsec/contrib/aws_lambda/patcher.rb +30 -0
- data/lib/datadog/appsec/contrib/aws_lambda/waf_addresses.rb +146 -0
- data/lib/datadog/appsec/contrib/devise/configuration.rb +1 -1
- data/lib/datadog/appsec/contrib/devise/data_extractor.rb +3 -3
- data/lib/datadog/appsec/contrib/devise/ext.rb +20 -20
- data/lib/datadog/appsec/contrib/devise/integration.rb +4 -4
- data/lib/datadog/appsec/contrib/devise/patcher.rb +8 -8
- data/lib/datadog/appsec/contrib/devise/patches/signin_tracking_patch.rb +14 -13
- data/lib/datadog/appsec/contrib/devise/patches/signup_tracking_patch.rb +8 -8
- data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +24 -9
- data/lib/datadog/appsec/contrib/excon/integration.rb +4 -4
- data/lib/datadog/appsec/contrib/excon/patcher.rb +1 -1
- data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +76 -21
- data/lib/datadog/appsec/contrib/faraday/integration.rb +4 -4
- data/lib/datadog/appsec/contrib/faraday/patcher.rb +4 -4
- data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +72 -18
- data/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +4 -4
- data/lib/datadog/appsec/contrib/graphql/gateway/multiplex.rb +66 -21
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +7 -7
- data/lib/datadog/appsec/contrib/graphql/integration.rb +9 -8
- data/lib/datadog/appsec/contrib/graphql/patcher.rb +3 -3
- data/lib/datadog/appsec/contrib/rack/buffered_input.rb +83 -0
- data/lib/datadog/appsec/contrib/rack/ext.rb +29 -29
- data/lib/datadog/appsec/contrib/rack/gateway/request.rb +56 -17
- data/lib/datadog/appsec/contrib/rack/gateway/response.rb +1 -1
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +46 -30
- data/lib/datadog/appsec/contrib/rack/input_peeker.rb +79 -0
- data/lib/datadog/appsec/contrib/rack/integration.rb +6 -6
- data/lib/datadog/appsec/contrib/rack/patcher.rb +3 -3
- data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +11 -8
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +51 -61
- data/lib/datadog/appsec/contrib/rack/response_body.rb +1 -1
- data/lib/datadog/appsec/contrib/rails/gateway/request.rb +43 -4
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +25 -9
- data/lib/datadog/appsec/contrib/rails/integration.rb +5 -5
- data/lib/datadog/appsec/contrib/rails/patcher.rb +17 -17
- data/lib/datadog/appsec/contrib/rails/patches/process_action_patch.rb +2 -2
- data/lib/datadog/appsec/contrib/rails/patches/render_to_body_patch.rb +3 -3
- data/lib/datadog/appsec/contrib/rails/request.rb +3 -3
- data/lib/datadog/appsec/contrib/rails/request_middleware.rb +2 -1
- data/lib/datadog/appsec/contrib/rest_client/integration.rb +5 -5
- data/lib/datadog/appsec/contrib/rest_client/patcher.rb +1 -1
- data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +74 -21
- data/lib/datadog/appsec/contrib/sinatra/gateway/request.rb +1 -1
- data/lib/datadog/appsec/contrib/sinatra/gateway/route_params.rb +1 -1
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +34 -13
- data/lib/datadog/appsec/contrib/sinatra/integration.rb +5 -5
- data/lib/datadog/appsec/contrib/sinatra/patcher.rb +11 -11
- data/lib/datadog/appsec/contrib/sinatra/patches/json_patch.rb +3 -3
- data/lib/datadog/appsec/contrib/sinatra/request_middleware.rb +2 -1
- data/lib/datadog/appsec/counter_sampler.rb +1 -1
- data/lib/datadog/appsec/default_header_tags.rb +52 -0
- data/lib/datadog/appsec/event.rb +14 -14
- data/lib/datadog/appsec/ext.rb +11 -10
- data/lib/datadog/appsec/extensions.rb +2 -2
- data/lib/datadog/appsec/instrumentation/gateway.rb +1 -14
- data/lib/datadog/appsec/metrics/collector.rb +18 -1
- data/lib/datadog/appsec/metrics/exporter.rb +17 -11
- data/lib/datadog/appsec/metrics/telemetry.rb +15 -3
- data/lib/datadog/appsec/metrics/telemetry_exporter.rb +4 -4
- data/lib/datadog/appsec/metrics.rb +4 -4
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +18 -12
- data/lib/datadog/appsec/monitor.rb +1 -1
- data/lib/datadog/appsec/processor/rule_loader.rb +32 -32
- data/lib/datadog/appsec/rate_limiter.rb +1 -1
- data/lib/datadog/appsec/remote.rb +15 -9
- data/lib/datadog/appsec/response.rb +22 -22
- data/lib/datadog/appsec/route_normalizer/rails_route_pattern.rb +176 -0
- data/lib/datadog/appsec/route_normalizer/route_pattern.rb +378 -0
- data/lib/datadog/appsec/route_normalizer/route_text.rb +57 -0
- data/lib/datadog/appsec/route_normalizer.rb +80 -0
- data/lib/datadog/appsec/security_engine/engine.rb +40 -40
- data/lib/datadog/appsec/security_engine/runner.rb +3 -3
- data/lib/datadog/appsec/security_event.rb +2 -2
- data/lib/datadog/appsec/trace_keeper.rb +18 -6
- data/lib/datadog/appsec/utils/http/body.rb +11 -8
- data/lib/datadog/appsec/utils/http/body_reader.rb +61 -0
- data/lib/datadog/appsec/utils/http/media_range.rb +15 -15
- data/lib/datadog/appsec/utils/http/media_type.rb +5 -6
- data/lib/datadog/appsec/utils/http/url_encoded.rb +79 -24
- data/lib/datadog/appsec.rb +21 -24
- data/lib/datadog/auto_instrument.rb +2 -2
- data/lib/datadog/core/buffer/cruby.rb +1 -1
- data/lib/datadog/core/buffer/thread_safe.rb +1 -1
- data/lib/datadog/core/configuration/agent_settings.rb +1 -1
- data/lib/datadog/core/configuration/agent_settings_resolver.rb +15 -15
- data/lib/datadog/core/configuration/agentless_settings_resolver.rb +2 -2
- data/lib/datadog/core/configuration/base.rb +19 -7
- data/lib/datadog/core/configuration/components.rb +151 -37
- data/lib/datadog/core/configuration/components_state.rb +6 -1
- data/lib/datadog/core/configuration/config_helper.rb +12 -3
- data/lib/datadog/core/configuration/deprecations.rb +6 -6
- data/lib/datadog/core/configuration/ext.rb +11 -11
- data/lib/datadog/core/configuration/option.rb +46 -21
- data/lib/datadog/core/configuration/option_definition.rb +43 -17
- data/lib/datadog/core/configuration/options.rb +42 -8
- data/lib/datadog/core/configuration/settings.rb +133 -105
- data/lib/datadog/core/configuration/stable_config.rb +1 -1
- data/lib/datadog/core/configuration/supported_configurations.rb +33 -1
- data/lib/datadog/core/configuration.rb +9 -9
- data/lib/datadog/core/contrib/rails/railtie.rb +32 -0
- data/lib/datadog/core/contrib/rails/utils.rb +7 -3
- data/lib/datadog/core/crashtracking/component.rb +17 -13
- data/lib/datadog/core/crashtracking/tag_builder.rb +5 -5
- data/lib/datadog/core/deprecations.rb +1 -1
- data/lib/datadog/core/diagnostics/environment_logger.rb +45 -8
- data/lib/datadog/core/diagnostics/health.rb +2 -2
- data/lib/datadog/core/encoding.rb +4 -4
- data/lib/datadog/core/environment/agent_info.rb +2 -2
- data/lib/datadog/core/environment/cgroup.rb +4 -4
- data/lib/datadog/core/environment/container.rb +11 -11
- data/lib/datadog/core/environment/execution.rb +3 -3
- data/lib/datadog/core/environment/ext.rb +21 -15
- data/lib/datadog/core/environment/gc.rb +1 -1
- data/lib/datadog/core/environment/git.rb +2 -2
- data/lib/datadog/core/environment/identity.rb +47 -11
- data/lib/datadog/core/environment/platform.rb +8 -8
- data/lib/datadog/core/environment/process.rb +54 -19
- data/lib/datadog/core/environment/socket.rb +15 -2
- data/lib/datadog/core/environment/variable_helpers.rb +1 -1
- data/lib/datadog/core/environment/vm_cache.rb +1 -1
- data/lib/datadog/core/environment/yjit.rb +2 -2
- data/lib/datadog/core/error.rb +5 -5
- data/lib/datadog/core/evp.rb +11 -0
- data/lib/datadog/core/extensions.rb +1 -1
- data/lib/datadog/core/feature_flags.rb +3 -3
- data/lib/datadog/core/git/ext.rb +4 -4
- data/lib/datadog/core/knuth_sampler.rb +3 -1
- data/lib/datadog/core/logger.rb +3 -3
- data/lib/datadog/core/logging/ext.rb +1 -1
- data/lib/datadog/core/metrics/client.rb +26 -26
- data/lib/datadog/core/metrics/ext.rb +5 -5
- data/lib/datadog/core/metrics/helpers.rb +1 -1
- data/lib/datadog/core/metrics/logging.rb +2 -2
- data/lib/datadog/core/metrics/options.rb +5 -5
- data/lib/datadog/core/pin.rb +1 -1
- data/lib/datadog/core/process_discovery.rb +8 -8
- data/lib/datadog/core/rate_limiter.rb +1 -1
- data/lib/datadog/core/remote/client/capabilities.rb +77 -19
- data/lib/datadog/core/remote/client.rb +18 -18
- data/lib/datadog/core/remote/component.rb +66 -34
- data/lib/datadog/core/remote/configuration/content.rb +3 -3
- data/lib/datadog/core/remote/configuration/digest.rb +1 -1
- data/lib/datadog/core/remote/configuration/path.rb +9 -9
- data/lib/datadog/core/remote/configuration/repository.rb +4 -4
- data/lib/datadog/core/remote/configuration/target.rb +9 -9
- data/lib/datadog/core/remote/configuration.rb +4 -4
- data/lib/datadog/core/remote/ext.rb +3 -3
- data/lib/datadog/core/remote/negotiation.rb +1 -1
- data/lib/datadog/core/remote/tie/tracing.rb +7 -7
- data/lib/datadog/core/remote/transport/config.rb +4 -4
- data/lib/datadog/core/remote/transport/http/config.rb +10 -10
- data/lib/datadog/core/remote/transport/http/negotiation.rb +4 -4
- data/lib/datadog/core/remote/transport/http.rb +10 -10
- data/lib/datadog/core/remote/transport/negotiation.rb +3 -3
- data/lib/datadog/core/remote/worker.rb +13 -5
- data/lib/datadog/core/runtime/ext.rb +22 -22
- data/lib/datadog/core/runtime/metrics.rb +10 -10
- data/lib/datadog/core/tag_builder.rb +18 -18
- data/lib/datadog/core/tag_normalizer.rb +7 -7
- data/lib/datadog/core/telemetry/component.rb +16 -13
- data/lib/datadog/core/telemetry/configuration_value.rb +38 -0
- data/lib/datadog/core/telemetry/emitter.rb +5 -5
- data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +10 -9
- data/lib/datadog/core/telemetry/event/app_closing.rb +2 -2
- data/lib/datadog/core/telemetry/event/app_dependencies_loaded.rb +2 -2
- data/lib/datadog/core/telemetry/event/app_endpoints_loaded.rb +3 -3
- data/lib/datadog/core/telemetry/event/app_extended_heartbeat.rb +32 -0
- data/lib/datadog/core/telemetry/event/app_heartbeat.rb +2 -2
- data/lib/datadog/core/telemetry/event/app_integrations_change.rb +2 -2
- data/lib/datadog/core/telemetry/event/app_started.rb +142 -193
- data/lib/datadog/core/telemetry/event/base.rb +1 -1
- data/lib/datadog/core/telemetry/event/distributions.rb +2 -2
- data/lib/datadog/core/telemetry/event/generate_metrics.rb +3 -3
- data/lib/datadog/core/telemetry/event/log.rb +6 -6
- data/lib/datadog/core/telemetry/event/message_batch.rb +1 -1
- data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +3 -3
- data/lib/datadog/core/telemetry/event.rb +16 -22
- data/lib/datadog/core/telemetry/ext.rb +11 -10
- data/lib/datadog/core/telemetry/logger.rb +1 -1
- data/lib/datadog/core/telemetry/logging.rb +5 -5
- data/lib/datadog/core/telemetry/metric.rb +9 -9
- data/lib/datadog/core/telemetry/metrics_collection.rb +2 -2
- data/lib/datadog/core/telemetry/metrics_manager.rb +1 -1
- data/lib/datadog/core/telemetry/request.rb +6 -8
- data/lib/datadog/core/telemetry/transport/http/telemetry.rb +16 -11
- data/lib/datadog/core/telemetry/transport/http.rb +7 -7
- data/lib/datadog/core/telemetry/transport/telemetry.rb +3 -3
- data/lib/datadog/core/telemetry/worker.rb +26 -6
- data/lib/datadog/core/transport/ext.rb +14 -14
- data/lib/datadog/core/transport/http/adapters/net.rb +4 -4
- data/lib/datadog/core/transport/http/adapters/test.rb +1 -1
- data/lib/datadog/core/transport/http/adapters/unix_socket.rb +4 -4
- data/lib/datadog/core/transport/http/api/endpoint.rb +1 -1
- data/lib/datadog/core/transport/http/api/map.rb +1 -1
- data/lib/datadog/core/transport/http/builder.rb +6 -6
- data/lib/datadog/core/transport/http/client.rb +2 -2
- data/lib/datadog/core/transport/http/response.rb +1 -1
- data/lib/datadog/core/transport/http.rb +9 -7
- data/lib/datadog/core/transport/response.rb +1 -1
- data/lib/datadog/core/transport/transport.rb +2 -2
- data/lib/datadog/core/utils/at_fork_monkey_patch.rb +172 -20
- data/lib/datadog/core/utils/base64_codec.rb +23 -0
- data/lib/datadog/core/utils/duration.rb +1 -1
- data/lib/datadog/core/utils/{array.rb → enumerable_compat.rb} +2 -2
- data/lib/datadog/core/utils/forking.rb +3 -1
- data/lib/datadog/core/utils/hash.rb +0 -23
- data/lib/datadog/core/utils/lru_cache.rb +3 -3
- data/lib/datadog/core/utils/network.rb +11 -11
- data/lib/datadog/core/utils/only_once.rb +1 -1
- data/lib/datadog/core/utils/only_once_successful.rb +1 -1
- data/lib/datadog/core/utils/safe_dup.rb +2 -1
- data/lib/datadog/core/utils/sequence.rb +3 -6
- data/lib/datadog/core/utils/spawn_monkey_patch.rb +68 -0
- data/lib/datadog/core/utils/time.rb +18 -52
- data/lib/datadog/core/utils/url.rb +1 -1
- data/lib/datadog/core/utils.rb +5 -5
- data/lib/datadog/core/workers/async.rb +2 -2
- data/lib/datadog/core/workers/polling.rb +2 -2
- data/lib/datadog/core/workers/runtime_metrics.rb +4 -4
- data/lib/datadog/core.rb +7 -5
- data/lib/datadog/data_streams/configuration.rb +40 -1
- data/lib/datadog/data_streams/ext.rb +1 -1
- data/lib/datadog/data_streams/extensions.rb +2 -2
- data/lib/datadog/data_streams/pathway_context.rb +28 -30
- data/lib/datadog/data_streams/processor.rb +93 -62
- data/lib/datadog/data_streams/transport/http/stats.rb +5 -5
- data/lib/datadog/data_streams/transport/http.rb +5 -5
- data/lib/datadog/data_streams/transport/stats.rb +7 -7
- data/lib/datadog/data_streams.rb +5 -5
- data/lib/datadog/di/base.rb +16 -8
- data/lib/datadog/di/boot.rb +25 -24
- data/lib/datadog/di/capture_expression.rb +21 -0
- data/lib/datadog/di/capture_expression_evaluator.rb +71 -0
- data/lib/datadog/di/capture_limits.rb +41 -0
- data/lib/datadog/di/code_tracker.rb +218 -16
- data/lib/datadog/di/component.rb +123 -37
- data/lib/datadog/di/configuration.rb +241 -2
- data/lib/datadog/di/context.rb +9 -3
- data/lib/datadog/di/contrib/active_record.rb +6 -2
- data/lib/datadog/di/contrib/railtie.rb +1 -1
- data/lib/datadog/di/contrib.rb +5 -5
- data/lib/datadog/di/el/compiler.rb +114 -38
- data/lib/datadog/di/el/evaluator.rb +82 -2
- data/lib/datadog/di/el/expression.rb +13 -2
- data/lib/datadog/di/el.rb +3 -3
- data/lib/datadog/di/error.rb +10 -0
- data/lib/datadog/di/fatal_exceptions.rb +26 -0
- data/lib/datadog/di/instrumenter.rb +528 -184
- data/lib/datadog/di/logger.rb +3 -3
- data/lib/datadog/di/preload.rb +1 -1
- data/lib/datadog/di/probe.rb +69 -2
- data/lib/datadog/di/probe_builder.rb +98 -15
- data/lib/datadog/di/probe_file_loader/railtie.rb +1 -1
- data/lib/datadog/di/probe_file_loader.rb +14 -9
- data/lib/datadog/di/probe_manager.rb +83 -20
- data/lib/datadog/di/probe_notification_builder.rb +178 -25
- data/lib/datadog/di/probe_notifier_worker.rb +57 -37
- data/lib/datadog/di/probe_repository.rb +1 -1
- data/lib/datadog/di/proc_responder.rb +1 -1
- data/lib/datadog/di/redactor.rb +16 -1
- data/lib/datadog/di/remote.rb +187 -26
- data/lib/datadog/di/serializer.rb +79 -35
- data/lib/datadog/di/transport/diagnostics.rb +5 -5
- data/lib/datadog/di/transport/http/diagnostics.rb +3 -3
- data/lib/datadog/di/transport/http/input.rb +2 -2
- data/lib/datadog/di/transport/http.rb +10 -10
- data/lib/datadog/di/transport/input.rb +18 -14
- data/lib/datadog/di/utils.rb +43 -15
- data/lib/datadog/di.rb +147 -3
- data/lib/datadog/error_tracking/collector.rb +3 -2
- data/lib/datadog/error_tracking/component.rb +12 -12
- data/lib/datadog/error_tracking/configuration.rb +55 -2
- data/lib/datadog/error_tracking/ext.rb +7 -7
- data/lib/datadog/error_tracking/extensions.rb +2 -2
- data/lib/datadog/error_tracking/filters.rb +4 -4
- data/lib/datadog/error_tracking.rb +6 -6
- data/lib/datadog/kit/appsec/events/v2.rb +91 -33
- data/lib/datadog/kit/appsec/events.rb +25 -25
- data/lib/datadog/kit/enable_core_dumps.rb +3 -3
- data/lib/datadog/kit/identity.rb +18 -18
- data/lib/datadog/kit/tracing/method_tracer.rb +9 -6
- data/lib/datadog/kit.rb +1 -1
- data/lib/datadog/open_feature/agentless/configuration_source.rb +246 -0
- data/lib/datadog/open_feature/agentless/parser.rb +43 -0
- data/lib/datadog/open_feature/agentless/response.rb +19 -0
- data/lib/datadog/open_feature/agentless/transport.rb +103 -0
- data/lib/datadog/open_feature/component.rb +118 -13
- data/lib/datadog/open_feature/configuration/agentless_endpoint.rb +90 -0
- data/lib/datadog/open_feature/configuration/source/resolution.rb +22 -0
- data/lib/datadog/open_feature/configuration/source.rb +43 -0
- data/lib/datadog/open_feature/configuration.rb +140 -1
- data/lib/datadog/open_feature/evaluation_engine.rb +38 -12
- data/lib/datadog/open_feature/exposures/batch_builder.rb +1 -1
- data/lib/datadog/open_feature/exposures/buffer.rb +1 -1
- data/lib/datadog/open_feature/exposures/deduplicator.rb +1 -1
- data/lib/datadog/open_feature/exposures/event.rb +17 -10
- data/lib/datadog/open_feature/exposures/reporter.rb +3 -3
- data/lib/datadog/open_feature/exposures/worker.rb +6 -6
- data/lib/datadog/open_feature/ext.rb +32 -6
- data/lib/datadog/open_feature/flag_evaluation/aggregator.rb +442 -0
- data/lib/datadog/open_feature/flag_evaluation/writer.rb +544 -0
- data/lib/datadog/open_feature/hooks/flag_eval_evp_hook.rb +105 -0
- data/lib/datadog/open_feature/hooks/flag_eval_metrics_hook.rb +51 -0
- data/lib/datadog/open_feature/hooks/span_enrichment_hook/codec.rb +58 -0
- data/lib/datadog/open_feature/hooks/span_enrichment_hook/span_enrichment_state.rb +96 -0
- data/lib/datadog/open_feature/hooks/span_enrichment_hook/span_enrichment_state_store.rb +49 -0
- data/lib/datadog/open_feature/hooks/span_enrichment_hook.rb +184 -0
- data/lib/datadog/open_feature/metrics/flag_eval_metrics.rb +149 -0
- data/lib/datadog/open_feature/native_evaluator.rb +43 -7
- data/lib/datadog/open_feature/noop_evaluator.rb +8 -3
- data/lib/datadog/open_feature/provider.rb +115 -21
- data/lib/datadog/open_feature/remote.rb +8 -8
- data/lib/datadog/open_feature/resolution_details.rb +4 -2
- data/lib/datadog/open_feature/transport.rb +71 -12
- data/lib/datadog/open_feature.rb +2 -2
- data/lib/datadog/opentelemetry/api/baggage.rb +3 -3
- data/lib/datadog/opentelemetry/api/context.rb +4 -4
- data/lib/datadog/opentelemetry/configuration/settings.rb +95 -28
- data/lib/datadog/opentelemetry/ext.rb +9 -0
- data/lib/datadog/opentelemetry/logs.rb +98 -0
- data/lib/datadog/opentelemetry/metrics.rb +17 -44
- data/lib/datadog/opentelemetry/sdk/configurator.rb +46 -6
- data/lib/datadog/opentelemetry/sdk/id_generator.rb +16 -10
- data/lib/datadog/opentelemetry/sdk/logs_exporter.rb +30 -0
- data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +9 -16
- data/lib/datadog/opentelemetry/sdk/propagator.rb +17 -11
- data/lib/datadog/opentelemetry/sdk/span_processor.rb +18 -15
- data/lib/datadog/opentelemetry/sdk/trace/span.rb +32 -32
- data/lib/datadog/opentelemetry/sdk.rb +19 -0
- data/lib/datadog/opentelemetry/signal_configuration.rb +57 -0
- data/lib/datadog/opentelemetry/trace.rb +4 -1
- data/lib/datadog/opentelemetry.rb +8 -7
- data/lib/datadog/profiling/collectors/code_provenance.rb +36 -11
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +45 -3
- data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +10 -4
- data/lib/datadog/profiling/collectors/info.rb +19 -10
- data/lib/datadog/profiling/collectors/thread_context.rb +16 -22
- data/lib/datadog/profiling/component.rb +43 -37
- data/lib/datadog/profiling/exporter.rb +43 -16
- data/lib/datadog/profiling/ext/dir_monkey_patches.rb +6 -5
- data/lib/datadog/profiling/ext.rb +0 -2
- data/lib/datadog/profiling/flush.rb +21 -12
- data/lib/datadog/profiling/http_transport.rb +13 -2
- data/lib/datadog/profiling/load_native_extension.rb +2 -2
- data/lib/datadog/profiling/profiler.rb +13 -5
- data/lib/datadog/profiling/scheduler.rb +2 -2
- data/lib/datadog/profiling/sequence_tracker.rb +1 -1
- data/lib/datadog/profiling/stack_recorder.rb +0 -8
- data/lib/datadog/profiling/tag_builder.rb +19 -19
- data/lib/datadog/profiling/tasks/exec.rb +9 -4
- data/lib/datadog/profiling/tasks/help.rb +1 -0
- data/lib/datadog/profiling/tasks/setup.rb +2 -2
- data/lib/datadog/profiling.rb +32 -29
- data/lib/datadog/ruby_version.rb +25 -0
- data/lib/datadog/single_step_instrument.rb +2 -2
- data/lib/datadog/symbol_database/component.rb +734 -0
- data/lib/datadog/symbol_database/configuration.rb +73 -0
- data/lib/datadog/symbol_database/extensions.rb +19 -0
- data/lib/datadog/symbol_database/extractor.rb +1092 -0
- data/lib/datadog/symbol_database/file_hash.rb +48 -0
- data/lib/datadog/symbol_database/logger.rb +43 -0
- data/lib/datadog/symbol_database/remote.rb +195 -0
- data/lib/datadog/symbol_database/scope.rb +102 -0
- data/lib/datadog/symbol_database/scope_batcher.rb +292 -0
- data/lib/datadog/symbol_database/service_version.rb +66 -0
- data/lib/datadog/symbol_database/symbol.rb +69 -0
- data/lib/datadog/symbol_database/transport/http/endpoint.rb +28 -0
- data/lib/datadog/symbol_database/transport/http.rb +45 -0
- data/lib/datadog/symbol_database/transport.rb +54 -0
- data/lib/datadog/symbol_database/uploader.rb +230 -0
- data/lib/datadog/symbol_database.rb +71 -0
- data/lib/datadog/tracing/analytics.rb +1 -1
- data/lib/datadog/tracing/buffer.rb +8 -8
- data/lib/datadog/tracing/client_ip.rb +4 -4
- data/lib/datadog/tracing/component.rb +41 -7
- data/lib/datadog/tracing/configuration/dynamic/option.rb +4 -0
- data/lib/datadog/tracing/configuration/dynamic.rb +13 -11
- data/lib/datadog/tracing/configuration/ext.rb +53 -38
- data/lib/datadog/tracing/configuration/http.rb +2 -2
- data/lib/datadog/tracing/configuration/settings.rb +58 -17
- data/lib/datadog/tracing/context.rb +25 -3
- data/lib/datadog/tracing/context_provider.rb +11 -7
- data/lib/datadog/tracing/contrib/action_cable/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/action_cable/event.rb +4 -4
- data/lib/datadog/tracing/contrib/action_cable/events/broadcast.rb +9 -6
- data/lib/datadog/tracing/contrib/action_cable/events/perform_action.rb +8 -5
- data/lib/datadog/tracing/contrib/action_cable/events/transmit.rb +9 -6
- data/lib/datadog/tracing/contrib/action_cable/events.rb +5 -5
- data/lib/datadog/tracing/contrib/action_cable/ext.rb +18 -18
- data/lib/datadog/tracing/contrib/action_cable/instrumentation.rb +8 -5
- data/lib/datadog/tracing/contrib/action_cable/integration.rb +7 -7
- data/lib/datadog/tracing/contrib/action_cable/patcher.rb +4 -4
- data/lib/datadog/tracing/contrib/action_mailer/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/action_mailer/event.rb +7 -4
- data/lib/datadog/tracing/contrib/action_mailer/events/deliver.rb +8 -8
- data/lib/datadog/tracing/contrib/action_mailer/events/process.rb +4 -4
- data/lib/datadog/tracing/contrib/action_mailer/events.rb +3 -3
- data/lib/datadog/tracing/contrib/action_mailer/ext.rb +18 -18
- data/lib/datadog/tracing/contrib/action_mailer/integration.rb +7 -7
- data/lib/datadog/tracing/contrib/action_mailer/patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +15 -12
- data/lib/datadog/tracing/contrib/action_pack/action_controller/patcher.rb +2 -2
- data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +31 -3
- data/lib/datadog/tracing/contrib/action_pack/action_dispatch/patcher.rb +5 -3
- data/lib/datadog/tracing/contrib/action_pack/configuration/settings.rb +3 -3
- data/lib/datadog/tracing/contrib/action_pack/ext.rb +10 -10
- data/lib/datadog/tracing/contrib/action_pack/integration.rb +7 -7
- data/lib/datadog/tracing/contrib/action_pack/patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/action_pack/utils.rb +1 -1
- data/lib/datadog/tracing/contrib/action_view/configuration/settings.rb +3 -3
- data/lib/datadog/tracing/contrib/action_view/event.rb +1 -1
- data/lib/datadog/tracing/contrib/action_view/events/render_partial.rb +10 -7
- data/lib/datadog/tracing/contrib/action_view/events/render_template.rb +11 -8
- data/lib/datadog/tracing/contrib/action_view/events.rb +3 -3
- data/lib/datadog/tracing/contrib/action_view/ext.rb +10 -10
- data/lib/datadog/tracing/contrib/action_view/integration.rb +11 -11
- data/lib/datadog/tracing/contrib/action_view/patcher.rb +5 -5
- data/lib/datadog/tracing/contrib/action_view/utils.rb +2 -2
- data/lib/datadog/tracing/contrib/active_job/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/active_job/data_streams.rb +62 -0
- data/lib/datadog/tracing/contrib/active_job/event.rb +3 -3
- data/lib/datadog/tracing/contrib/active_job/events/discard.rb +10 -7
- data/lib/datadog/tracing/contrib/active_job/events/enqueue.rb +10 -7
- data/lib/datadog/tracing/contrib/active_job/events/enqueue_at.rb +10 -7
- data/lib/datadog/tracing/contrib/active_job/events/enqueue_retry.rb +10 -7
- data/lib/datadog/tracing/contrib/active_job/events/perform.rb +10 -7
- data/lib/datadog/tracing/contrib/active_job/events/retry_stopped.rb +10 -7
- data/lib/datadog/tracing/contrib/active_job/events.rb +6 -6
- data/lib/datadog/tracing/contrib/active_job/ext.rb +23 -23
- data/lib/datadog/tracing/contrib/active_job/integration.rb +7 -7
- data/lib/datadog/tracing/contrib/active_job/patcher.rb +17 -5
- data/lib/datadog/tracing/contrib/active_model_serializers/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/active_model_serializers/event.rb +4 -4
- data/lib/datadog/tracing/contrib/active_model_serializers/events/render.rb +7 -7
- data/lib/datadog/tracing/contrib/active_model_serializers/events/serialize.rb +8 -9
- data/lib/datadog/tracing/contrib/active_model_serializers/events.rb +3 -3
- data/lib/datadog/tracing/contrib/active_model_serializers/ext.rb +10 -10
- data/lib/datadog/tracing/contrib/active_model_serializers/integration.rb +5 -5
- data/lib/datadog/tracing/contrib/active_model_serializers/patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/active_record/configuration/makara_resolver.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +9 -9
- data/lib/datadog/tracing/contrib/active_record/configuration/settings.rb +4 -4
- data/lib/datadog/tracing/contrib/active_record/event.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +9 -9
- data/lib/datadog/tracing/contrib/active_record/events/sql.rb +12 -14
- data/lib/datadog/tracing/contrib/active_record/events.rb +3 -3
- data/lib/datadog/tracing/contrib/active_record/ext.rb +15 -15
- data/lib/datadog/tracing/contrib/active_record/integration.rb +11 -11
- data/lib/datadog/tracing/contrib/active_record/patcher.rb +2 -2
- data/lib/datadog/tracing/contrib/active_record/utils.rb +4 -4
- data/lib/datadog/tracing/contrib/active_support/cache/event.rb +1 -1
- data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +14 -17
- data/lib/datadog/tracing/contrib/active_support/cache/events.rb +1 -1
- data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +5 -8
- data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +5 -5
- data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +4 -4
- data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +3 -3
- data/lib/datadog/tracing/contrib/active_support/ext.rb +16 -16
- data/lib/datadog/tracing/contrib/active_support/integration.rb +8 -8
- data/lib/datadog/tracing/contrib/active_support/notifications/event.rb +1 -1
- data/lib/datadog/tracing/contrib/active_support/notifications/subscriber.rb +2 -2
- data/lib/datadog/tracing/contrib/active_support/notifications/subscription.rb +3 -3
- data/lib/datadog/tracing/contrib/active_support/patcher.rb +2 -2
- data/lib/datadog/tracing/contrib/analytics.rb +1 -1
- data/lib/datadog/tracing/contrib/auto_instrument.rb +4 -4
- data/lib/datadog/tracing/contrib/aws/configuration/settings.rb +3 -3
- data/lib/datadog/tracing/contrib/aws/ext.rb +26 -26
- data/lib/datadog/tracing/contrib/aws/instrumentation.rb +7 -11
- data/lib/datadog/tracing/contrib/aws/integration.rb +9 -9
- data/lib/datadog/tracing/contrib/aws/parsed_context.rb +1 -1
- data/lib/datadog/tracing/contrib/aws/patcher.rb +5 -5
- data/lib/datadog/tracing/contrib/aws/service/dynamodb.rb +2 -2
- data/lib/datadog/tracing/contrib/aws/service/eventbridge.rb +2 -2
- data/lib/datadog/tracing/contrib/aws/service/kinesis.rb +4 -4
- data/lib/datadog/tracing/contrib/aws/service/s3.rb +2 -2
- data/lib/datadog/tracing/contrib/aws/service/sns.rb +3 -3
- data/lib/datadog/tracing/contrib/aws/service/sqs.rb +3 -3
- data/lib/datadog/tracing/contrib/aws/service/states.rb +5 -5
- data/lib/datadog/tracing/contrib/aws/services.rb +14 -14
- data/lib/datadog/tracing/contrib/component.rb +1 -1
- data/lib/datadog/tracing/contrib/concurrent_ruby/async_patch.rb +1 -1
- data/lib/datadog/tracing/contrib/concurrent_ruby/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/concurrent_ruby/context_composite_executor_service.rb +1 -1
- data/lib/datadog/tracing/contrib/concurrent_ruby/ext.rb +2 -2
- data/lib/datadog/tracing/contrib/concurrent_ruby/future_patch.rb +1 -1
- data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +6 -6
- data/lib/datadog/tracing/contrib/concurrent_ruby/patcher.rb +4 -4
- data/lib/datadog/tracing/contrib/concurrent_ruby/promises_future_patch.rb +1 -1
- data/lib/datadog/tracing/contrib/configurable.rb +20 -5
- data/lib/datadog/tracing/contrib/configuration/resolver.rb +14 -4
- data/lib/datadog/tracing/contrib/configuration/resolvers/pattern_resolver.rb +1 -1
- data/lib/datadog/tracing/contrib/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/dalli/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/dalli/ext.rb +13 -13
- data/lib/datadog/tracing/contrib/dalli/instrumentation.rb +6 -10
- data/lib/datadog/tracing/contrib/dalli/integration.rb +7 -7
- data/lib/datadog/tracing/contrib/dalli/patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/dalli/quantize.rb +3 -3
- data/lib/datadog/tracing/contrib/delayed_job/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/delayed_job/ext.rb +14 -14
- data/lib/datadog/tracing/contrib/delayed_job/integration.rb +5 -5
- data/lib/datadog/tracing/contrib/delayed_job/patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/delayed_job/plugin.rb +7 -5
- data/lib/datadog/tracing/contrib/delayed_job/server_internal_tracer/worker.rb +1 -0
- data/lib/datadog/tracing/contrib/elasticsearch/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/elasticsearch/ext.rb +15 -15
- data/lib/datadog/tracing/contrib/elasticsearch/integration.rb +6 -6
- data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +12 -16
- data/lib/datadog/tracing/contrib/elasticsearch/quantize.rb +4 -4
- data/lib/datadog/tracing/contrib/ethon/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +9 -13
- data/lib/datadog/tracing/contrib/ethon/ext.rb +13 -13
- data/lib/datadog/tracing/contrib/ethon/integration.rb +6 -6
- data/lib/datadog/tracing/contrib/ethon/multi_patch.rb +4 -11
- data/lib/datadog/tracing/contrib/ethon/patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/excon/configuration/settings.rb +5 -5
- data/lib/datadog/tracing/contrib/excon/ext.rb +11 -11
- data/lib/datadog/tracing/contrib/excon/integration.rb +6 -6
- data/lib/datadog/tracing/contrib/excon/middleware.rb +10 -14
- data/lib/datadog/tracing/contrib/excon/patcher.rb +2 -2
- data/lib/datadog/tracing/contrib/ext.rb +20 -18
- data/lib/datadog/tracing/contrib/extensions.rb +11 -2
- data/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +4 -4
- data/lib/datadog/tracing/contrib/faraday/ext.rb +11 -11
- data/lib/datadog/tracing/contrib/faraday/integration.rb +6 -6
- data/lib/datadog/tracing/contrib/faraday/middleware.rb +10 -14
- data/lib/datadog/tracing/contrib/faraday/patcher.rb +6 -6
- data/lib/datadog/tracing/contrib/grape/configuration/settings.rb +4 -4
- data/lib/datadog/tracing/contrib/grape/endpoint.rb +59 -29
- data/lib/datadog/tracing/contrib/grape/ext.rb +15 -15
- data/lib/datadog/tracing/contrib/grape/instrumentation.rb +3 -3
- data/lib/datadog/tracing/contrib/grape/integration.rb +5 -5
- data/lib/datadog/tracing/contrib/grape/patcher.rb +5 -5
- data/lib/datadog/tracing/contrib/graphql/configuration/error_extension_env_parser.rb +1 -1
- data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +3 -3
- data/lib/datadog/tracing/contrib/graphql/ext.rb +9 -9
- data/lib/datadog/tracing/contrib/graphql/integration.rb +9 -9
- data/lib/datadog/tracing/contrib/graphql/patcher.rb +7 -7
- data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +38 -37
- data/lib/datadog/tracing/contrib/graphql/unified_trace_patcher.rb +2 -2
- data/lib/datadog/tracing/contrib/grpc/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +11 -15
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +11 -15
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor.rb +6 -6
- data/lib/datadog/tracing/contrib/grpc/distributed/fetcher.rb +1 -1
- data/lib/datadog/tracing/contrib/grpc/distributed/propagation.rb +11 -9
- data/lib/datadog/tracing/contrib/grpc/ext.rb +14 -14
- data/lib/datadog/tracing/contrib/grpc/formatting.rb +7 -7
- data/lib/datadog/tracing/contrib/grpc/integration.rb +5 -5
- data/lib/datadog/tracing/contrib/grpc/intercept_with_datadog.rb +1 -1
- data/lib/datadog/tracing/contrib/grpc/patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/grpc.rb +7 -6
- data/lib/datadog/tracing/contrib/hanami/action_tracer.rb +4 -3
- data/lib/datadog/tracing/contrib/hanami/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/hanami/ext.rb +8 -8
- data/lib/datadog/tracing/contrib/hanami/integration.rb +6 -6
- data/lib/datadog/tracing/contrib/hanami/patcher.rb +5 -5
- data/lib/datadog/tracing/contrib/hanami/renderer_policy_tracing.rb +4 -3
- data/lib/datadog/tracing/contrib/hanami/router_tracing.rb +6 -4
- data/lib/datadog/tracing/contrib/http/circuit_breaker.rb +1 -1
- data/lib/datadog/tracing/contrib/http/configuration/settings.rb +4 -4
- data/lib/datadog/tracing/contrib/http/distributed/fetcher.rb +3 -3
- data/lib/datadog/tracing/contrib/http/distributed/propagation.rb +10 -8
- data/lib/datadog/tracing/contrib/http/ext.rb +11 -11
- data/lib/datadog/tracing/contrib/http/instrumentation.rb +10 -14
- data/lib/datadog/tracing/contrib/http/integration.rb +7 -7
- data/lib/datadog/tracing/contrib/http/patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/http.rb +7 -6
- data/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb +4 -4
- data/lib/datadog/tracing/contrib/httpclient/ext.rb +11 -11
- data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +12 -12
- data/lib/datadog/tracing/contrib/httpclient/integration.rb +6 -6
- data/lib/datadog/tracing/contrib/httpclient/patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/httprb/configuration/settings.rb +4 -4
- data/lib/datadog/tracing/contrib/httprb/ext.rb +11 -11
- data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +10 -14
- data/lib/datadog/tracing/contrib/httprb/integration.rb +7 -7
- data/lib/datadog/tracing/contrib/httprb/patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/integration.rb +3 -3
- data/lib/datadog/tracing/contrib/kafka/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/kafka/event.rb +4 -3
- data/lib/datadog/tracing/contrib/kafka/events/connection/request.rb +7 -3
- data/lib/datadog/tracing/contrib/kafka/events/consumer/process_batch.rb +4 -4
- data/lib/datadog/tracing/contrib/kafka/events/consumer/process_message.rb +4 -4
- data/lib/datadog/tracing/contrib/kafka/events/consumer_group/heartbeat.rb +5 -5
- data/lib/datadog/tracing/contrib/kafka/events/consumer_group/join_group.rb +5 -5
- data/lib/datadog/tracing/contrib/kafka/events/consumer_group/leave_group.rb +5 -5
- data/lib/datadog/tracing/contrib/kafka/events/consumer_group/sync_group.rb +5 -5
- data/lib/datadog/tracing/contrib/kafka/events/produce_operation/send_messages.rb +10 -5
- data/lib/datadog/tracing/contrib/kafka/events/producer/deliver_messages.rb +10 -5
- data/lib/datadog/tracing/contrib/kafka/events.rb +10 -10
- data/lib/datadog/tracing/contrib/kafka/ext.rb +40 -40
- data/lib/datadog/tracing/contrib/kafka/instrumentation/consumer.rb +4 -4
- data/lib/datadog/tracing/contrib/kafka/instrumentation/producer.rb +6 -6
- data/lib/datadog/tracing/contrib/kafka/integration.rb +6 -6
- data/lib/datadog/tracing/contrib/kafka/patcher.rb +5 -5
- data/lib/datadog/tracing/contrib/karafka/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/karafka/distributed/propagation.rb +11 -9
- data/lib/datadog/tracing/contrib/karafka/ext.rb +13 -13
- data/lib/datadog/tracing/contrib/karafka/integration.rb +5 -5
- data/lib/datadog/tracing/contrib/karafka/monitor.rb +14 -14
- data/lib/datadog/tracing/contrib/karafka/patcher.rb +9 -9
- data/lib/datadog/tracing/contrib/karafka.rb +7 -6
- data/lib/datadog/tracing/contrib/lograge/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/lograge/ext.rb +1 -1
- data/lib/datadog/tracing/contrib/lograge/integration.rb +5 -5
- data/lib/datadog/tracing/contrib/lograge/patcher.rb +9 -9
- data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/mongodb/ext.rb +18 -18
- data/lib/datadog/tracing/contrib/mongodb/instrumentation.rb +3 -3
- data/lib/datadog/tracing/contrib/mongodb/integration.rb +7 -7
- data/lib/datadog/tracing/contrib/mongodb/parsers.rb +9 -9
- data/lib/datadog/tracing/contrib/mongodb/patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +18 -21
- data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +3 -3
- data/lib/datadog/tracing/contrib/mysql2/ext.rb +11 -11
- data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +7 -11
- data/lib/datadog/tracing/contrib/mysql2/integration.rb +5 -5
- data/lib/datadog/tracing/contrib/mysql2/patcher.rb +2 -2
- data/lib/datadog/tracing/contrib/opensearch/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/opensearch/ext.rb +23 -23
- data/lib/datadog/tracing/contrib/opensearch/integration.rb +6 -6
- data/lib/datadog/tracing/contrib/opensearch/patcher.rb +15 -19
- data/lib/datadog/tracing/contrib/opensearch/quantize.rb +5 -5
- data/lib/datadog/tracing/contrib/patchable.rb +1 -1
- data/lib/datadog/tracing/contrib/patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +3 -3
- data/lib/datadog/tracing/contrib/pg/ext.rb +19 -19
- data/lib/datadog/tracing/contrib/pg/instrumentation.rb +19 -23
- data/lib/datadog/tracing/contrib/pg/integration.rb +5 -5
- data/lib/datadog/tracing/contrib/pg/patcher.rb +2 -2
- data/lib/datadog/tracing/contrib/presto/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/presto/ext.rb +21 -21
- data/lib/datadog/tracing/contrib/presto/instrumentation.rb +8 -10
- data/lib/datadog/tracing/contrib/presto/integration.rb +6 -6
- data/lib/datadog/tracing/contrib/presto/patcher.rb +4 -4
- data/lib/datadog/tracing/contrib/propagation/sql_comment/comment.rb +2 -2
- data/lib/datadog/tracing/contrib/propagation/sql_comment/ext.rb +19 -16
- data/lib/datadog/tracing/contrib/propagation/sql_comment/mode.rb +3 -3
- data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +5 -5
- data/lib/datadog/tracing/contrib/que/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/que/ext.rb +19 -19
- data/lib/datadog/tracing/contrib/que/integration.rb +6 -6
- data/lib/datadog/tracing/contrib/que/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/que/tracer.rb +3 -2
- data/lib/datadog/tracing/contrib/racecar/configuration/settings.rb +3 -3
- data/lib/datadog/tracing/contrib/racecar/event.rb +5 -9
- data/lib/datadog/tracing/contrib/racecar/events/batch.rb +3 -3
- data/lib/datadog/tracing/contrib/racecar/events/consume.rb +3 -3
- data/lib/datadog/tracing/contrib/racecar/events/message.rb +3 -3
- data/lib/datadog/tracing/contrib/racecar/events.rb +4 -4
- data/lib/datadog/tracing/contrib/racecar/ext.rb +18 -18
- data/lib/datadog/tracing/contrib/racecar/integration.rb +5 -5
- data/lib/datadog/tracing/contrib/racecar/patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/rack/configuration/settings.rb +9 -3
- data/lib/datadog/tracing/contrib/rack/ext.rb +43 -16
- data/lib/datadog/tracing/contrib/rack/header_collection.rb +3 -3
- data/lib/datadog/tracing/contrib/rack/header_tagging.rb +24 -1
- data/lib/datadog/tracing/contrib/rack/integration.rb +6 -6
- data/lib/datadog/tracing/contrib/rack/middlewares.rb +28 -25
- data/lib/datadog/tracing/contrib/rack/patcher.rb +5 -5
- data/lib/datadog/tracing/contrib/rack/request_queue.rb +4 -4
- data/lib/datadog/tracing/contrib/rack/route_inference.rb +12 -10
- data/lib/datadog/tracing/contrib/rack/trace_proxy_middleware.rb +124 -6
- data/lib/datadog/tracing/contrib/rails/auto_instrument_railtie.rb +1 -1
- data/lib/datadog/tracing/contrib/rails/configuration/settings.rb +3 -3
- data/lib/datadog/tracing/contrib/rails/ext.rb +15 -15
- data/lib/datadog/tracing/contrib/rails/framework.rb +11 -11
- data/lib/datadog/tracing/contrib/rails/integration.rb +5 -5
- data/lib/datadog/tracing/contrib/rails/log_injection.rb +1 -1
- data/lib/datadog/tracing/contrib/rails/middlewares.rb +1 -1
- data/lib/datadog/tracing/contrib/rails/patcher.rb +8 -9
- data/lib/datadog/tracing/contrib/rails/railtie.rb +4 -4
- data/lib/datadog/tracing/contrib/rails/runner.rb +4 -2
- data/lib/datadog/tracing/contrib/rake/configuration/settings.rb +3 -3
- data/lib/datadog/tracing/contrib/rake/ext.rb +12 -12
- data/lib/datadog/tracing/contrib/rake/instrumentation.rb +9 -7
- data/lib/datadog/tracing/contrib/rake/integration.rb +5 -5
- data/lib/datadog/tracing/contrib/rake/patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/redis/configuration/resolver.rb +3 -3
- data/lib/datadog/tracing/contrib/redis/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/redis/ext.rb +16 -16
- data/lib/datadog/tracing/contrib/redis/instrumentation.rb +6 -6
- data/lib/datadog/tracing/contrib/redis/integration.rb +7 -7
- data/lib/datadog/tracing/contrib/redis/patcher.rb +10 -10
- data/lib/datadog/tracing/contrib/redis/quantize.rb +40 -6
- data/lib/datadog/tracing/contrib/redis/tags.rb +6 -11
- data/lib/datadog/tracing/contrib/redis/trace_middleware.rb +16 -8
- data/lib/datadog/tracing/contrib/resque/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/resque/ext.rb +7 -7
- data/lib/datadog/tracing/contrib/resque/integration.rb +5 -5
- data/lib/datadog/tracing/contrib/resque/patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/resque/resque_job.rb +6 -5
- data/lib/datadog/tracing/contrib/rest_client/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/rest_client/ext.rb +10 -10
- data/lib/datadog/tracing/contrib/rest_client/integration.rb +6 -6
- data/lib/datadog/tracing/contrib/rest_client/patcher.rb +2 -2
- data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +6 -10
- data/lib/datadog/tracing/contrib/roda/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/roda/ext.rb +6 -5
- data/lib/datadog/tracing/contrib/roda/instrumentation.rb +8 -5
- data/lib/datadog/tracing/contrib/roda/integration.rb +6 -6
- data/lib/datadog/tracing/contrib/roda/patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/semantic_logger/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/semantic_logger/ext.rb +1 -1
- data/lib/datadog/tracing/contrib/semantic_logger/integration.rb +5 -5
- data/lib/datadog/tracing/contrib/semantic_logger/patcher.rb +2 -2
- data/lib/datadog/tracing/contrib/sequel/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/sequel/database.rb +7 -10
- data/lib/datadog/tracing/contrib/sequel/dataset.rb +6 -5
- data/lib/datadog/tracing/contrib/sequel/ext.rb +12 -8
- data/lib/datadog/tracing/contrib/sequel/integration.rb +5 -5
- data/lib/datadog/tracing/contrib/sequel/jdbc_connection_string.rb +140 -0
- data/lib/datadog/tracing/contrib/sequel/patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/sequel/utils.rb +103 -16
- data/lib/datadog/tracing/contrib/shoryuken/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/shoryuken/ext.rb +12 -12
- data/lib/datadog/tracing/contrib/shoryuken/integration.rb +6 -6
- data/lib/datadog/tracing/contrib/shoryuken/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/shoryuken/tracer.rb +3 -2
- data/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +9 -8
- data/lib/datadog/tracing/contrib/sidekiq/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/sidekiq/distributed/propagation.rb +12 -10
- data/lib/datadog/tracing/contrib/sidekiq/ext.rb +30 -30
- data/lib/datadog/tracing/contrib/sidekiq/integration.rb +7 -7
- data/lib/datadog/tracing/contrib/sidekiq/patcher.rb +8 -8
- data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/heartbeat.rb +2 -0
- data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/job_fetch.rb +1 -0
- data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/redis_info.rb +1 -0
- data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/scheduled_poller.rb +2 -0
- data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/stop.rb +1 -0
- data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +15 -14
- data/lib/datadog/tracing/contrib/sidekiq/utils.rb +10 -10
- data/lib/datadog/tracing/contrib/sidekiq.rb +7 -6
- data/lib/datadog/tracing/contrib/sinatra/configuration/settings.rb +3 -3
- data/lib/datadog/tracing/contrib/sinatra/env.rb +6 -6
- data/lib/datadog/tracing/contrib/sinatra/ext.rb +17 -17
- data/lib/datadog/tracing/contrib/sinatra/framework.rb +2 -2
- data/lib/datadog/tracing/contrib/sinatra/integration.rb +5 -5
- data/lib/datadog/tracing/contrib/sinatra/patcher.rb +5 -5
- data/lib/datadog/tracing/contrib/sinatra/tracer.rb +11 -10
- data/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb +9 -8
- data/lib/datadog/tracing/contrib/sneakers/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/sneakers/ext.rb +12 -12
- data/lib/datadog/tracing/contrib/sneakers/integration.rb +7 -7
- data/lib/datadog/tracing/contrib/sneakers/patcher.rb +2 -2
- data/lib/datadog/tracing/contrib/sneakers/tracer.rb +5 -4
- data/lib/datadog/tracing/contrib/span_attribute_schema.rb +2 -2
- data/lib/datadog/tracing/contrib/status_range_env_parser.rb +2 -2
- data/lib/datadog/tracing/contrib/status_range_matcher.rb +4 -0
- data/lib/datadog/tracing/contrib/stripe/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/stripe/ext.rb +12 -12
- data/lib/datadog/tracing/contrib/stripe/integration.rb +5 -5
- data/lib/datadog/tracing/contrib/stripe/patcher.rb +2 -2
- data/lib/datadog/tracing/contrib/stripe/request.rb +4 -4
- data/lib/datadog/tracing/contrib/sucker_punch/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/sucker_punch/exception_handler.rb +1 -1
- data/lib/datadog/tracing/contrib/sucker_punch/ext.rb +13 -13
- data/lib/datadog/tracing/contrib/sucker_punch/instrumentation.rb +5 -4
- data/lib/datadog/tracing/contrib/sucker_punch/integration.rb +5 -5
- data/lib/datadog/tracing/contrib/sucker_punch/patcher.rb +4 -4
- data/lib/datadog/tracing/contrib/trilogy/configuration/settings.rb +3 -3
- data/lib/datadog/tracing/contrib/trilogy/ext.rb +11 -11
- data/lib/datadog/tracing/contrib/trilogy/instrumentation.rb +7 -11
- data/lib/datadog/tracing/contrib/trilogy/integration.rb +5 -5
- data/lib/datadog/tracing/contrib/trilogy/patcher.rb +2 -2
- data/lib/datadog/tracing/contrib/utils/database.rb +5 -5
- data/lib/datadog/tracing/contrib/utils/quantization/{hash.rb → hash_formatter.rb} +3 -3
- data/lib/datadog/tracing/contrib/utils/quantization/http.rb +16 -13
- data/lib/datadog/tracing/contrib/waterdrop/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/waterdrop/distributed/propagation.rb +11 -9
- data/lib/datadog/tracing/contrib/waterdrop/ext.rb +4 -4
- data/lib/datadog/tracing/contrib/waterdrop/integration.rb +5 -5
- data/lib/datadog/tracing/contrib/waterdrop/middleware.rb +2 -2
- data/lib/datadog/tracing/contrib/waterdrop/patcher.rb +7 -7
- data/lib/datadog/tracing/contrib/waterdrop/producer.rb +3 -3
- data/lib/datadog/tracing/contrib/waterdrop.rb +7 -6
- data/lib/datadog/tracing/contrib.rb +62 -54
- data/lib/datadog/tracing/correlation.rb +12 -12
- data/lib/datadog/tracing/diagnostics/environment_logger.rb +15 -12
- data/lib/datadog/tracing/diagnostics/ext.rb +19 -19
- data/lib/datadog/tracing/diagnostics/health.rb +1 -1
- data/lib/datadog/tracing/distributed/b3_multi.rb +8 -8
- data/lib/datadog/tracing/distributed/b3_single.rb +4 -4
- data/lib/datadog/tracing/distributed/baggage.rb +81 -28
- data/lib/datadog/tracing/distributed/datadog.rb +34 -32
- data/lib/datadog/tracing/distributed/fetcher.rb +1 -1
- data/lib/datadog/tracing/distributed/helpers.rb +3 -3
- data/lib/datadog/tracing/distributed/propagation.rb +46 -11
- data/lib/datadog/tracing/distributed/propagation_policy.rb +5 -0
- data/lib/datadog/tracing/distributed/trace_context.rb +29 -263
- data/lib/datadog/tracing/distributed/trace_state/datadog.rb +233 -0
- data/lib/datadog/tracing/distributed/trace_state/ext.rb +44 -0
- data/lib/datadog/tracing/distributed/trace_state/open_telemetry.rb +156 -0
- data/lib/datadog/tracing/distributed/trace_state.rb +121 -0
- data/lib/datadog/tracing/event.rb +2 -2
- data/lib/datadog/tracing/ext.rb +9 -0
- data/lib/datadog/tracing/metadata/analytics.rb +2 -2
- data/lib/datadog/tracing/metadata/errors.rb +4 -4
- data/lib/datadog/tracing/metadata/ext.rb +79 -66
- data/lib/datadog/tracing/metadata/metastruct.rb +1 -1
- data/lib/datadog/tracing/metadata/metastruct_tagging.rb +1 -1
- data/lib/datadog/tracing/metadata/tagging.rb +5 -5
- data/lib/datadog/tracing/metadata.rb +4 -4
- data/lib/datadog/tracing/otel_thread_context.rb +99 -0
- data/lib/datadog/tracing/pipeline/span_filter.rb +2 -2
- data/lib/datadog/tracing/pipeline.rb +3 -3
- data/lib/datadog/tracing/remote.rb +227 -21
- data/lib/datadog/tracing/sampling/all_sampler.rb +1 -1
- data/lib/datadog/tracing/sampling/ext.rb +9 -7
- data/lib/datadog/tracing/sampling/matcher.rb +4 -4
- data/lib/datadog/tracing/sampling/priority_sampler.rb +17 -4
- data/lib/datadog/tracing/sampling/rate_by_key_sampler.rb +3 -3
- data/lib/datadog/tracing/sampling/rate_by_service_sampler.rb +2 -2
- data/lib/datadog/tracing/sampling/rate_sampler.rb +2 -2
- data/lib/datadog/tracing/sampling/rule.rb +5 -5
- data/lib/datadog/tracing/sampling/rule_sampler.rb +68 -37
- data/lib/datadog/tracing/sampling/sampler.rb +2 -2
- data/lib/datadog/tracing/sampling/span/ext.rb +3 -3
- data/lib/datadog/tracing/sampling/span/matcher.rb +2 -2
- data/lib/datadog/tracing/sampling/span/rule.rb +1 -1
- data/lib/datadog/tracing/sampling/span/rule_parser.rb +10 -10
- data/lib/datadog/tracing/span.rb +9 -9
- data/lib/datadog/tracing/span_event.rb +5 -5
- data/lib/datadog/tracing/span_operation.rb +39 -26
- data/lib/datadog/tracing/sync_writer.rb +12 -7
- data/lib/datadog/tracing/trace_digest.rb +29 -4
- data/lib/datadog/tracing/trace_operation.rb +112 -31
- data/lib/datadog/tracing/trace_segment.rb +10 -10
- data/lib/datadog/tracing/tracer.rb +83 -29
- data/lib/datadog/tracing/transport/http/client.rb +4 -4
- data/lib/datadog/tracing/transport/http/statistics.rb +2 -2
- data/lib/datadog/tracing/transport/http/traces.rb +8 -8
- data/lib/datadog/tracing/transport/http.rb +10 -10
- data/lib/datadog/tracing/transport/io/client.rb +3 -3
- data/lib/datadog/tracing/transport/io/response.rb +1 -1
- data/lib/datadog/tracing/transport/io/traces.rb +5 -5
- data/lib/datadog/tracing/transport/io.rb +3 -3
- data/lib/datadog/tracing/transport/native/response.rb +71 -0
- data/lib/datadog/tracing/transport/native.rb +380 -0
- data/lib/datadog/tracing/transport/serializable_trace.rb +19 -19
- data/lib/datadog/tracing/transport/span_events_negotiation.rb +41 -0
- data/lib/datadog/tracing/transport/statistics.rb +2 -2
- data/lib/datadog/tracing/transport/trace_formatter.rb +23 -13
- data/lib/datadog/tracing/transport/traces.rb +12 -32
- data/lib/datadog/tracing/utils.rb +2 -2
- data/lib/datadog/tracing/workers.rb +4 -3
- data/lib/datadog/tracing/writer.rb +22 -9
- data/lib/datadog/tracing.rb +3 -3
- data/lib/datadog/version.rb +4 -4
- data/lib/datadog.rb +15 -11
- metadata +109 -23
- data/ext/datadog_profiling_native_extension/clock_id_noop.c +0 -21
- data/lib/datadog/ai_guard/configuration/settings.rb +0 -113
- data/lib/datadog/appsec/configuration/settings.rb +0 -423
- data/lib/datadog/core/utils/base64.rb +0 -22
- data/lib/datadog/data_streams/configuration/settings.rb +0 -49
- data/lib/datadog/di/configuration/settings.rb +0 -243
- data/lib/datadog/error_tracking/configuration/settings.rb +0 -63
- data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +0 -82
|
@@ -16,6 +16,11 @@
|
|
|
16
16
|
#include "private_vm_api_access.h"
|
|
17
17
|
#include "setup_signal_handler.h"
|
|
18
18
|
#include "time_helpers.h"
|
|
19
|
+
#include "unsafe_api_calls_check.h"
|
|
20
|
+
|
|
21
|
+
#ifdef __APPLE__
|
|
22
|
+
#include "macos_sampler_thread.h"
|
|
23
|
+
#endif
|
|
19
24
|
|
|
20
25
|
// Used to trigger the execution of Collectors::ThreadContext, which implements all of the sampling logic
|
|
21
26
|
// itself; this class only implements the "when to do it" part.
|
|
@@ -64,14 +69,24 @@
|
|
|
64
69
|
// 4. The Ruby VM calls our `sample_from_postponed_job` from a thread holding the global VM lock. A sample is recorded by
|
|
65
70
|
// calling `thread_context_collector_sample`.
|
|
66
71
|
//
|
|
67
|
-
//
|
|
72
|
+
//
|
|
73
|
+
// ### Hooks and TracePoints
|
|
74
|
+
//
|
|
75
|
+
// This class uses various hooks:
|
|
76
|
+
// * A RUBY_INTERNAL_EVENT_GC_ENTER & RUBY_INTERNAL_EVENT_GC_EXIT TracePoint
|
|
77
|
+
// * A RUBY_INTERNAL_EVENT_NEWOBJ "event hook"/internal tracepoint
|
|
78
|
+
// * A GVL thread event hook
|
|
79
|
+
//
|
|
80
|
+
// We refer to those collectively as "hooks".
|
|
81
|
+
//
|
|
82
|
+
// ### Hooks and Forking
|
|
68
83
|
//
|
|
69
84
|
// When the Ruby VM forks, the CPU/Wall-time profiling stops naturally because it's triggered by a background thread
|
|
70
85
|
// that doesn't get automatically restarted by the VM on the child process. (The profiler does trigger its restart at
|
|
71
86
|
// some point -- see `Profiling::Tasks::Setup` for details).
|
|
72
87
|
//
|
|
73
|
-
// But this doesn't apply to any
|
|
74
|
-
// always remember consider this case of -- the worker thread may not be alive but the
|
|
88
|
+
// But this doesn't apply to any hooks this class may use, which will continue to be active. Thus, we need to
|
|
89
|
+
// always remember consider this case of -- the worker thread may not be alive but the hooks can continue to
|
|
75
90
|
// trigger samples.
|
|
76
91
|
//
|
|
77
92
|
// ---
|
|
@@ -87,7 +102,7 @@ unsigned int MAX_ALLOC_WEIGHT = 10000;
|
|
|
87
102
|
static rb_postponed_job_handle_t sample_from_postponed_job_handle;
|
|
88
103
|
static rb_postponed_job_handle_t after_gc_from_postponed_job_handle;
|
|
89
104
|
static rb_postponed_job_handle_t after_gvl_running_from_postponed_job_handle;
|
|
90
|
-
static rb_postponed_job_handle_t
|
|
105
|
+
static rb_postponed_job_handle_t commit_heap_recordings_from_postponed_job_may_lose_gvl_handle;
|
|
91
106
|
#endif
|
|
92
107
|
|
|
93
108
|
// Contains state for a single CpuAndWallTimeWorker instance
|
|
@@ -103,9 +118,12 @@ typedef struct {
|
|
|
103
118
|
bool skip_idle_samples_for_testing;
|
|
104
119
|
bool sighandler_sampling_enabled;
|
|
105
120
|
uint32_t cpu_sampling_interval_ms;
|
|
121
|
+
// Minimum duration of a "Waiting for GVL" period to trigger a sample
|
|
122
|
+
uint32_t waiting_for_gvl_threshold_ns;
|
|
106
123
|
VALUE self_instance;
|
|
107
124
|
VALUE thread_context_collector_instance;
|
|
108
125
|
VALUE idle_sampling_helper_instance;
|
|
126
|
+
idle_sampling_loop_state *idle_sampling_helper_state;
|
|
109
127
|
VALUE owner_thread;
|
|
110
128
|
dynamic_sampling_rate_state cpu_dynamic_sampling_rate;
|
|
111
129
|
discrete_dynamic_sampler allocation_sampler;
|
|
@@ -123,13 +141,29 @@ typedef struct {
|
|
|
123
141
|
|
|
124
142
|
// Others
|
|
125
143
|
|
|
126
|
-
// Used to detect/avoid nested sampling,
|
|
127
|
-
//
|
|
128
|
-
// sampling.
|
|
144
|
+
// Used to detect/avoid nested sampling, and intended to behave as a lock to ensure the profiler doesn't recurse on itself,
|
|
145
|
+
// e.g. when on_newobj_event gets triggered by a memory allocation that happens during another sample, or when the
|
|
146
|
+
// signal handler gets triggered while we're already in the middle of sampling.
|
|
147
|
+
//
|
|
148
|
+
// It's not an actual lock because we rely on the GVL for correct synchronization
|
|
149
|
+
// (and thus this flag is only valid when we know we have the GVL).
|
|
150
|
+
// Exception: `on_gvl_event` sets it for RUBY_INTERNAL_THREAD_EVENT_RESUMED without the GVL -- see the notes there.
|
|
151
|
+
//
|
|
152
|
+
// Similar to a lock, it should not be held across long-running operations,
|
|
153
|
+
// **in particular it MUST NEVER be held during operations where we might lose the GVL**
|
|
154
|
+
// because effectively that would stop the profiler from working until control
|
|
155
|
+
// goes back to that special thread, which on a contended Ruby app, can take hundreds of ms (or more).
|
|
156
|
+
//
|
|
157
|
+
// Because what we want is "profiler doesn't recurse on itself" we want this to behave as a non-reentrant lock
|
|
158
|
+
// (FIXME: We should have checks for this)
|
|
129
159
|
//
|
|
130
160
|
// @ivoanjo: Right now we always sample inside `safely_call`; if that ever changes, this flag may need to become
|
|
131
161
|
// volatile/atomic/have some barriers to ensure it's visible during e.g. signal handlers.
|
|
132
162
|
bool during_sample;
|
|
163
|
+
// Used from the signal handler to ask for a sample at the end of GC.
|
|
164
|
+
// The GC_EXIT event is emitted by the thread that had the GVL + was doing GC, e.g. Ruby won't switch threads between
|
|
165
|
+
// this flag getting set in the signal handler and the GC_EXIT event.
|
|
166
|
+
bool prepare_sample_on_gc_finish;
|
|
133
167
|
|
|
134
168
|
#ifndef NO_GVL_INSTRUMENTATION
|
|
135
169
|
// Only set when sampling is active (gets created at start and cleaned on stop)
|
|
@@ -150,8 +184,6 @@ typedef struct {
|
|
|
150
184
|
unsigned int signal_handler_enqueued_sample;
|
|
151
185
|
// How many times we prepared a sample (sampled directly) from the signal handler
|
|
152
186
|
unsigned int signal_handler_prepared_sample;
|
|
153
|
-
// How many times the signal handler was called from the wrong thread
|
|
154
|
-
unsigned int signal_handler_wrong_thread;
|
|
155
187
|
// How many times we actually tried to interrupt a thread for sampling
|
|
156
188
|
unsigned int interrupt_thread_attempts;
|
|
157
189
|
|
|
@@ -178,6 +210,11 @@ typedef struct {
|
|
|
178
210
|
unsigned int allocations_during_sample;
|
|
179
211
|
|
|
180
212
|
// # GVL profiling stats
|
|
213
|
+
// Note that this tracks two kind of samples from RESUMED:
|
|
214
|
+
// * samples when Waiting for GVL for more than the threshold
|
|
215
|
+
// * samples for the skip-samples-while-without-GVL optimization,
|
|
216
|
+
// which are needed to attribute the time without GVL to the correct Ruby stack
|
|
217
|
+
|
|
181
218
|
// How many times we triggered the after_gvl_running sampling
|
|
182
219
|
unsigned int after_gvl_running;
|
|
183
220
|
// How many times we skipped the after_gvl_running sampling
|
|
@@ -186,6 +223,11 @@ typedef struct {
|
|
|
186
223
|
uint64_t gvl_sampling_time_ns_min;
|
|
187
224
|
uint64_t gvl_sampling_time_ns_max;
|
|
188
225
|
uint64_t gvl_sampling_time_ns_total;
|
|
226
|
+
|
|
227
|
+
struct vm_metrics {
|
|
228
|
+
// Total time spent waiting for the GVL
|
|
229
|
+
uint64_t gvl_waiting_time_ns_total;
|
|
230
|
+
} vm_metrics;
|
|
189
231
|
} stats;
|
|
190
232
|
} cpu_and_wall_time_worker_state;
|
|
191
233
|
|
|
@@ -193,6 +235,8 @@ static VALUE _native_new(VALUE klass);
|
|
|
193
235
|
static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self);
|
|
194
236
|
static void cpu_and_wall_time_worker_typed_data_mark(void *state_ptr);
|
|
195
237
|
static VALUE _native_sampling_loop(VALUE self, VALUE instance);
|
|
238
|
+
static VALUE _native_profiler_internal_thread_done(VALUE self_instance);
|
|
239
|
+
static VALUE _native_prepare_serialize(DDTRACE_UNUSED VALUE self, VALUE self_instance);
|
|
196
240
|
static VALUE _native_stop(DDTRACE_UNUSED VALUE _self, VALUE self_instance, VALUE worker_thread);
|
|
197
241
|
static VALUE stop(VALUE self_instance, VALUE optional_exception, const char *optional_exception_during_operation);
|
|
198
242
|
static void stop_state(cpu_and_wall_time_worker_state *state, VALUE optional_exception, const char *optional_operation_name);
|
|
@@ -211,6 +255,9 @@ static VALUE _native_remove_testing_signal_handler(DDTRACE_UNUSED VALUE self);
|
|
|
211
255
|
static VALUE _native_trigger_sample(DDTRACE_UNUSED VALUE self);
|
|
212
256
|
static VALUE _native_gc_tracepoint(DDTRACE_UNUSED VALUE self, VALUE instance);
|
|
213
257
|
static void on_gc_event(VALUE tracepoint_data, DDTRACE_UNUSED void *unused);
|
|
258
|
+
static void handle_gc_event(cpu_and_wall_time_worker_state *state, rb_event_flag_t event);
|
|
259
|
+
static VALUE _native_on_gc_event(VALUE self, VALUE instance, VALUE event, VALUE during_sample);
|
|
260
|
+
static VALUE _native_request_prepare_on_gc_finish(VALUE self, VALUE instance);
|
|
214
261
|
static void after_gc_from_postponed_job(DDTRACE_UNUSED void *_unused);
|
|
215
262
|
static VALUE safely_call(
|
|
216
263
|
VALUE (*function_to_call_safely)(VALUE),
|
|
@@ -230,12 +277,11 @@ static void reset_stats_not_thread_safe(cpu_and_wall_time_worker_state *state);
|
|
|
230
277
|
static void sleep_for(uint64_t time_ns);
|
|
231
278
|
static VALUE _native_allocation_count(DDTRACE_UNUSED VALUE self);
|
|
232
279
|
static void on_newobj_event(DDTRACE_UNUSED VALUE unused1, DDTRACE_UNUSED void *unused2);
|
|
233
|
-
static void
|
|
280
|
+
static void disable_hooks(cpu_and_wall_time_worker_state *state);
|
|
234
281
|
static VALUE _native_with_blocked_sigprof(DDTRACE_UNUSED VALUE self);
|
|
235
282
|
static VALUE rescued_sample_allocation(VALUE tracepoint_data);
|
|
236
|
-
static VALUE
|
|
283
|
+
static VALUE rescued_commit_heap_recordings_may_lose_gvl(VALUE self_instance);
|
|
237
284
|
static void delayed_error(cpu_and_wall_time_worker_state *state, const char *error);
|
|
238
|
-
static void delayed_error_clock_failure(cpu_and_wall_time_worker_state *state);
|
|
239
285
|
static VALUE _native_delayed_error(DDTRACE_UNUSED VALUE self, VALUE instance, VALUE error_msg);
|
|
240
286
|
static VALUE _native_hold_signals(DDTRACE_UNUSED VALUE self);
|
|
241
287
|
static VALUE _native_resume_signals(DDTRACE_UNUSED VALUE self);
|
|
@@ -248,11 +294,12 @@ static VALUE _native_resume_signals(DDTRACE_UNUSED VALUE self);
|
|
|
248
294
|
static VALUE _native_gvl_profiling_hook_active(DDTRACE_UNUSED VALUE self, VALUE instance);
|
|
249
295
|
static VALUE handle_sampling_failure_rescued_sample_from_postponed_job(VALUE self_instance, VALUE exception);
|
|
250
296
|
static VALUE handle_sampling_failure_thread_context_collector_sample_after_gc(VALUE self_instance, VALUE exception);
|
|
297
|
+
static VALUE handle_sampling_failure_thread_context_collector_heap_update(VALUE self_instance, VALUE exception);
|
|
251
298
|
static VALUE handle_sampling_failure_rescued_sample_allocation(VALUE self_instance, VALUE exception);
|
|
252
|
-
static VALUE
|
|
299
|
+
static VALUE handle_sampling_failure_rescued_commit_heap_recordings(VALUE self_instance, VALUE exception);
|
|
253
300
|
static inline void during_sample_enter(cpu_and_wall_time_worker_state* state);
|
|
254
301
|
static inline void during_sample_exit(cpu_and_wall_time_worker_state* state);
|
|
255
|
-
static void
|
|
302
|
+
static void commit_heap_recordings_from_postponed_job_may_lose_gvl(DDTRACE_UNUSED void *_unused);
|
|
256
303
|
|
|
257
304
|
// We're using `on_newobj_event` function with `rb_add_event_hook2`, which requires in its public signature a function
|
|
258
305
|
// with signature `rb_event_hook_func_t` which doesn't match `on_newobj_event`.
|
|
@@ -278,7 +325,6 @@ static void after_allocation_from_postponed_job(DDTRACE_UNUSED void *_unused);
|
|
|
278
325
|
// (e.g. signal handler) where it's impossible or just awkward to pass it as an argument.
|
|
279
326
|
static VALUE active_sampler_instance = Qnil;
|
|
280
327
|
static cpu_and_wall_time_worker_state *active_sampler_instance_state = NULL;
|
|
281
|
-
static VALUE clock_failure_exception_class = Qnil;
|
|
282
328
|
|
|
283
329
|
// See handle_sampling_signal for details on what this does
|
|
284
330
|
#ifdef NO_POSTPONED_TRIGGER
|
|
@@ -300,13 +346,14 @@ void collectors_cpu_and_wall_time_worker_init(VALUE profiling_module) {
|
|
|
300
346
|
sample_from_postponed_job_handle = rb_postponed_job_preregister(unused_flags, sample_from_postponed_job, NULL);
|
|
301
347
|
after_gc_from_postponed_job_handle = rb_postponed_job_preregister(unused_flags, after_gc_from_postponed_job, NULL);
|
|
302
348
|
after_gvl_running_from_postponed_job_handle = rb_postponed_job_preregister(unused_flags, after_gvl_running_from_postponed_job, NULL);
|
|
303
|
-
|
|
349
|
+
commit_heap_recordings_from_postponed_job_may_lose_gvl_handle =
|
|
350
|
+
rb_postponed_job_preregister(unused_flags, commit_heap_recordings_from_postponed_job_may_lose_gvl, NULL);
|
|
304
351
|
|
|
305
352
|
if (
|
|
306
353
|
sample_from_postponed_job_handle == POSTPONED_JOB_HANDLE_INVALID ||
|
|
307
354
|
after_gc_from_postponed_job_handle == POSTPONED_JOB_HANDLE_INVALID ||
|
|
308
355
|
after_gvl_running_from_postponed_job_handle == POSTPONED_JOB_HANDLE_INVALID ||
|
|
309
|
-
|
|
356
|
+
commit_heap_recordings_from_postponed_job_may_lose_gvl_handle == POSTPONED_JOB_HANDLE_INVALID
|
|
310
357
|
) {
|
|
311
358
|
raise_error(rb_eRuntimeError, "Failed to register profiler postponed jobs (got POSTPONED_JOB_HANDLE_INVALID)");
|
|
312
359
|
}
|
|
@@ -318,8 +365,6 @@ void collectors_cpu_and_wall_time_worker_init(VALUE profiling_module) {
|
|
|
318
365
|
VALUE collectors_cpu_and_wall_time_worker_class = rb_define_class_under(collectors_module, "CpuAndWallTimeWorker", rb_cObject);
|
|
319
366
|
// Hosts methods used for testing the native code using RSpec
|
|
320
367
|
VALUE testing_module = rb_define_module_under(collectors_cpu_and_wall_time_worker_class, "Testing");
|
|
321
|
-
clock_failure_exception_class = rb_define_class_under(collectors_cpu_and_wall_time_worker_class, "ClockFailure", rb_eRuntimeError);
|
|
322
|
-
rb_gc_register_mark_object(clock_failure_exception_class);
|
|
323
368
|
|
|
324
369
|
// Instances of the CpuAndWallTimeWorker class are "TypedData" objects.
|
|
325
370
|
// "TypedData" objects are special objects in the Ruby VM that can wrap C structs.
|
|
@@ -333,6 +378,8 @@ void collectors_cpu_and_wall_time_worker_init(VALUE profiling_module) {
|
|
|
333
378
|
|
|
334
379
|
rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_initialize", _native_initialize, -1);
|
|
335
380
|
rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_sampling_loop", _native_sampling_loop, 1);
|
|
381
|
+
rb_define_method(collectors_cpu_and_wall_time_worker_class, "_native_profiler_internal_thread_done", _native_profiler_internal_thread_done, 0);
|
|
382
|
+
rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_prepare_serialize", _native_prepare_serialize, 1);
|
|
336
383
|
rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_stop", _native_stop, 2);
|
|
337
384
|
rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_reset_after_fork", _native_reset_after_fork, 1);
|
|
338
385
|
rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_stats", _native_stats, 1);
|
|
@@ -347,6 +394,8 @@ void collectors_cpu_and_wall_time_worker_init(VALUE profiling_module) {
|
|
|
347
394
|
rb_define_singleton_method(testing_module, "_native_remove_testing_signal_handler", _native_remove_testing_signal_handler, 0);
|
|
348
395
|
rb_define_singleton_method(testing_module, "_native_trigger_sample", _native_trigger_sample, 0);
|
|
349
396
|
rb_define_singleton_method(testing_module, "_native_gc_tracepoint", _native_gc_tracepoint, 1);
|
|
397
|
+
rb_define_singleton_method(testing_module, "_native_on_gc_event", _native_on_gc_event, 3);
|
|
398
|
+
rb_define_singleton_method(testing_module, "_native_request_prepare_on_gc_finish", _native_request_prepare_on_gc_finish, 1);
|
|
350
399
|
rb_define_singleton_method(testing_module, "_native_simulate_handle_sampling_signal", _native_simulate_handle_sampling_signal, 0);
|
|
351
400
|
rb_define_singleton_method(testing_module, "_native_simulate_sample_from_postponed_job", _native_simulate_sample_from_postponed_job, 0);
|
|
352
401
|
rb_define_singleton_method(testing_module, "_native_is_sigprof_blocked_in_current_thread", _native_is_sigprof_blocked_in_current_thread, 0);
|
|
@@ -369,7 +418,7 @@ static const rb_data_type_t cpu_and_wall_time_worker_typed_data = {
|
|
|
369
418
|
};
|
|
370
419
|
|
|
371
420
|
static VALUE _native_new(VALUE klass) {
|
|
372
|
-
long now = monotonic_wall_time_now_ns(
|
|
421
|
+
long now = monotonic_wall_time_now_ns();
|
|
373
422
|
|
|
374
423
|
cpu_and_wall_time_worker_state *state = ruby_xcalloc(1, sizeof(cpu_and_wall_time_worker_state));
|
|
375
424
|
|
|
@@ -385,8 +434,10 @@ static VALUE _native_new(VALUE klass) {
|
|
|
385
434
|
state->skip_idle_samples_for_testing = false;
|
|
386
435
|
state->sighandler_sampling_enabled = false;
|
|
387
436
|
state->cpu_sampling_interval_ms = 10;
|
|
437
|
+
state->waiting_for_gvl_threshold_ns = 10 * 1000 * 1000;
|
|
388
438
|
state->thread_context_collector_instance = Qnil;
|
|
389
439
|
state->idle_sampling_helper_instance = Qnil;
|
|
440
|
+
state->idle_sampling_helper_state = NULL;
|
|
390
441
|
state->owner_thread = Qnil;
|
|
391
442
|
dynamic_sampling_rate_init(&state->cpu_dynamic_sampling_rate);
|
|
392
443
|
state->gc_tracepoint = Qnil;
|
|
@@ -430,6 +481,7 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
|
|
|
430
481
|
VALUE skip_idle_samples_for_testing = rb_hash_fetch(options, ID2SYM(rb_intern("skip_idle_samples_for_testing")));
|
|
431
482
|
VALUE sighandler_sampling_enabled = rb_hash_fetch(options, ID2SYM(rb_intern("sighandler_sampling_enabled")));
|
|
432
483
|
VALUE cpu_sampling_interval_ms = rb_hash_fetch(options, ID2SYM(rb_intern("cpu_sampling_interval_ms")));
|
|
484
|
+
VALUE waiting_for_gvl_threshold_ns = rb_hash_fetch(options, ID2SYM(rb_intern("waiting_for_gvl_threshold_ns")));
|
|
433
485
|
|
|
434
486
|
ENFORCE_BOOLEAN(gc_profiling_enabled);
|
|
435
487
|
ENFORCE_BOOLEAN(no_signals_workaround_enabled);
|
|
@@ -441,6 +493,7 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
|
|
|
441
493
|
ENFORCE_BOOLEAN(skip_idle_samples_for_testing)
|
|
442
494
|
ENFORCE_BOOLEAN(sighandler_sampling_enabled)
|
|
443
495
|
ENFORCE_TYPE(cpu_sampling_interval_ms, T_FIXNUM);
|
|
496
|
+
ENFORCE_TYPE(waiting_for_gvl_threshold_ns, T_FIXNUM);
|
|
444
497
|
|
|
445
498
|
cpu_and_wall_time_worker_state *state;
|
|
446
499
|
TypedData_Get_Struct(self_instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
|
@@ -454,6 +507,7 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
|
|
|
454
507
|
state->skip_idle_samples_for_testing = (skip_idle_samples_for_testing == Qtrue);
|
|
455
508
|
state->sighandler_sampling_enabled = (sighandler_sampling_enabled == Qtrue);
|
|
456
509
|
state->cpu_sampling_interval_ms = NUM2INT(cpu_sampling_interval_ms);
|
|
510
|
+
state->waiting_for_gvl_threshold_ns = NUM2UINT(waiting_for_gvl_threshold_ns);
|
|
457
511
|
|
|
458
512
|
double total_overhead_target_percentage = NUM2DBL(dynamic_sampling_rate_overhead_target_percentage);
|
|
459
513
|
if (!state->allocation_profiling_enabled) {
|
|
@@ -462,12 +516,14 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
|
|
|
462
516
|
// TODO: May be nice to offer customization here? Distribute available "overhead" margin with a bias towards one or the other
|
|
463
517
|
// sampler.
|
|
464
518
|
dynamic_sampling_rate_set_overhead_target_percentage(&state->cpu_dynamic_sampling_rate, total_overhead_target_percentage / 2);
|
|
465
|
-
|
|
466
|
-
|
|
519
|
+
discrete_dynamic_sampler_set_overhead_target_percentage(
|
|
520
|
+
&state->allocation_sampler, total_overhead_target_percentage / 2, monotonic_wall_time_now_ns()
|
|
521
|
+
);
|
|
467
522
|
}
|
|
468
523
|
|
|
469
524
|
state->thread_context_collector_instance = enforce_thread_context_collector_instance(thread_context_collector_instance);
|
|
470
525
|
state->idle_sampling_helper_instance = idle_sampling_helper_instance;
|
|
526
|
+
state->idle_sampling_helper_state = idle_sampling_helper_get_state(idle_sampling_helper_instance);
|
|
471
527
|
state->gc_tracepoint = rb_tracepoint_new(Qnil, RUBY_INTERNAL_EVENT_GC_ENTER | RUBY_INTERNAL_EVENT_GC_EXIT, on_gc_event, NULL /* unused */);
|
|
472
528
|
|
|
473
529
|
return Qtrue;
|
|
@@ -492,7 +548,7 @@ static VALUE _native_sampling_loop(DDTRACE_UNUSED VALUE _self, VALUE instance) {
|
|
|
492
548
|
|
|
493
549
|
// If we already got a delayed exception registered even before starting, raise before starting
|
|
494
550
|
if (state->failure_exception != Qnil) {
|
|
495
|
-
|
|
551
|
+
disable_hooks(state);
|
|
496
552
|
rb_exc_raise(state->failure_exception);
|
|
497
553
|
}
|
|
498
554
|
|
|
@@ -502,13 +558,13 @@ static VALUE _native_sampling_loop(DDTRACE_UNUSED VALUE _self, VALUE instance) {
|
|
|
502
558
|
raise_error(rb_eRuntimeError, "Could not start CpuAndWallTimeWorker: There's already another instance of CpuAndWallTimeWorker active in a different thread");
|
|
503
559
|
} else {
|
|
504
560
|
// The previously active thread seems to have died without cleaning up after itself.
|
|
505
|
-
// In this case, we can still go ahead and start the profiler BUT we make sure to disable any existing
|
|
561
|
+
// In this case, we can still go ahead and start the profiler BUT we make sure to disable any existing hooks
|
|
506
562
|
// first as:
|
|
507
|
-
// a) If this is a new instance of the CpuAndWallTimeWorker, we don't want the
|
|
563
|
+
// a) If this is a new instance of the CpuAndWallTimeWorker, we don't want the hooks from the old instance
|
|
508
564
|
// being kept around
|
|
509
565
|
// b) If this is the same instance of the CpuAndWallTimeWorker if we call enable on a tracepoint that is already
|
|
510
566
|
// enabled, it will start firing more than once, see https://bugs.ruby-lang.org/issues/19114 for details.
|
|
511
|
-
|
|
567
|
+
disable_hooks(old_state);
|
|
512
568
|
}
|
|
513
569
|
}
|
|
514
570
|
|
|
@@ -516,10 +572,18 @@ static VALUE _native_sampling_loop(DDTRACE_UNUSED VALUE _self, VALUE instance) {
|
|
|
516
572
|
// situation we stop immediately and never even start the sampling trigger loop.
|
|
517
573
|
if (state->stop_thread == rb_thread_current()) return Qnil;
|
|
518
574
|
|
|
575
|
+
thread_context_collector_profiler_internal_thread_started();
|
|
576
|
+
|
|
519
577
|
// Reset the dynamic sampling rate state, if any (reminder: the monotonic clock reference may change after a fork)
|
|
520
578
|
dynamic_sampling_rate_reset(&state->cpu_dynamic_sampling_rate);
|
|
521
|
-
|
|
522
|
-
|
|
579
|
+
discrete_dynamic_sampler_reset(&state->allocation_sampler, monotonic_wall_time_now_ns());
|
|
580
|
+
|
|
581
|
+
// Reset per-thread state, if any. This ensures there's no leftover state from a previous profiler run that would
|
|
582
|
+
// affect or be included in samples taken by this profiler about to run.
|
|
583
|
+
//
|
|
584
|
+
// NOTE: This needs to be called before we enable any hooks or anything that could trigger samples (e.g.
|
|
585
|
+
// reset cannot be concurrent with any sampling activity)
|
|
586
|
+
thread_context_collector_reset_all_per_thread_contexts(state->thread_context_collector_instance);
|
|
523
587
|
|
|
524
588
|
// This write to a global is thread-safe BECAUSE we're still holding on to the global VM lock at this point
|
|
525
589
|
active_sampler_instance_state = state;
|
|
@@ -530,13 +594,21 @@ static VALUE _native_sampling_loop(DDTRACE_UNUSED VALUE _self, VALUE instance) {
|
|
|
530
594
|
|
|
531
595
|
block_sigprof_signal_handler_from_running_in_current_thread(); // We want to interrupt the thread with the global VM lock, never this one
|
|
532
596
|
|
|
597
|
+
#ifdef __APPLE__
|
|
598
|
+
// Promote the native thread that will run the sampling loop to a realtime scheduling policy so
|
|
599
|
+
// its periodic wake-ups are not subject to the default ~1-2ms timeshare wake latency. The matching
|
|
600
|
+
// demote happens below in this same function, alongside the SIGPROF unblock dance, so both per-thread
|
|
601
|
+
// policy changes are reverted before Ruby reuses this native thread for an unrelated Ruby thread.
|
|
602
|
+
promote_sampler_thread_to_realtime(MILLIS_AS_NS(state->cpu_sampling_interval_ms));
|
|
603
|
+
#endif
|
|
604
|
+
|
|
533
605
|
// Release GVL, get to the actual work!
|
|
534
606
|
int exception_state;
|
|
535
607
|
rb_protect(release_gvl_and_run_sampling_trigger_loop, instance, &exception_state);
|
|
536
608
|
|
|
537
609
|
// The sample trigger loop finished (either cleanly or with an error); let's clean up
|
|
538
610
|
|
|
539
|
-
|
|
611
|
+
disable_hooks(state);
|
|
540
612
|
|
|
541
613
|
active_sampler_instance_state = NULL;
|
|
542
614
|
active_sampler_instance = Qnil;
|
|
@@ -551,6 +623,14 @@ static VALUE _native_sampling_loop(DDTRACE_UNUSED VALUE _self, VALUE instance) {
|
|
|
551
623
|
// had SIGPROF delivery blocked. :hide_the_pain_harold:
|
|
552
624
|
unblock_sigprof_signal_handler_from_running_in_current_thread();
|
|
553
625
|
|
|
626
|
+
#ifdef __APPLE__
|
|
627
|
+
// Pairs with promote_sampler_thread_to_realtime above. Same reasoning as the SIGPROF unblock:
|
|
628
|
+
// Ruby may reuse this native thread for an unrelated Ruby thread that would otherwise inherit
|
|
629
|
+
// our scheduler policy. Doing it here also covers the exception path, since grab_gvl_and_sample
|
|
630
|
+
// can raise and unwind out of the sampling loop.
|
|
631
|
+
demote_sampler_thread_from_realtime();
|
|
632
|
+
#endif
|
|
633
|
+
|
|
554
634
|
// Why replace and not use remove the signal handler? We do this because when a process receives a SIGPROF without
|
|
555
635
|
// having an explicit signal handler set up, the process will instantly terminate with a confusing
|
|
556
636
|
// "Profiling timer expired" message left behind. (This message doesn't come from us -- it's the default message for
|
|
@@ -573,6 +653,38 @@ static VALUE _native_sampling_loop(DDTRACE_UNUSED VALUE _self, VALUE instance) {
|
|
|
573
653
|
return Qnil;
|
|
574
654
|
}
|
|
575
655
|
|
|
656
|
+
static VALUE during_sample_exit_ensure(VALUE state_ptr) {
|
|
657
|
+
during_sample_exit((cpu_and_wall_time_worker_state *) state_ptr);
|
|
658
|
+
return Qnil;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
static VALUE _native_profiler_internal_thread_done(VALUE self_instance) {
|
|
662
|
+
cpu_and_wall_time_worker_state *state;
|
|
663
|
+
TypedData_Get_Struct(self_instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
|
664
|
+
|
|
665
|
+
during_sample_enter(state);
|
|
666
|
+
return rb_ensure(
|
|
667
|
+
thread_context_collector_profiler_internal_thread_done, state->thread_context_collector_instance,
|
|
668
|
+
during_sample_exit_ensure, (VALUE) state
|
|
669
|
+
);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// This method exists so that we run `thread_context_prepare_serialize` protected with
|
|
673
|
+
// `during_sample_enter`/`during_sample_exit` before we actually serialize.
|
|
674
|
+
//
|
|
675
|
+
// That's why in normal operation we go through the `CpuAndWallTimeWorker` and not directly to the `ThreadContext` to
|
|
676
|
+
// serialize.
|
|
677
|
+
static VALUE _native_prepare_serialize(DDTRACE_UNUSED VALUE self, VALUE self_instance) {
|
|
678
|
+
cpu_and_wall_time_worker_state *state;
|
|
679
|
+
TypedData_Get_Struct(self_instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
|
680
|
+
|
|
681
|
+
during_sample_enter(state);
|
|
682
|
+
return rb_ensure(
|
|
683
|
+
thread_context_prepare_serialize, state->thread_context_collector_instance,
|
|
684
|
+
during_sample_exit_ensure, (VALUE) state
|
|
685
|
+
);
|
|
686
|
+
}
|
|
687
|
+
|
|
576
688
|
static VALUE _native_stop(DDTRACE_UNUSED VALUE _self, VALUE self_instance, VALUE worker_thread) {
|
|
577
689
|
cpu_and_wall_time_worker_state *state;
|
|
578
690
|
TypedData_Get_Struct(self_instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
|
@@ -588,8 +700,8 @@ static void stop_state(cpu_and_wall_time_worker_state *state, VALUE optional_exc
|
|
|
588
700
|
state->failure_exception = optional_exception;
|
|
589
701
|
state->failure_exception_during_operation = optional_exception_during_operation;
|
|
590
702
|
|
|
591
|
-
// Disable the
|
|
592
|
-
|
|
703
|
+
// Disable the hooks as soon as possible, so the VM doesn't keep on calling them
|
|
704
|
+
disable_hooks(state);
|
|
593
705
|
}
|
|
594
706
|
|
|
595
707
|
static VALUE stop(VALUE self_instance, VALUE optional_exception, const char *optional_exception_during_operation) {
|
|
@@ -604,25 +716,29 @@ static VALUE stop(VALUE self_instance, VALUE optional_exception, const char *opt
|
|
|
604
716
|
// NOTE: Remember that this will run in the thread and within the scope of user code, including user C code.
|
|
605
717
|
// 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
|
|
606
718
|
// we do here can set `errno`, then we must be careful to restore the old `errno` after the fact.
|
|
719
|
+
//
|
|
720
|
+
// Neither this handler nor its callees may dereference Ruby objects before confirming GVL ownership or during GC.
|
|
721
|
+
// Holding the GVL is not enough: we may have interrupted GC itself, with Ruby heap pages protected by compaction.
|
|
607
722
|
static void handle_sampling_signal(DDTRACE_UNUSED int _signal, DDTRACE_UNUSED siginfo_t *_info, DDTRACE_UNUSED void *_ucontext) {
|
|
723
|
+
// We must first check that we landed on the correct thread and can proceed.
|
|
724
|
+
// We must never touch the state before we confirm that we have landed on the thread that is holding the GVL on the main
|
|
725
|
+
// ractor as otherwise we may be concurrent with the profiler shutting down and removing its state.
|
|
726
|
+
if (
|
|
727
|
+
!ruby_native_thread_p() || // Not a Ruby thread
|
|
728
|
+
!is_current_thread_in_main_ractor_and_holding_the_gvl() // Not safe to enqueue a sample from this thread
|
|
729
|
+
) return;
|
|
730
|
+
|
|
608
731
|
cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
|
|
609
732
|
|
|
610
733
|
// This can potentially happen if the CpuAndWallTimeWorker was stopped while the signal delivery was happening; nothing to do
|
|
611
734
|
if (state == NULL) return;
|
|
612
735
|
|
|
613
|
-
if (
|
|
614
|
-
!ruby_native_thread_p() || // Not a Ruby thread
|
|
615
|
-
!is_current_thread_holding_the_gvl() || // Not safe to enqueue a sample from this thread
|
|
616
|
-
!ddtrace_rb_ractor_main_p() // We're not on the main Ractor; we currently don't support profiling non-main Ractors
|
|
617
|
-
) {
|
|
618
|
-
state->stats.signal_handler_wrong_thread++;
|
|
619
|
-
return;
|
|
620
|
-
}
|
|
621
|
-
|
|
622
736
|
// We assume there can be no concurrent nor nested calls to handle_sampling_signal because
|
|
623
737
|
// a) we get triggered using SIGPROF, and the docs state a second SIGPROF will not interrupt an existing one (see sigaction docs on sa_mask)
|
|
624
738
|
// b) we validate we are in the thread that has the global VM lock; if a different thread gets a signal, it will return early
|
|
625
739
|
// because it will not have the global VM lock
|
|
740
|
+
// c) `simulate_sampling_signal_delivery` calls us directly instead of via a real SIGPROF, and blocks SIGPROF delivery on its
|
|
741
|
+
// thread for the duration of that call, so it can't be nested into by a real SIGPROF either
|
|
626
742
|
|
|
627
743
|
state->stats.signal_handler_enqueued_sample++;
|
|
628
744
|
|
|
@@ -632,11 +748,20 @@ static void handle_sampling_signal(DDTRACE_UNUSED int _signal, DDTRACE_UNUSED si
|
|
|
632
748
|
!state->during_sample;
|
|
633
749
|
|
|
634
750
|
if (sample_from_signal_handler) {
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
751
|
+
if (rb_during_gc()) {
|
|
752
|
+
// During GC Ruby might be marking our buffer or compacting (moving) where iseqs live so we skip preparing the
|
|
753
|
+
// sample immediately, and instead defer preparation until GC_EXIT.
|
|
754
|
+
//
|
|
755
|
+
// When GC profiling is disabled, we just fall back to sampling the stack after GC finishes, e.g. it's the
|
|
756
|
+
// equivalent of disabling `sample_from_signal_handler` for samples that happen during GC.
|
|
757
|
+
state->prepare_sample_on_gc_finish = true;
|
|
758
|
+
} else {
|
|
759
|
+
// Buffer current stack trace. Note that this will not actually record the sample, for that we still need to wait
|
|
760
|
+
// until the postponed job below gets run.
|
|
761
|
+
bool prepared = thread_context_collector_prepare_sample_inside_signal_handler();
|
|
638
762
|
|
|
639
|
-
|
|
763
|
+
if (prepared) state->stats.signal_handler_prepared_sample++;
|
|
764
|
+
}
|
|
640
765
|
}
|
|
641
766
|
|
|
642
767
|
#ifndef NO_POSTPONED_TRIGGER // Ruby 3.3+
|
|
@@ -670,7 +795,8 @@ static void handle_sampling_signal(DDTRACE_UNUSED int _signal, DDTRACE_UNUSED si
|
|
|
670
795
|
#endif
|
|
671
796
|
}
|
|
672
797
|
|
|
673
|
-
//
|
|
798
|
+
// Runs without the GVL: neither this loop nor its callees may dereference Ruby objects until they reacquire it.
|
|
799
|
+
// GC compaction can protect Ruby heap pages while this loop runs, so even reading an object's header is unsafe.
|
|
674
800
|
static void *run_sampling_trigger_loop(void *state_ptr) {
|
|
675
801
|
cpu_and_wall_time_worker_state *state = (cpu_and_wall_time_worker_state *) state_ptr;
|
|
676
802
|
|
|
@@ -690,7 +816,7 @@ static void *run_sampling_trigger_loop(void *state_ptr) {
|
|
|
690
816
|
state->stats.trigger_simulated_signal_delivery_attempts++;
|
|
691
817
|
grab_gvl_and_sample(); // Note: Can raise exceptions
|
|
692
818
|
} else {
|
|
693
|
-
current_gvl_owner owner =
|
|
819
|
+
current_gvl_owner owner = main_ractor_gvl_owner();
|
|
694
820
|
if (owner.valid) {
|
|
695
821
|
// Note that reading the GVL owner and sending them a signal is a race -- the Ruby VM keeps on executing while
|
|
696
822
|
// we're doing this, so we may still not signal the correct thread from time to time, but our signal handler
|
|
@@ -714,7 +840,7 @@ static void *run_sampling_trigger_loop(void *state_ptr) {
|
|
|
714
840
|
// for an uncontrolled amount of time. (This can still happen to the IdleSamplingHelper, but the
|
|
715
841
|
// CpuAndWallTimeWorker will still be free to interrupt the Ruby VM and keep sampling for the entire blocking period).
|
|
716
842
|
state->stats.trigger_simulated_signal_delivery_attempts++;
|
|
717
|
-
idle_sampling_helper_request_action(state->
|
|
843
|
+
idle_sampling_helper_request_action(state->idle_sampling_helper_state, grab_gvl_and_sample);
|
|
718
844
|
}
|
|
719
845
|
}
|
|
720
846
|
}
|
|
@@ -726,7 +852,7 @@ static void *run_sampling_trigger_loop(void *state_ptr) {
|
|
|
726
852
|
// Note that we deliberately should NOT combine this sleep_for with the one above because the result of
|
|
727
853
|
// `dynamic_sampling_rate_get_sleep` may have changed while the above sleep was ongoing.
|
|
728
854
|
uint64_t extra_sleep =
|
|
729
|
-
dynamic_sampling_rate_get_sleep(&state->cpu_dynamic_sampling_rate, monotonic_wall_time_now_ns(
|
|
855
|
+
dynamic_sampling_rate_get_sleep(&state->cpu_dynamic_sampling_rate, monotonic_wall_time_now_ns());
|
|
730
856
|
if (state->dynamic_sampling_rate_enabled && extra_sleep > 0) {
|
|
731
857
|
state->stats.trigger_sample_extra_sleep++;
|
|
732
858
|
sleep_for(extra_sleep);
|
|
@@ -760,7 +886,7 @@ static void sample_from_postponed_job(DDTRACE_UNUSED void *_unused) {
|
|
|
760
886
|
during_sample_enter(state);
|
|
761
887
|
|
|
762
888
|
// Rescue against any exceptions that happen during sampling
|
|
763
|
-
safely_call(
|
|
889
|
+
VALUE needs_otel_span_key = safely_call(
|
|
764
890
|
rescued_sample_from_postponed_job,
|
|
765
891
|
state->self_instance,
|
|
766
892
|
state->self_instance,
|
|
@@ -768,29 +894,37 @@ static void sample_from_postponed_job(DDTRACE_UNUSED void *_unused) {
|
|
|
768
894
|
);
|
|
769
895
|
|
|
770
896
|
during_sample_exit(state);
|
|
897
|
+
|
|
898
|
+
// Extracting the otel span key can lose the GVL, so we move it outside `during_sample`
|
|
899
|
+
// (It can't raise: it rescues its own exceptions)
|
|
900
|
+
if (needs_otel_span_key == Qtrue) {
|
|
901
|
+
thread_context_collector_resolve_otel_span_key_may_lose_gvl(state->thread_context_collector_instance);
|
|
902
|
+
}
|
|
771
903
|
}
|
|
772
904
|
|
|
773
905
|
static VALUE rescued_sample_from_postponed_job(VALUE self_instance) {
|
|
774
906
|
cpu_and_wall_time_worker_state *state;
|
|
775
907
|
TypedData_Get_Struct(self_instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
|
776
908
|
|
|
777
|
-
long wall_time_ns_before_sample = monotonic_wall_time_now_ns(
|
|
909
|
+
long wall_time_ns_before_sample = monotonic_wall_time_now_ns();
|
|
778
910
|
|
|
779
911
|
if (state->dynamic_sampling_rate_enabled && !dynamic_sampling_rate_should_sample(&state->cpu_dynamic_sampling_rate, wall_time_ns_before_sample)) {
|
|
780
912
|
state->stats.cpu_skipped++;
|
|
781
|
-
return
|
|
913
|
+
return Qfalse;
|
|
782
914
|
}
|
|
783
915
|
|
|
784
916
|
state->stats.cpu_sampled++;
|
|
785
917
|
|
|
786
|
-
|
|
787
|
-
|
|
918
|
+
bool needs_otel_span_key =
|
|
919
|
+
thread_context_collector_sample(state->thread_context_collector_instance, wall_time_ns_before_sample);
|
|
788
920
|
|
|
789
|
-
long wall_time_ns_after_sample = monotonic_wall_time_now_ns(
|
|
790
|
-
long delta_ns = wall_time_ns_after_sample - wall_time_ns_before_sample;
|
|
921
|
+
long wall_time_ns_after_sample = monotonic_wall_time_now_ns();
|
|
791
922
|
|
|
792
|
-
|
|
793
|
-
|
|
923
|
+
if (wall_time_ns_after_sample < wall_time_ns_before_sample) {
|
|
924
|
+
raise_error(rb_eRuntimeError, "BUG: Unexpected wall time going backwards when tracking overhead");
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
uint64_t sampling_time_ns = wall_time_ns_after_sample - wall_time_ns_before_sample;
|
|
794
928
|
|
|
795
929
|
state->stats.cpu_sampling_time_ns_min = uint64_min_of(sampling_time_ns, state->stats.cpu_sampling_time_ns_min);
|
|
796
930
|
state->stats.cpu_sampling_time_ns_max = uint64_max_of(sampling_time_ns, state->stats.cpu_sampling_time_ns_max);
|
|
@@ -798,8 +932,7 @@ static VALUE rescued_sample_from_postponed_job(VALUE self_instance) {
|
|
|
798
932
|
|
|
799
933
|
dynamic_sampling_rate_after_sample(&state->cpu_dynamic_sampling_rate, wall_time_ns_after_sample, sampling_time_ns);
|
|
800
934
|
|
|
801
|
-
|
|
802
|
-
return Qnil;
|
|
935
|
+
return needs_otel_span_key ? Qtrue : Qfalse;
|
|
803
936
|
}
|
|
804
937
|
|
|
805
938
|
// This method exists only to enable testing Datadog::Profiling::Collectors::CpuAndWallTimeWorker behavior using RSpec.
|
|
@@ -825,7 +958,7 @@ static VALUE release_gvl_and_run_sampling_trigger_loop(VALUE instance) {
|
|
|
825
958
|
cpu_and_wall_time_worker_state *state;
|
|
826
959
|
TypedData_Get_Struct(instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
|
827
960
|
|
|
828
|
-
// Final preparations: Setup signal handler and enable
|
|
961
|
+
// Final preparations: Setup signal handler and enable hooks. We run these here and not in `_native_sampling_loop`
|
|
829
962
|
// because they may raise exceptions.
|
|
830
963
|
install_sigprof_signal_handler(handle_sampling_signal, "handle_sampling_signal");
|
|
831
964
|
if (state->gc_profiling_enabled) rb_tracepoint_enable(state->gc_tracepoint);
|
|
@@ -840,15 +973,12 @@ static VALUE release_gvl_and_run_sampling_trigger_loop(VALUE instance) {
|
|
|
840
973
|
|
|
841
974
|
if (state->gvl_profiling_enabled) {
|
|
842
975
|
#ifndef NO_GVL_INSTRUMENTATION
|
|
843
|
-
#ifdef USE_GVL_PROFILING_3_2_WORKAROUNDS
|
|
844
|
-
gvl_profiling_state_thread_tracking_workaround();
|
|
845
|
-
#endif
|
|
846
|
-
|
|
847
976
|
state->gvl_profiling_hook = rb_internal_thread_add_event_hook(
|
|
848
977
|
on_gvl_event,
|
|
849
978
|
(
|
|
850
979
|
// For now we're only asking for these events, even though there's more
|
|
851
980
|
// (e.g. check docs or gvl-tracing gem)
|
|
981
|
+
RUBY_INTERNAL_THREAD_EVENT_SUSPENDED | /* released gvl */
|
|
852
982
|
RUBY_INTERNAL_THREAD_EVENT_READY /* waiting for gvl */ |
|
|
853
983
|
RUBY_INTERNAL_THREAD_EVENT_RESUMED /* running/runnable */
|
|
854
984
|
),
|
|
@@ -867,6 +997,8 @@ static VALUE release_gvl_and_run_sampling_trigger_loop(VALUE instance) {
|
|
|
867
997
|
// If we stopped sampling due to an exception, re-raise it (now in the worker thread)
|
|
868
998
|
if (state->failure_exception != Qnil) rb_exc_raise(state->failure_exception);
|
|
869
999
|
|
|
1000
|
+
_native_profiler_internal_thread_done(instance);
|
|
1001
|
+
|
|
870
1002
|
return Qnil;
|
|
871
1003
|
}
|
|
872
1004
|
|
|
@@ -948,9 +1080,20 @@ static void on_gc_event(VALUE tracepoint_data, DDTRACE_UNUSED void *unused) {
|
|
|
948
1080
|
// and disabled before it is cleared, but just in case...
|
|
949
1081
|
if (state == NULL) return;
|
|
950
1082
|
|
|
1083
|
+
handle_gc_event(state, event);
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
static void handle_gc_event(cpu_and_wall_time_worker_state *state, rb_event_flag_t event) {
|
|
951
1087
|
if (event == RUBY_INTERNAL_EVENT_GC_ENTER) {
|
|
1088
|
+
// A signal can arrive after GC_EXIT while `rb_during_gc` is still true; discard requests from the previous GC step.
|
|
1089
|
+
state->prepare_sample_on_gc_finish = false;
|
|
952
1090
|
thread_context_collector_on_gc_start(state->thread_context_collector_instance);
|
|
953
1091
|
} else if (event == RUBY_INTERNAL_EVENT_GC_EXIT) {
|
|
1092
|
+
if (state->prepare_sample_on_gc_finish && !state->during_sample) {
|
|
1093
|
+
during_sample_enter(state);
|
|
1094
|
+
thread_context_collector_prepare_sample_on_gc_finish();
|
|
1095
|
+
during_sample_exit(state);
|
|
1096
|
+
}
|
|
954
1097
|
bool should_flush = thread_context_collector_on_gc_finish(state->thread_context_collector_instance);
|
|
955
1098
|
|
|
956
1099
|
// We use rb_postponed_job_register_one to ask Ruby to run thread_context_collector_sample_after_gc when the
|
|
@@ -965,6 +1108,31 @@ static void on_gc_event(VALUE tracepoint_data, DDTRACE_UNUSED void *unused) {
|
|
|
965
1108
|
}
|
|
966
1109
|
}
|
|
967
1110
|
|
|
1111
|
+
static VALUE _native_request_prepare_on_gc_finish(DDTRACE_UNUSED VALUE self, VALUE instance) {
|
|
1112
|
+
cpu_and_wall_time_worker_state *state;
|
|
1113
|
+
TypedData_Get_Struct(instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
|
1114
|
+
state->prepare_sample_on_gc_finish = true;
|
|
1115
|
+
return Qnil;
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
static VALUE _native_on_gc_event(DDTRACE_UNUSED VALUE self, VALUE instance, VALUE event, VALUE during_sample) {
|
|
1119
|
+
cpu_and_wall_time_worker_state *state;
|
|
1120
|
+
TypedData_Get_Struct(instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
|
1121
|
+
ENFORCE_BOOLEAN(during_sample);
|
|
1122
|
+
rb_event_flag_t event_flag;
|
|
1123
|
+
if (event == ID2SYM(rb_intern("enter"))) event_flag = RUBY_INTERNAL_EVENT_GC_ENTER;
|
|
1124
|
+
else if (event == ID2SYM(rb_intern("exit"))) event_flag = RUBY_INTERNAL_EVENT_GC_EXIT;
|
|
1125
|
+
else rb_raise(rb_eArgError, "Expected :enter or :exit");
|
|
1126
|
+
|
|
1127
|
+
bool was_during_sample = state->during_sample;
|
|
1128
|
+
if (during_sample == Qtrue) during_sample_enter(state);
|
|
1129
|
+
debug_enter_unsafe_context();
|
|
1130
|
+
handle_gc_event(state, event_flag);
|
|
1131
|
+
debug_leave_unsafe_context();
|
|
1132
|
+
if (!was_during_sample) during_sample_exit(state);
|
|
1133
|
+
return Qnil;
|
|
1134
|
+
}
|
|
1135
|
+
|
|
968
1136
|
static void after_gc_from_postponed_job(DDTRACE_UNUSED void *_unused) {
|
|
969
1137
|
cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
|
|
970
1138
|
|
|
@@ -987,6 +1155,15 @@ static void after_gc_from_postponed_job(DDTRACE_UNUSED void *_unused) {
|
|
|
987
1155
|
);
|
|
988
1156
|
|
|
989
1157
|
during_sample_exit(state);
|
|
1158
|
+
|
|
1159
|
+
// This part runs separately from above because it may lose the GVL and we don't want `during_sample` to be set in
|
|
1160
|
+
// such a situation
|
|
1161
|
+
safely_call(
|
|
1162
|
+
thread_context_collector_heap_update_may_lose_gvl,
|
|
1163
|
+
state->thread_context_collector_instance,
|
|
1164
|
+
state->self_instance,
|
|
1165
|
+
handle_sampling_failure_thread_context_collector_heap_update
|
|
1166
|
+
);
|
|
990
1167
|
}
|
|
991
1168
|
|
|
992
1169
|
// Equivalent to Ruby begin/rescue call, where we call a C function and jump to the exception handler if an
|
|
@@ -1024,18 +1201,23 @@ static VALUE _native_simulate_sample_from_postponed_job(DDTRACE_UNUSED VALUE sel
|
|
|
1024
1201
|
|
|
1025
1202
|
// After the Ruby VM forks, this method gets called in the child process to clean up any leftover state from the parent.
|
|
1026
1203
|
//
|
|
1027
|
-
// Assumption: This method gets called BEFORE restarting profiling. Note that profiling-related
|
|
1204
|
+
// Assumption: This method gets called BEFORE restarting profiling. Note that profiling-related hooks may still
|
|
1028
1205
|
// be active, so we make sure to disable them before calling into anything else, so that there are no components
|
|
1029
1206
|
// attempting to trigger samples at the same time as the reset is done.
|
|
1030
1207
|
//
|
|
1031
|
-
// In the future, if we add more other components with
|
|
1032
|
-
//
|
|
1208
|
+
// In the future, if we add more other components with hooks, we will need to coordinate stopping all such
|
|
1209
|
+
// hooks before doing the other cleaning steps.
|
|
1210
|
+
//
|
|
1211
|
+
// Note that tests call this method directly in the same process without forking,
|
|
1212
|
+
// and in such a case non-current Threads keep running.
|
|
1033
1213
|
static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE instance) {
|
|
1034
1214
|
cpu_and_wall_time_worker_state *state;
|
|
1035
1215
|
TypedData_Get_Struct(instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
|
1036
1216
|
|
|
1037
|
-
// Disable all
|
|
1038
|
-
|
|
1217
|
+
// Disable all hooks, so that there are no more attempts to mutate the profile
|
|
1218
|
+
disable_hooks(state);
|
|
1219
|
+
|
|
1220
|
+
private_vm_api_access_self_test();
|
|
1039
1221
|
|
|
1040
1222
|
reset_stats_not_thread_safe(state);
|
|
1041
1223
|
|
|
@@ -1071,7 +1253,6 @@ static VALUE _native_stats(DDTRACE_UNUSED VALUE self, VALUE instance) {
|
|
|
1071
1253
|
ID2SYM(rb_intern("simulated_signal_delivery")), /* => */ UINT2NUM(state->stats.simulated_signal_delivery),
|
|
1072
1254
|
ID2SYM(rb_intern("signal_handler_enqueued_sample")), /* => */ UINT2NUM(state->stats.signal_handler_enqueued_sample),
|
|
1073
1255
|
ID2SYM(rb_intern("signal_handler_prepared_sample")), /* => */ UINT2NUM(state->stats.signal_handler_prepared_sample),
|
|
1074
|
-
ID2SYM(rb_intern("signal_handler_wrong_thread")), /* => */ UINT2NUM(state->stats.signal_handler_wrong_thread),
|
|
1075
1256
|
ID2SYM(rb_intern("interrupt_thread_attempts")), /* => */ UINT2NUM(state->stats.interrupt_thread_attempts),
|
|
1076
1257
|
|
|
1077
1258
|
// CPU Stats
|
|
@@ -1101,8 +1282,12 @@ static VALUE _native_stats(DDTRACE_UNUSED VALUE self, VALUE instance) {
|
|
|
1101
1282
|
ID2SYM(rb_intern("gvl_sampling_time_ns_max")), /* => */ RUBY_NUM_OR_NIL(state->stats.gvl_sampling_time_ns_max, > 0, ULL2NUM),
|
|
1102
1283
|
ID2SYM(rb_intern("gvl_sampling_time_ns_total")), /* => */ RUBY_NUM_OR_NIL(state->stats.gvl_sampling_time_ns_total, > 0, ULL2NUM),
|
|
1103
1284
|
ID2SYM(rb_intern("gvl_sampling_time_ns_avg")), /* => */ RUBY_AVG_OR_NIL(state->stats.gvl_sampling_time_ns_total, state->stats.after_gvl_running),
|
|
1285
|
+
ID2SYM(rb_intern("gvl_waiting_time_ns_total")), /* => */ state->gvl_profiling_enabled ? ULL2NUM(state->stats.vm_metrics.gvl_waiting_time_ns_total) : Qnil,
|
|
1104
1286
|
};
|
|
1105
1287
|
for (long unsigned int i = 0; i < VALUE_COUNT(arguments); i += 2) rb_hash_aset(stats_as_hash, arguments[i], arguments[i+1]);
|
|
1288
|
+
|
|
1289
|
+
thread_context_collector_stats(state->thread_context_collector_instance, stats_as_hash);
|
|
1290
|
+
|
|
1106
1291
|
return stats_as_hash;
|
|
1107
1292
|
}
|
|
1108
1293
|
|
|
@@ -1110,6 +1295,7 @@ static VALUE _native_stats_reset_not_thread_safe(DDTRACE_UNUSED VALUE self, VALU
|
|
|
1110
1295
|
cpu_and_wall_time_worker_state *state;
|
|
1111
1296
|
TypedData_Get_Struct(instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
|
1112
1297
|
reset_stats_not_thread_safe(state);
|
|
1298
|
+
thread_context_collector_stats_reset_not_thread_safe(state->thread_context_collector_instance);
|
|
1113
1299
|
return Qnil;
|
|
1114
1300
|
}
|
|
1115
1301
|
|
|
@@ -1119,11 +1305,19 @@ void *simulate_sampling_signal_delivery(DDTRACE_UNUSED void *_unused) {
|
|
|
1119
1305
|
// This can potentially happen if the CpuAndWallTimeWorker was stopped while the IdleSamplingHelper was trying to execute this action
|
|
1120
1306
|
if (state == NULL) return NULL;
|
|
1121
1307
|
|
|
1308
|
+
// Since this is not a real signal firing, we need to block SIGPROF delivery on this thread to avoid an actual SIGPROF
|
|
1309
|
+
// signal coming in nested and interrupting us on this thread. Thus we respect the invariant of "no nesting" for `handle_sampling_signal`.
|
|
1310
|
+
//
|
|
1311
|
+
// Not needed when `no_signals_workaround_enabled` is set: no SIGPROFs are ever sent in that mode, so there's nothing to mask.
|
|
1312
|
+
if (!state->no_signals_workaround_enabled) block_sigprof_signal_handler_from_running_in_current_thread();
|
|
1313
|
+
|
|
1122
1314
|
state->stats.simulated_signal_delivery++;
|
|
1123
1315
|
|
|
1124
1316
|
// `handle_sampling_signal` does a few things extra on top of `sample_from_postponed_job` so that's why we don't shortcut here
|
|
1125
1317
|
handle_sampling_signal(0, NULL, NULL);
|
|
1126
1318
|
|
|
1319
|
+
if (!state->no_signals_workaround_enabled) unblock_sigprof_signal_handler_from_running_in_current_thread();
|
|
1320
|
+
|
|
1127
1321
|
return NULL; // Unused
|
|
1128
1322
|
}
|
|
1129
1323
|
|
|
@@ -1136,11 +1330,13 @@ static void reset_stats_not_thread_safe(cpu_and_wall_time_worker_state *state) {
|
|
|
1136
1330
|
// * Included in the following stats window (writes after stats retrieval and reset).
|
|
1137
1331
|
// Given the expected infrequency of resetting (~once per 60s profile) and the auxiliary/non-critical nature of these stats
|
|
1138
1332
|
// this momentary loss of accuracy is deemed acceptable to keep overhead to a minimum.
|
|
1333
|
+
|
|
1139
1334
|
state->stats = (struct stats) {
|
|
1140
1335
|
// All these values are initialized to their highest value possible since we always take the min between existing and latest sample
|
|
1141
1336
|
.cpu_sampling_time_ns_min = UINT64_MAX,
|
|
1142
1337
|
.allocation_sampling_time_ns_min = UINT64_MAX,
|
|
1143
1338
|
.gvl_sampling_time_ns_min = UINT64_MAX,
|
|
1339
|
+
// Other fields are reset to 0
|
|
1144
1340
|
};
|
|
1145
1341
|
}
|
|
1146
1342
|
|
|
@@ -1170,18 +1366,12 @@ static VALUE _native_allocation_count(DDTRACE_UNUSED VALUE self) {
|
|
|
1170
1366
|
return are_allocations_being_tracked ? ULL2NUM(allocation_count) : Qnil;
|
|
1171
1367
|
}
|
|
1172
1368
|
|
|
1173
|
-
#define HANDLE_CLOCK_FAILURE(call) ({ \
|
|
1174
|
-
long _result = (call); \
|
|
1175
|
-
if (_result == 0) { \
|
|
1176
|
-
delayed_error_clock_failure(state); \
|
|
1177
|
-
return; \
|
|
1178
|
-
} \
|
|
1179
|
-
_result; \
|
|
1180
|
-
})
|
|
1181
|
-
|
|
1182
1369
|
// Implements memory-related profiling events. This function is called by Ruby via the `rb_add_event_hook2`
|
|
1183
1370
|
// when the RUBY_INTERNAL_EVENT_NEWOBJ event is triggered.
|
|
1184
1371
|
//
|
|
1372
|
+
// This function is called from the RUBY_INTERNAL_EVENT_NEWOBJ tracepoint so it should neither allocate in the
|
|
1373
|
+
// Ruby heap nor release the GVL (https://github.com/DataDog/dd-trace-rb/pull/4240).
|
|
1374
|
+
//
|
|
1185
1375
|
// When allocation sampling is enabled, this function gets called for almost all* objects allocated by the Ruby VM.
|
|
1186
1376
|
// (*In some weird cases the VM may skip this tracepoint.)
|
|
1187
1377
|
//
|
|
@@ -1218,13 +1408,22 @@ static void on_newobj_event(DDTRACE_UNUSED VALUE unused1, DDTRACE_UNUSED void *u
|
|
|
1218
1408
|
return;
|
|
1219
1409
|
}
|
|
1220
1410
|
|
|
1411
|
+
VALUE current_thread = rb_thread_current();
|
|
1412
|
+
|
|
1221
1413
|
// If Ruby is in the middle of raising an exception, we don't want to try to sample. This is because if we accidentally
|
|
1222
1414
|
// trigger an exception inside the profiler code, bad things will happen (specifically, Ruby will try to kill off the
|
|
1223
1415
|
// thread even though we may try to catch the exception).
|
|
1224
1416
|
//
|
|
1225
1417
|
// Note that "in the middle of raising an exception" means the exception itself has already been allocated.
|
|
1226
1418
|
// What's getting allocated now is probably the backtrace objects (@ivoanjo or at least that's what I've observed)
|
|
1227
|
-
if (is_raised_flag_set(
|
|
1419
|
+
if (is_raised_flag_set(current_thread)) {
|
|
1420
|
+
return;
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
per_thread_context *thread_context = get_per_thread_context(current_thread);
|
|
1424
|
+
if (!thread_context) {
|
|
1425
|
+
// Context is created eagerly via on_thread_begin_event, so this should not normally be NULL.
|
|
1426
|
+
// We keep the guard since we can't allocate here (inside on_newobj_event).
|
|
1228
1427
|
return;
|
|
1229
1428
|
}
|
|
1230
1429
|
|
|
@@ -1232,16 +1431,13 @@ static void on_newobj_event(DDTRACE_UNUSED VALUE unused1, DDTRACE_UNUSED void *u
|
|
|
1232
1431
|
if (RB_LIKELY(state->dynamic_sampling_rate_enabled && !discrete_dynamic_sampler_should_sample(&state->allocation_sampler))) {
|
|
1233
1432
|
state->stats.allocation_skipped++;
|
|
1234
1433
|
|
|
1235
|
-
|
|
1236
|
-
HANDLE_CLOCK_FAILURE(now.timestamp_ns);
|
|
1237
|
-
|
|
1238
|
-
bool needs_readjust = discrete_dynamic_sampler_skipped_sample(&state->allocation_sampler, now);
|
|
1434
|
+
bool needs_readjust = discrete_dynamic_sampler_skipped_sample(&state->allocation_sampler, monotonic_coarse_wall_time_now_ns());
|
|
1239
1435
|
if (RB_UNLIKELY(needs_readjust)) {
|
|
1240
1436
|
// We rarely readjust, so this is a cold path
|
|
1241
1437
|
// Also, while above we used the cheaper monotonic_coarse, for this call we want the regular monotonic call,
|
|
1242
1438
|
// which is why we end up getting time "again".
|
|
1243
1439
|
discrete_dynamic_sampler_readjust(
|
|
1244
|
-
&state->allocation_sampler,
|
|
1440
|
+
&state->allocation_sampler, monotonic_wall_time_now_ns()
|
|
1245
1441
|
);
|
|
1246
1442
|
}
|
|
1247
1443
|
|
|
@@ -1251,7 +1447,7 @@ static void on_newobj_event(DDTRACE_UNUSED VALUE unused1, DDTRACE_UNUSED void *u
|
|
|
1251
1447
|
// From here on, we've decided to go ahead with the sample, which is way less common than skipping it
|
|
1252
1448
|
|
|
1253
1449
|
discrete_dynamic_sampler_before_sample(
|
|
1254
|
-
&state->allocation_sampler,
|
|
1450
|
+
&state->allocation_sampler, monotonic_wall_time_now_ns()
|
|
1255
1451
|
);
|
|
1256
1452
|
|
|
1257
1453
|
during_sample_enter(state);
|
|
@@ -1259,18 +1455,13 @@ static void on_newobj_event(DDTRACE_UNUSED VALUE unused1, DDTRACE_UNUSED void *u
|
|
|
1259
1455
|
// Rescue against any exceptions that happen during sampling
|
|
1260
1456
|
safely_call(
|
|
1261
1457
|
rescued_sample_allocation,
|
|
1262
|
-
|
|
1458
|
+
(VALUE) thread_context,
|
|
1263
1459
|
state->self_instance,
|
|
1264
1460
|
handle_sampling_failure_rescued_sample_allocation
|
|
1265
1461
|
);
|
|
1266
1462
|
|
|
1267
1463
|
if (state->dynamic_sampling_rate_enabled) {
|
|
1268
|
-
|
|
1269
|
-
if (now == 0) {
|
|
1270
|
-
delayed_error_clock_failure(state);
|
|
1271
|
-
// NOTE: Not short-circuiting here to make sure cleanup happens
|
|
1272
|
-
}
|
|
1273
|
-
uint64_t sampling_time_ns = discrete_dynamic_sampler_after_sample(&state->allocation_sampler, now);
|
|
1464
|
+
uint64_t sampling_time_ns = discrete_dynamic_sampler_after_sample(&state->allocation_sampler, monotonic_wall_time_now_ns());
|
|
1274
1465
|
// NOTE: To keep things lean when dynamic sampling rate is disabled we skip clock interactions which is
|
|
1275
1466
|
// why we're fine with having this inside this conditional.
|
|
1276
1467
|
state->stats.allocation_sampling_time_ns_min = uint64_min_of(sampling_time_ns, state->stats.allocation_sampling_time_ns_min);
|
|
@@ -1283,7 +1474,7 @@ static void on_newobj_event(DDTRACE_UNUSED VALUE unused1, DDTRACE_UNUSED void *u
|
|
|
1283
1474
|
during_sample_exit(state);
|
|
1284
1475
|
}
|
|
1285
1476
|
|
|
1286
|
-
static void
|
|
1477
|
+
static void disable_hooks(cpu_and_wall_time_worker_state *state) {
|
|
1287
1478
|
if (state->gc_tracepoint != Qnil) {
|
|
1288
1479
|
rb_tracepoint_disable(state->gc_tracepoint);
|
|
1289
1480
|
}
|
|
@@ -1311,7 +1502,8 @@ static VALUE _native_with_blocked_sigprof(DDTRACE_UNUSED VALUE self) {
|
|
|
1311
1502
|
}
|
|
1312
1503
|
}
|
|
1313
1504
|
|
|
1314
|
-
static VALUE rescued_sample_allocation(
|
|
1505
|
+
static VALUE rescued_sample_allocation(VALUE arg) {
|
|
1506
|
+
per_thread_context *thread_context = (per_thread_context*) arg;
|
|
1315
1507
|
cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
|
|
1316
1508
|
|
|
1317
1509
|
// This should not happen in a normal situation because on_newobj_event already checked for this, but just in case...
|
|
@@ -1330,18 +1522,18 @@ static VALUE rescued_sample_allocation(DDTRACE_UNUSED VALUE unused) {
|
|
|
1330
1522
|
// To control bias from sampling, we clamp the maximum weight attributed to a single allocation sample. This avoids
|
|
1331
1523
|
// assigning a very large number to a sample, if for instance the dynamic sampling mechanism chose a really big interval.
|
|
1332
1524
|
unsigned int weight = allocations_since_last_sample > MAX_ALLOC_WEIGHT ? MAX_ALLOC_WEIGHT : (unsigned int) allocations_since_last_sample;
|
|
1333
|
-
bool
|
|
1525
|
+
bool needs_commit = thread_context_collector_sample_allocation(state->thread_context_collector_instance, thread_context, weight, new_object);
|
|
1334
1526
|
// ...but we still represent the skipped samples in the profile, thus the data will account for all allocations.
|
|
1335
1527
|
if (weight < allocations_since_last_sample) {
|
|
1336
1528
|
uint32_t skipped_samples = (uint32_t) uint64_min_of(allocations_since_last_sample - weight, UINT32_MAX);
|
|
1337
1529
|
thread_context_collector_sample_skipped_allocation_samples(state->thread_context_collector_instance, skipped_samples);
|
|
1338
1530
|
}
|
|
1339
1531
|
|
|
1340
|
-
if (
|
|
1532
|
+
if (needs_commit) {
|
|
1341
1533
|
#ifndef NO_POSTPONED_TRIGGER
|
|
1342
|
-
rb_postponed_job_trigger(
|
|
1534
|
+
rb_postponed_job_trigger(commit_heap_recordings_from_postponed_job_may_lose_gvl_handle);
|
|
1343
1535
|
#else
|
|
1344
|
-
|
|
1536
|
+
rb_postponed_job_register_one(0, commit_heap_recordings_from_postponed_job_may_lose_gvl, NULL);
|
|
1345
1537
|
#endif
|
|
1346
1538
|
}
|
|
1347
1539
|
|
|
@@ -1354,11 +1546,6 @@ static void delayed_error(cpu_and_wall_time_worker_state *state, const char *err
|
|
|
1354
1546
|
stop_state(state, rb_exc_new_cstr(rb_eRuntimeError, error), "delayed_error");
|
|
1355
1547
|
}
|
|
1356
1548
|
|
|
1357
|
-
static void delayed_error_clock_failure(cpu_and_wall_time_worker_state *state) {
|
|
1358
|
-
// If we can't raise an immediate exception at the calling site, use the asynchronous flow through the main worker loop.
|
|
1359
|
-
stop_state(state, rb_exc_new_cstr(clock_failure_exception_class, "failed to get clock time"), "delayed_error_clock_failure");
|
|
1360
|
-
}
|
|
1361
|
-
|
|
1362
1549
|
static VALUE _native_delayed_error(DDTRACE_UNUSED VALUE self, VALUE instance, VALUE error_msg) {
|
|
1363
1550
|
ENFORCE_TYPE(error_msg, T_STRING);
|
|
1364
1551
|
|
|
@@ -1387,44 +1574,73 @@ static VALUE _native_resume_signals(DDTRACE_UNUSED VALUE self) {
|
|
|
1387
1574
|
#ifndef NO_GVL_INSTRUMENTATION
|
|
1388
1575
|
static void on_gvl_event(rb_event_flag_t event_id, const rb_internal_thread_event_data_t *event_data, DDTRACE_UNUSED void *_unused) {
|
|
1389
1576
|
// Be very careful about touching the `state` here or doing anything at all:
|
|
1390
|
-
// This function gets called without the GVL, and potentially from
|
|
1577
|
+
// This function gets called without the GVL, and potentially from non-main Ractors!
|
|
1391
1578
|
//
|
|
1392
|
-
//
|
|
1393
|
-
//
|
|
1394
|
-
|
|
1579
|
+
// Note, even though these events can get called without the GVL, they synchronize-with enabling/disabling of
|
|
1580
|
+
// the hook that calls us using a read-write lock. Thus, disabling the hook cannot be concurrent with calling this function,
|
|
1581
|
+
// and once the disable finishes there can't be "late" calls into this function.
|
|
1582
|
+
|
|
1583
|
+
// The thread that this event is about may not be the current thread
|
|
1584
|
+
// (as documented on rb_internal_thread_add_event_hook(), and this is notably the case for READY on Ruby 4.0),
|
|
1585
|
+
// so be careful with native thread locals that are not directly tied to the thread object and the like.
|
|
1395
1586
|
|
|
1396
|
-
|
|
1397
|
-
|
|
1587
|
+
#ifdef HAVE_RUBY_THREAD_STORAGE_API
|
|
1588
|
+
VALUE target_thread = event_data->thread;
|
|
1589
|
+
#else
|
|
1590
|
+
// On Ruby 3.2 the event does not carry the thread, but all events fire on the thread itself.
|
|
1591
|
+
// However, during early thread startup rb_thread_current() can crash because the execution context (Fiber) isn't
|
|
1592
|
+
// stored in TLS yet; ruby_native_thread_p() guards against this.
|
|
1593
|
+
if (!ruby_native_thread_p()) return;
|
|
1594
|
+
VALUE target_thread = rb_thread_current();
|
|
1595
|
+
#endif
|
|
1596
|
+
|
|
1597
|
+
// TODO: `rb_internal_thread_specific_get` is documented as "async and native thread safe.",
|
|
1598
|
+
// unclear if that holds during GC compaction.
|
|
1599
|
+
per_thread_context* thread_context = get_per_thread_context(target_thread);
|
|
1600
|
+
if (!thread_context) return;
|
|
1601
|
+
// If non-NULL the thread is profiled and from the main Ractor
|
|
1602
|
+
|
|
1603
|
+
if (event_id == RUBY_INTERNAL_THREAD_EVENT_SUSPENDED) { /* released gvl */
|
|
1604
|
+
thread_context_collector_on_gvl_released(thread_context);
|
|
1605
|
+
} else if (event_id == RUBY_INTERNAL_THREAD_EVENT_READY) { /* waiting for gvl */
|
|
1606
|
+
thread_context_collector_on_gvl_waiting(thread_context);
|
|
1398
1607
|
} else if (event_id == RUBY_INTERNAL_THREAD_EVENT_RESUMED) { /* running/runnable */
|
|
1399
|
-
//
|
|
1400
|
-
//
|
|
1608
|
+
// We must only use async-signal-safe functions here and not call arbitrary Ruby APIs and not allocate!
|
|
1609
|
+
// One might assume RUBY_INTERNAL_THREAD_EVENT_RESUMED means having the GVL and running that thread.
|
|
1610
|
+
// However, the reality is more complicated (https://bugs.ruby-lang.org/issues/22098),
|
|
1611
|
+
// it only "sort of" has the GVL but not fully, and it's called while holding the scheduler lock,
|
|
1612
|
+
// so we do as little work as possible here, and perform the sample in a postponed_job.
|
|
1613
|
+
cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
|
|
1614
|
+
if (state == NULL) return; // This should not happen, but just in case...
|
|
1615
|
+
|
|
1616
|
+
// on_gvl_running prepares a stack sample so we need to gate it with `during_sample_enter` to avoid a
|
|
1617
|
+
// SIGPROF signal coming in during that function and potentially causing a corrupted final state.
|
|
1401
1618
|
//
|
|
1402
|
-
//
|
|
1403
|
-
//
|
|
1404
|
-
//
|
|
1619
|
+
// TODO: Currently, the sample prepared in on_gvl_running can still be clobbered if the signal handler runs
|
|
1620
|
+
// after `during_sample_exit` but before `after_gvl_running_from_postponed_job` gets to run. We'll need to fix
|
|
1621
|
+
// that next.
|
|
1622
|
+
during_sample_enter(state);
|
|
1405
1623
|
|
|
1406
|
-
|
|
1407
|
-
target_thread
|
|
1408
|
-
|
|
1624
|
+
on_gvl_running_result result =
|
|
1625
|
+
thread_context_collector_on_gvl_running(target_thread, thread_context, state->waiting_for_gvl_threshold_ns);
|
|
1626
|
+
|
|
1627
|
+
during_sample_exit(state);
|
|
1409
1628
|
|
|
1410
|
-
|
|
1629
|
+
if (result.waiting_for_gvl_duration_ns > 0) {
|
|
1630
|
+
state->stats.vm_metrics.gvl_waiting_time_ns_total += (uint64_t) result.waiting_for_gvl_duration_ns;
|
|
1631
|
+
}
|
|
1411
1632
|
|
|
1412
|
-
if (result == ON_GVL_RUNNING_SAMPLE) {
|
|
1633
|
+
if (result.action == ON_GVL_RUNNING_SAMPLE) {
|
|
1413
1634
|
#ifndef NO_POSTPONED_TRIGGER
|
|
1414
1635
|
rb_postponed_job_trigger(after_gvl_running_from_postponed_job_handle);
|
|
1415
1636
|
#else
|
|
1416
1637
|
rb_postponed_job_register_one(0, after_gvl_running_from_postponed_job, NULL);
|
|
1417
1638
|
#endif
|
|
1418
|
-
} else if (result == ON_GVL_RUNNING_DONT_SAMPLE) {
|
|
1419
|
-
cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
|
|
1420
|
-
|
|
1421
|
-
if (state == NULL) return; // This should not happen, but just in case...
|
|
1422
|
-
|
|
1639
|
+
} else if (result.action == ON_GVL_RUNNING_DONT_SAMPLE) {
|
|
1423
1640
|
state->stats.gvl_dont_sample++;
|
|
1424
1641
|
}
|
|
1425
1642
|
} else {
|
|
1426
|
-
|
|
1427
|
-
fprintf(stderr, "[ddtrace] Unexpected value in on_gvl_event (%d)\n", event_id);
|
|
1643
|
+
rb_bug("[ddtrace] Unexpected value in on_gvl_event (%d)\n", event_id);
|
|
1428
1644
|
}
|
|
1429
1645
|
}
|
|
1430
1646
|
|
|
@@ -1451,14 +1667,15 @@ static VALUE _native_resume_signals(DDTRACE_UNUSED VALUE self) {
|
|
|
1451
1667
|
cpu_and_wall_time_worker_state *state;
|
|
1452
1668
|
TypedData_Get_Struct(self_instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
|
1453
1669
|
|
|
1454
|
-
long wall_time_ns_before_sample = monotonic_wall_time_now_ns(
|
|
1670
|
+
long wall_time_ns_before_sample = monotonic_wall_time_now_ns();
|
|
1455
1671
|
thread_context_collector_sample_after_gvl_running(state->thread_context_collector_instance, rb_thread_current(), wall_time_ns_before_sample);
|
|
1456
|
-
long wall_time_ns_after_sample = monotonic_wall_time_now_ns(
|
|
1672
|
+
long wall_time_ns_after_sample = monotonic_wall_time_now_ns();
|
|
1457
1673
|
|
|
1458
|
-
|
|
1674
|
+
if (wall_time_ns_after_sample < wall_time_ns_before_sample) {
|
|
1675
|
+
raise_error(rb_eRuntimeError, "BUG: Unexpected wall time going backwards when tracking overhead");
|
|
1676
|
+
}
|
|
1459
1677
|
|
|
1460
|
-
|
|
1461
|
-
uint64_t sampling_time_ns = delta_ns < 0 ? 0 : delta_ns;
|
|
1678
|
+
uint64_t sampling_time_ns = wall_time_ns_after_sample - wall_time_ns_before_sample;
|
|
1462
1679
|
|
|
1463
1680
|
state->stats.gvl_sampling_time_ns_min = uint64_min_of(sampling_time_ns, state->stats.gvl_sampling_time_ns_min);
|
|
1464
1681
|
state->stats.gvl_sampling_time_ns_max = uint64_max_of(sampling_time_ns, state->stats.gvl_sampling_time_ns_max);
|
|
@@ -1496,54 +1713,54 @@ static VALUE handle_sampling_failure_thread_context_collector_sample_after_gc(VA
|
|
|
1496
1713
|
return Qnil;
|
|
1497
1714
|
}
|
|
1498
1715
|
|
|
1716
|
+
static VALUE handle_sampling_failure_thread_context_collector_heap_update(VALUE self_instance, VALUE exception) {
|
|
1717
|
+
stop(self_instance, exception, "thread_context_collector_heap_update_may_lose_gvl");
|
|
1718
|
+
return Qnil;
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1499
1721
|
static VALUE handle_sampling_failure_rescued_sample_allocation(VALUE self_instance, VALUE exception) {
|
|
1500
1722
|
stop(self_instance, exception, "rescued_sample_allocation");
|
|
1501
1723
|
return Qnil;
|
|
1502
1724
|
}
|
|
1503
1725
|
|
|
1504
|
-
static VALUE
|
|
1505
|
-
stop(self_instance, exception, "
|
|
1726
|
+
static VALUE handle_sampling_failure_rescued_commit_heap_recordings(VALUE self_instance, VALUE exception) {
|
|
1727
|
+
stop(self_instance, exception, "rescued_commit_heap_recordings_may_lose_gvl");
|
|
1506
1728
|
return Qnil;
|
|
1507
1729
|
}
|
|
1508
1730
|
|
|
1509
|
-
static VALUE
|
|
1731
|
+
static VALUE rescued_commit_heap_recordings_may_lose_gvl(VALUE self_instance) {
|
|
1510
1732
|
cpu_and_wall_time_worker_state *state;
|
|
1511
1733
|
TypedData_Get_Struct(self_instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
|
1512
1734
|
|
|
1513
|
-
|
|
1735
|
+
thread_context_collector_commit_heap_recordings_may_lose_gvl(state->thread_context_collector_instance);
|
|
1514
1736
|
|
|
1515
1737
|
// Return a dummy VALUE because we're called from rb_rescue2 which requires it
|
|
1516
1738
|
return Qnil;
|
|
1517
1739
|
}
|
|
1518
1740
|
|
|
1519
|
-
// This postponed job callback is used to
|
|
1520
|
-
// During on_newobj_event,
|
|
1521
|
-
//
|
|
1522
|
-
|
|
1523
|
-
#pragma GCC diagnostic ignored "-Wunused-function" // This is only used for some Rubies, but we want to build on all to make it easier to dev
|
|
1524
|
-
static void after_allocation_from_postponed_job(DDTRACE_UNUSED void *_unused) {
|
|
1741
|
+
// This postponed job callback is used to commit heap allocation recordings.
|
|
1742
|
+
// During on_newobj_event, we can't take the weak reference the heap recorder needs to track the object, so we defer
|
|
1743
|
+
// that until after the event completes.
|
|
1744
|
+
static void commit_heap_recordings_from_postponed_job_may_lose_gvl(DDTRACE_UNUSED void *_unused) {
|
|
1525
1745
|
cpu_and_wall_time_worker_state *state = active_sampler_instance_state;
|
|
1526
1746
|
|
|
1527
1747
|
if (state == NULL || !ddtrace_rb_ractor_main_p()) return;
|
|
1528
1748
|
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1749
|
+
if (state->during_sample) {
|
|
1750
|
+
delayed_error(state, "commit_heap_recordings_from_postponed_job_may_lose_gvl called during_sample");
|
|
1751
|
+
return;
|
|
1752
|
+
}
|
|
1533
1753
|
|
|
1534
1754
|
// NOTE: We're not updating the allocation_sampler here.
|
|
1535
1755
|
// This means work done in this function isn't accounted for as profiler overhead.
|
|
1536
1756
|
// This is acceptable as the amount of work done here is expected to be small.
|
|
1537
1757
|
safely_call(
|
|
1538
|
-
|
|
1758
|
+
rescued_commit_heap_recordings_may_lose_gvl,
|
|
1539
1759
|
state->self_instance,
|
|
1540
1760
|
state->self_instance,
|
|
1541
|
-
|
|
1761
|
+
handle_sampling_failure_rescued_commit_heap_recordings
|
|
1542
1762
|
);
|
|
1543
|
-
|
|
1544
|
-
during_sample_exit(state);
|
|
1545
1763
|
}
|
|
1546
|
-
#pragma GCC diagnostic pop
|
|
1547
1764
|
|
|
1548
1765
|
static inline void during_sample_enter(cpu_and_wall_time_worker_state* state) {
|
|
1549
1766
|
// Tell the compiler it's not allowed to reorder the `during_sample` flag with anything that happens after.
|