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
|
@@ -2,42 +2,48 @@
|
|
|
2
2
|
|
|
3
3
|
// This file exports functions used to access private Ruby VM APIs and internals.
|
|
4
4
|
// To do this, it imports a few VM internal (private) headers.
|
|
5
|
+
// We rely on the datadog-ruby_core_source gem to get access to private VM headers; see
|
|
6
|
+
// https://github.com/DataDog/datadog-ruby_core_source for details.
|
|
5
7
|
//
|
|
6
8
|
// **Important Note**: Our medium/long-term plan is to stop relying on all private Ruby headers, and instead request and
|
|
7
9
|
// contribute upstream changes so that they become official public VM APIs.
|
|
8
10
|
//
|
|
9
11
|
// In the meanwhile, be very careful when changing things here :)
|
|
10
12
|
|
|
11
|
-
#
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
#include <ruby/defines.h>
|
|
14
|
+
|
|
15
|
+
// We can't do anything about warnings in VM headers, so we just use this technique to suppress them.
|
|
16
|
+
// See https://nelkinda.com/blog/suppress-warnings-in-gcc-and-clang/#d11e364 for details.
|
|
17
|
+
#pragma GCC diagnostic push
|
|
18
|
+
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
|
19
|
+
#pragma GCC diagnostic ignored "-Wattributes"
|
|
20
|
+
#pragma GCC diagnostic ignored "-Wpragmas"
|
|
21
|
+
#pragma GCC diagnostic ignored "-Wexpansion-to-defined"
|
|
22
|
+
#include <vm_core.h>
|
|
23
|
+
#pragma GCC diagnostic pop
|
|
24
|
+
|
|
25
|
+
#pragma GCC diagnostic push
|
|
26
|
+
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
|
27
|
+
#include <iseq.h>
|
|
28
|
+
#ifdef HAVE_ZJIT_FRAME
|
|
29
|
+
#include <zjit.h>
|
|
30
|
+
#endif
|
|
31
|
+
#pragma GCC diagnostic pop
|
|
17
32
|
|
|
18
|
-
|
|
19
|
-
// See https://nelkinda.com/blog/suppress-warnings-in-gcc-and-clang/#d11e364 for details.
|
|
33
|
+
#ifndef NO_INTERNAL_CLASS_HEADER_INCLUDE
|
|
20
34
|
#pragma GCC diagnostic push
|
|
21
35
|
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
|
22
|
-
|
|
23
|
-
#pragma GCC diagnostic ignored "-Wpragmas"
|
|
24
|
-
#pragma GCC diagnostic ignored "-Wexpansion-to-defined"
|
|
25
|
-
#include <vm_core.h>
|
|
36
|
+
#include <internal/class.h>
|
|
26
37
|
#pragma GCC diagnostic pop
|
|
38
|
+
#endif
|
|
39
|
+
|
|
40
|
+
#include <ruby.h>
|
|
27
41
|
|
|
42
|
+
#ifndef NO_RACTOR_HEADER_INCLUDE
|
|
28
43
|
#pragma GCC diagnostic push
|
|
29
44
|
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
|
30
|
-
#include <
|
|
45
|
+
#include <ractor_core.h>
|
|
31
46
|
#pragma GCC diagnostic pop
|
|
32
|
-
|
|
33
|
-
#include <ruby.h>
|
|
34
|
-
|
|
35
|
-
#ifndef NO_RACTOR_HEADER_INCLUDE
|
|
36
|
-
#pragma GCC diagnostic push
|
|
37
|
-
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
|
38
|
-
#include <ractor_core.h>
|
|
39
|
-
#pragma GCC diagnostic pop
|
|
40
|
-
#endif
|
|
41
47
|
#endif
|
|
42
48
|
|
|
43
49
|
// This file can't include datadog_ruby_common.h so we replicate this here
|
|
@@ -50,18 +56,45 @@
|
|
|
50
56
|
#define PRIVATE_VM_API_ACCESS_SKIP_RUBY_INCLUDES
|
|
51
57
|
#include "private_vm_api_access.h"
|
|
52
58
|
|
|
59
|
+
#ifdef HAVE_RUBY_RACTOR_H
|
|
60
|
+
typedef rb_ractor_t gvl_owner_context_t;
|
|
61
|
+
#else
|
|
62
|
+
typedef rb_vm_t gvl_owner_context_t;
|
|
63
|
+
#endif
|
|
64
|
+
|
|
65
|
+
static inline const rb_callable_method_entry_t* get_cfunc_method_entry(const rb_control_frame_t *cfp);
|
|
66
|
+
static const rb_callable_method_entry_t* safe_vm_frame_method_entry(const rb_control_frame_t *cfp);
|
|
67
|
+
static gvl_owner_context_t *get_gvl_owner_context(void);
|
|
68
|
+
|
|
69
|
+
typedef struct {
|
|
70
|
+
gvl_owner_context_t *main_ractor_gvl_owner_context;
|
|
71
|
+
const rb_data_type_t *thread_data_type;
|
|
72
|
+
} private_vm_api_global_t;
|
|
73
|
+
|
|
74
|
+
// Initialized once on the main ractor with the GVL held, before sampling starts; never rewritten.
|
|
75
|
+
// The native context stays at the same address across GC compaction and forks from the main ractor.
|
|
76
|
+
static private_vm_api_global_t private_vm_api_global;
|
|
77
|
+
|
|
78
|
+
void private_vm_api_access_init(void) {
|
|
79
|
+
private_vm_api_global.thread_data_type = RTYPEDDATA_TYPE(rb_thread_current());
|
|
80
|
+
private_vm_api_global.main_ractor_gvl_owner_context = get_gvl_owner_context();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
void private_vm_api_access_self_test(void) {
|
|
84
|
+
if (private_vm_api_global.main_ractor_gvl_owner_context != get_gvl_owner_context()) {
|
|
85
|
+
rb_raise(rb_eRuntimeError, "BUG: main_ractor_gvl_owner_context changed unexpectedly");
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
53
89
|
// MRI has a similar rb_thread_ptr() function which we can't call it directly
|
|
54
90
|
// because Ruby does not expose the thread_data_type publicly.
|
|
55
|
-
// Instead, we have our own version of that function, and we
|
|
91
|
+
// Instead, we have our own version of that function, and we initialize the thread_data_type pointer
|
|
56
92
|
// from a known-correct object: the current thread.
|
|
57
93
|
//
|
|
58
94
|
// Note that beyond returning the rb_thread_struct*, rb_check_typeddata() raises an exception
|
|
59
95
|
// if the argument passed in is not actually a `Thread` instance.
|
|
60
96
|
static inline rb_thread_t *thread_struct_from_object(VALUE thread) {
|
|
61
|
-
|
|
62
|
-
if (UNLIKELY(thread_data_type == NULL)) thread_data_type = RTYPEDDATA_TYPE(rb_thread_current());
|
|
63
|
-
|
|
64
|
-
return (rb_thread_t *) rb_check_typeddata(thread, thread_data_type);
|
|
97
|
+
return (rb_thread_t *) rb_check_typeddata(thread, private_vm_api_global.thread_data_type);
|
|
65
98
|
}
|
|
66
99
|
|
|
67
100
|
rb_nativethread_id_t pthread_id_for(VALUE thread) {
|
|
@@ -69,123 +102,131 @@ rb_nativethread_id_t pthread_id_for(VALUE thread) {
|
|
|
69
102
|
#ifndef NO_RB_NATIVE_THREAD
|
|
70
103
|
struct rb_native_thread* native_thread = thread_struct_from_object(thread)->nt;
|
|
71
104
|
// This can be NULL on Ruby 3.3 with MN threads (RUBY_MN_THREADS=1)
|
|
72
|
-
if (native_thread == NULL)
|
|
105
|
+
if (native_thread == NULL) {
|
|
106
|
+
return 0;
|
|
107
|
+
}
|
|
73
108
|
return native_thread->thread_id;
|
|
74
109
|
#else
|
|
75
110
|
return thread_struct_from_object(thread)->thread_id;
|
|
76
111
|
#endif
|
|
77
112
|
}
|
|
78
113
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
VALUE ddtrace_iseq_base_label(const void *iseq) {
|
|
84
|
-
return rb_iseq_base_label((const rb_iseq_t *)iseq);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
VALUE ddtrace_iseq_path(const void *iseq) {
|
|
88
|
-
return rb_iseq_path((const rb_iseq_t *)iseq);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Queries if the current thread is the owner of the global VM lock.
|
|
114
|
+
// Combines checking for main ractor and GVL in one check that can be done safely from a signal handler, even
|
|
115
|
+
// if the thread is not a Ruby thread or if we're in the middle of GC.
|
|
92
116
|
//
|
|
93
|
-
//
|
|
94
|
-
//
|
|
95
|
-
//
|
|
96
|
-
// will have the GVL which is probably true for the situations that API was designed to be called from BUT this assumption
|
|
97
|
-
// does not hold true when calling `ruby_thread_has_gvl_p` from a signal handler. (Because the thread may have lost the
|
|
98
|
-
// GVL due to a scheduler decision, not because it decided to block.)
|
|
99
|
-
// I have also submitted https://bugs.ruby-lang.org/issues/19172 to discuss this with upstream Ruby developers.
|
|
117
|
+
// Note that Ruby has `ruby_thread_has_gvl_p`, but unfortunately it can return true in a signal
|
|
118
|
+
// handler even when the thread doesn't hold the GVL. It assumes that a thread outside a "blocking region" holds
|
|
119
|
+
// the GVL, but the scheduler can also take it away (https://bugs.ruby-lang.org/issues/19172).
|
|
100
120
|
//
|
|
101
|
-
//
|
|
102
|
-
bool
|
|
103
|
-
current_gvl_owner owner =
|
|
121
|
+
// This must not touch Ruby objects, since GC compaction may have protected their heap pages.
|
|
122
|
+
bool is_current_thread_in_main_ractor_and_holding_the_gvl(void) {
|
|
123
|
+
current_gvl_owner owner = main_ractor_gvl_owner();
|
|
104
124
|
return owner.valid && pthread_equal(pthread_self(), owner.owner);
|
|
105
125
|
}
|
|
106
126
|
|
|
107
127
|
#ifdef HAVE_RUBY_RACTOR_H
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
128
|
+
static inline rb_ractor_t *ddtrace_get_ractor(void) {
|
|
129
|
+
#ifndef USE_RACTOR_INTERNAL_APIS_DIRECTLY // Ruby >= 3.3
|
|
130
|
+
return thread_struct_from_object(rb_thread_current())->ractor;
|
|
131
|
+
#else
|
|
132
|
+
return GET_RACTOR();
|
|
133
|
+
#endif
|
|
134
|
+
}
|
|
115
135
|
#endif
|
|
116
136
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
// * In the case where a thread owns the GVL and calls `gvl_owner`, it will always see the correct value. That's
|
|
122
|
-
// because every thread sets itself as the owner when it grabs the GVL and unsets itself at the end.
|
|
123
|
-
// That means that `is_current_thread_holding_the_gvl` is always accurate.
|
|
124
|
-
// * In a case where we observe a different thread, then this may change by the time we do something with this value
|
|
125
|
-
// anyway. So unless we want to prevent the Ruby scheduler from switching threads, we need to deal with races here.
|
|
126
|
-
current_gvl_owner gvl_owner(void) {
|
|
127
|
-
const rb_thread_t *current_owner =
|
|
128
|
-
#ifndef NO_RB_THREAD_SCHED // Introduced in Ruby 3.2 as a replacement for struct rb_global_vm_lock_struct
|
|
129
|
-
ddtrace_get_ractor()->threads.sched.running;
|
|
130
|
-
#elif HAVE_RUBY_RACTOR_H
|
|
131
|
-
ddtrace_get_ractor()->threads.gvl.owner;
|
|
132
|
-
#else
|
|
133
|
-
GET_VM()->gvl.owner;
|
|
134
|
-
#endif
|
|
135
|
-
|
|
136
|
-
if (current_owner == NULL) return (current_gvl_owner) {.valid = false};
|
|
137
|
-
|
|
138
|
-
#ifndef NO_RB_NATIVE_THREAD
|
|
139
|
-
struct rb_native_thread* current_owner_native_thread = current_owner->nt;
|
|
137
|
+
static gvl_owner_context_t *get_gvl_owner_context(void) {
|
|
138
|
+
if (!ddtrace_rb_ractor_main_p()) {
|
|
139
|
+
rb_raise(rb_eRuntimeError, "BUG: get_gvl_owner_context must be called from the main ractor");
|
|
140
|
+
}
|
|
140
141
|
|
|
141
|
-
|
|
142
|
-
|
|
142
|
+
#ifdef HAVE_RUBY_RACTOR_H
|
|
143
|
+
return ddtrace_get_ractor();
|
|
144
|
+
#else
|
|
145
|
+
return GET_VM();
|
|
146
|
+
#endif
|
|
147
|
+
}
|
|
143
148
|
|
|
144
|
-
|
|
149
|
+
#ifndef NO_GVL_OWNER // Ruby < 2.6 doesn't have the owner/running field
|
|
150
|
+
// NOTE: Reading the owner in this is a racy read, because we're not grabbing the lock that Ruby uses to protect it.
|
|
151
|
+
//
|
|
152
|
+
// While we could potentially grab this lock, I (@ivoanjo) think we actually don't need it because:
|
|
153
|
+
// * In the case where a thread owns the GVL and calls `main_ractor_gvl_owner`, it will always see the correct value. That's
|
|
154
|
+
// because every thread sets itself as the owner when it grabs the GVL and unsets itself at the end.
|
|
155
|
+
// That means that `is_current_thread_in_main_ractor_and_holding_the_gvl` is always accurate.
|
|
156
|
+
// * In a case where we observe a different thread, then this may change by the time we do something with this value
|
|
157
|
+
// anyway. So unless we want to prevent the Ruby scheduler from switching threads, we need to deal with races here.
|
|
158
|
+
current_gvl_owner main_ractor_gvl_owner(void) {
|
|
159
|
+
if (private_vm_api_global.main_ractor_gvl_owner_context == NULL) return (current_gvl_owner) {.valid = false};
|
|
160
|
+
|
|
161
|
+
const rb_thread_t *current_owner =
|
|
162
|
+
#ifndef NO_RB_THREAD_SCHED // Introduced in Ruby 3.2 as a replacement for struct rb_global_vm_lock_struct
|
|
163
|
+
private_vm_api_global.main_ractor_gvl_owner_context->threads.sched.running;
|
|
164
|
+
#elif HAVE_RUBY_RACTOR_H
|
|
165
|
+
private_vm_api_global.main_ractor_gvl_owner_context->threads.gvl.owner;
|
|
145
166
|
#else
|
|
146
|
-
|
|
167
|
+
private_vm_api_global.main_ractor_gvl_owner_context->gvl.owner;
|
|
147
168
|
#endif
|
|
169
|
+
|
|
170
|
+
if (current_owner == NULL) {
|
|
171
|
+
return (current_gvl_owner) {.valid = false};
|
|
148
172
|
}
|
|
149
|
-
#else
|
|
150
|
-
current_gvl_owner gvl_owner(void) {
|
|
151
|
-
rb_vm_t *vm = GET_VM();
|
|
152
173
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
// * Declaration 1: Someone has the GVL
|
|
156
|
-
// * Declaration 2: That someone is the specific thread
|
|
157
|
-
//
|
|
158
|
-
// Observation 1: On older versions of Ruby, this ownership concept is actually split. Specifically, `gvl.acquired`
|
|
159
|
-
// is a boolean that represents declaration 1 above, and `vm->running_thread` (or `ruby_current_thread`/
|
|
160
|
-
// `ruby_current_execution_context_ptr`) represents declaration 2.
|
|
161
|
-
//
|
|
162
|
-
// Observation 2: In addition, when a thread releases the GVL, it only sets `gvl.acquired` back to 0 **BUT CRUCIALLY
|
|
163
|
-
// DOES NOT CHANGE THE OTHER global variables**.
|
|
164
|
-
//
|
|
165
|
-
// Observation 1+2 above lead to the following possible race:
|
|
166
|
-
// * Thread A grabs the GVL (`gvl.acquired == 1`)
|
|
167
|
-
// * Thread A sets `running_thread` (`gvl.acquired == 1` + `running_thread == Thread A`)
|
|
168
|
-
// * Thread A releases the GVL (`gvl.acquired == 0` + `running_thread == Thread A`)
|
|
169
|
-
// * Thread B grabs the GVL (`gvl.acquired == 1` + `running_thread == Thread A`)
|
|
170
|
-
// * Thread A calls gvl_owner. Due to the current state (`gvl.acquired == 1` + `running_thread == Thread A`), this
|
|
171
|
-
// function returns an incorrect result.
|
|
172
|
-
// * Thread B finally sets `running_thread` (`gvl.acquired == 1` + `running_thread == Thread B`)
|
|
173
|
-
//
|
|
174
|
-
// This is especially problematic because we use `gvl_owner` to implement `is_current_thread_holding_the_gvl` which
|
|
175
|
-
// is called in a signal handler to decide "is it safe for me to call `rb_postponed_job_register_one` or not".
|
|
176
|
-
// (See constraints in `collectors_cpu_and_wall_time_worker.c` comments for why).
|
|
177
|
-
//
|
|
178
|
-
// Thus an incorrect `is_current_thread_holding_the_gvl` result may lead to issues inside `rb_postponed_job_register_one`.
|
|
179
|
-
//
|
|
180
|
-
// For this reason we default to use the "no signals workaround" on Ruby 2.5 by default, and we print a
|
|
181
|
-
// warning when customers force-enable it.
|
|
182
|
-
bool gvl_acquired = vm->gvl.acquired != 0;
|
|
183
|
-
rb_thread_t *current_owner = vm->running_thread;
|
|
174
|
+
#ifndef NO_RB_NATIVE_THREAD
|
|
175
|
+
struct rb_native_thread* current_owner_native_thread = current_owner->nt;
|
|
184
176
|
|
|
185
|
-
|
|
177
|
+
// This can be NULL on Ruby 3.3 with MN threads (RUBY_MN_THREADS=1)
|
|
178
|
+
if (current_owner_native_thread == NULL) {
|
|
179
|
+
return (current_gvl_owner) {.valid = false};
|
|
180
|
+
}
|
|
186
181
|
|
|
182
|
+
return (current_gvl_owner) {.valid = true, .owner = current_owner_native_thread->thread_id};
|
|
183
|
+
#else
|
|
187
184
|
return (current_gvl_owner) {.valid = true, .owner = current_owner->thread_id};
|
|
185
|
+
#endif
|
|
186
|
+
}
|
|
187
|
+
#else
|
|
188
|
+
current_gvl_owner main_ractor_gvl_owner(void) {
|
|
189
|
+
rb_vm_t *vm = private_vm_api_global.main_ractor_gvl_owner_context;
|
|
190
|
+
if (vm == NULL) return (current_gvl_owner) {.valid = false};
|
|
191
|
+
|
|
192
|
+
// BIG Issue: Ruby < 2.6 did not have the owner field. The really nice thing about the owner field is that it's
|
|
193
|
+
// "atomic" -- when a thread sets it, it "declares" two things in a single step
|
|
194
|
+
// * Declaration 1: Someone has the GVL
|
|
195
|
+
// * Declaration 2: That someone is the specific thread
|
|
196
|
+
//
|
|
197
|
+
// Observation 1: On older versions of Ruby, this ownership concept is actually split. Specifically, `gvl.acquired`
|
|
198
|
+
// is a boolean that represents declaration 1 above, and `vm->running_thread` (or `ruby_current_thread`/
|
|
199
|
+
// `ruby_current_execution_context_ptr`) represents declaration 2.
|
|
200
|
+
//
|
|
201
|
+
// Observation 2: In addition, when a thread releases the GVL, it only sets `gvl.acquired` back to 0 **BUT CRUCIALLY
|
|
202
|
+
// DOES NOT CHANGE THE OTHER global variables**.
|
|
203
|
+
//
|
|
204
|
+
// Observation 1+2 above lead to the following possible race:
|
|
205
|
+
// * Thread A grabs the GVL (`gvl.acquired == 1`)
|
|
206
|
+
// * Thread A sets `running_thread` (`gvl.acquired == 1` + `running_thread == Thread A`)
|
|
207
|
+
// * Thread A releases the GVL (`gvl.acquired == 0` + `running_thread == Thread A`)
|
|
208
|
+
// * Thread B grabs the GVL (`gvl.acquired == 1` + `running_thread == Thread A`)
|
|
209
|
+
// * Thread A calls main_ractor_gvl_owner. Due to the current state (`gvl.acquired == 1` + `running_thread == Thread A`), this
|
|
210
|
+
// function returns an incorrect result.
|
|
211
|
+
// * Thread B finally sets `running_thread` (`gvl.acquired == 1` + `running_thread == Thread B`)
|
|
212
|
+
//
|
|
213
|
+
// This is especially problematic because we use `main_ractor_gvl_owner` to implement `is_current_thread_in_main_ractor_and_holding_the_gvl` which
|
|
214
|
+
// is called in a signal handler to decide "is it safe for me to call `rb_postponed_job_register_one` or not".
|
|
215
|
+
// (See constraints in `collectors_cpu_and_wall_time_worker.c` comments for why).
|
|
216
|
+
//
|
|
217
|
+
// Thus an incorrect `is_current_thread_in_main_ractor_and_holding_the_gvl` result may lead to issues inside `rb_postponed_job_register_one`.
|
|
218
|
+
//
|
|
219
|
+
// For this reason we default to use the "no signals workaround" on Ruby 2.5 by default, and we print a
|
|
220
|
+
// warning when customers force-enable it.
|
|
221
|
+
bool gvl_acquired = vm->gvl.acquired != 0;
|
|
222
|
+
rb_thread_t *current_owner = vm->running_thread;
|
|
223
|
+
|
|
224
|
+
if (!gvl_acquired || current_owner == NULL) {
|
|
225
|
+
return (current_gvl_owner) {.valid = false};
|
|
188
226
|
}
|
|
227
|
+
|
|
228
|
+
return (current_gvl_owner) {.valid = true, .owner = current_owner->thread_id};
|
|
229
|
+
}
|
|
189
230
|
#endif // NO_GVL_OWNER
|
|
190
231
|
|
|
191
232
|
// Taken from upstream vm_core.h at commit d9cf0388599a3234b9f3c06ddd006cd59a58ab8b (November 2022, Ruby 3.2 trunk)
|
|
@@ -193,7 +234,7 @@ bool is_current_thread_holding_the_gvl(void) {
|
|
|
193
234
|
// to support tid_for (see below)
|
|
194
235
|
// Modifications: None
|
|
195
236
|
#if defined(__linux__) || defined(__FreeBSD__)
|
|
196
|
-
#
|
|
237
|
+
#define RB_THREAD_T_HAS_NATIVE_ID
|
|
197
238
|
#endif
|
|
198
239
|
|
|
199
240
|
uint64_t native_thread_id_for(VALUE thread) {
|
|
@@ -201,7 +242,9 @@ uint64_t native_thread_id_for(VALUE thread) {
|
|
|
201
242
|
#if !defined(NO_THREAD_TID) && defined(RB_THREAD_T_HAS_NATIVE_ID)
|
|
202
243
|
#ifndef NO_RB_NATIVE_THREAD
|
|
203
244
|
struct rb_native_thread* native_thread = thread_struct_from_object(thread)->nt;
|
|
204
|
-
if (native_thread == NULL)
|
|
245
|
+
if (native_thread == NULL) {
|
|
246
|
+
return 0;
|
|
247
|
+
}
|
|
205
248
|
return native_thread->tid;
|
|
206
249
|
#else
|
|
207
250
|
return thread_struct_from_object(thread)->tid;
|
|
@@ -213,7 +256,9 @@ uint64_t native_thread_id_for(VALUE thread) {
|
|
|
213
256
|
uint64_t result;
|
|
214
257
|
// On macOS, this gives us the same identifier that shows up in activity monitor
|
|
215
258
|
int error = pthread_threadid_np(pthread_id, &result);
|
|
216
|
-
if (error)
|
|
259
|
+
if (error) {
|
|
260
|
+
rb_syserr_fail(error, "Unexpected failure in pthread_threadid_np");
|
|
261
|
+
}
|
|
217
262
|
return result;
|
|
218
263
|
#else
|
|
219
264
|
// Fallback, when we have nothing better (e.g. on Ruby < 3.1 on Linux)
|
|
@@ -245,11 +290,12 @@ void ddtrace_thread_list(VALUE result_array) {
|
|
|
245
290
|
// called from a different Ractor, but I'm not sure...
|
|
246
291
|
#ifdef HAVE_RUBY_RACTOR_H
|
|
247
292
|
rb_ractor_t *current_ractor = ddtrace_get_ractor();
|
|
248
|
-
ccan_list_for_each(¤t_ractor->threads.set, thread, lt_node)
|
|
293
|
+
ccan_list_for_each(¤t_ractor->threads.set, thread, lt_node)
|
|
249
294
|
#else
|
|
250
295
|
rb_vm_t *vm = GET_VM();
|
|
251
|
-
list_for_each(&vm->living_threads, thread, vmlt_node)
|
|
296
|
+
list_for_each(&vm->living_threads, thread, vmlt_node)
|
|
252
297
|
#endif
|
|
298
|
+
{
|
|
253
299
|
switch (thread->status) {
|
|
254
300
|
case THREAD_RUNNABLE:
|
|
255
301
|
case THREAD_STOPPED:
|
|
@@ -269,6 +315,23 @@ VALUE thread_name_for(VALUE thread) {
|
|
|
269
315
|
return thread_struct_from_object(thread)->name;
|
|
270
316
|
}
|
|
271
317
|
|
|
318
|
+
// This test doubles as a validation for the layout of the rb_thread_t structure. Because the `name` is almost at
|
|
319
|
+
// the end of the structure, if somehow we can't read the name, this probably means we're getting the structure wrong
|
|
320
|
+
// and we should stop immediately (this includes covering the use of `stat_insn_usage` on Ruby <= 3.2).
|
|
321
|
+
//
|
|
322
|
+
// One example where this happens is in patches such as
|
|
323
|
+
// https://github.com/gitlabhq/omnibus-gitlab/blob/master/config/patches/ruby/thread-memory-allocations-3.2.patch
|
|
324
|
+
// that add items to the structure and thus shift its position from where we expect.
|
|
325
|
+
void self_test_thread_name_for(void) {
|
|
326
|
+
VALUE thread = rb_eval_string("Thread.new { Thread.current.name = 'dd-prof-test' }.join");
|
|
327
|
+
VALUE expected_name = rb_funcall(thread, rb_intern("name"), 0);
|
|
328
|
+
if (thread_name_for(thread) != expected_name) {
|
|
329
|
+
rb_raise(rb_eRuntimeError,
|
|
330
|
+
"thread_name_for() self-test failed; this usually means the `rb_thread_t` on this Ruby doesn't match what the profiler expects"
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
272
335
|
// -----------------------------------------------------------------------------
|
|
273
336
|
// The sources below are modified versions of code extracted from the Ruby project.
|
|
274
337
|
// Each function is annotated with its origin, why we imported it, and the changes made.
|
|
@@ -317,63 +380,71 @@ VALUE thread_name_for(VALUE thread) {
|
|
|
317
380
|
#pragma GCC diagnostic push
|
|
318
381
|
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
|
319
382
|
static inline int
|
|
320
|
-
calc_pos(const rb_iseq_t *iseq, const VALUE *pc, int *lineno, int *node_id)
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
if (
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
383
|
+
calc_pos(const rb_iseq_t *iseq, const VALUE *pc, int *lineno, int *node_id) {
|
|
384
|
+
VM_ASSERT(iseq);
|
|
385
|
+
VM_ASSERT(ISEQ_BODY(iseq));
|
|
386
|
+
VM_ASSERT(ISEQ_BODY(iseq)->iseq_encoded);
|
|
387
|
+
VM_ASSERT(ISEQ_BODY(iseq)->iseq_size);
|
|
388
|
+
if (pc == NULL) {
|
|
389
|
+
if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_TOP) {
|
|
390
|
+
VM_ASSERT(! ISEQ_BODY(iseq)->local_table);
|
|
391
|
+
VM_ASSERT(! ISEQ_BODY(iseq)->local_table_size);
|
|
392
|
+
return 0;
|
|
393
|
+
}
|
|
394
|
+
#ifndef NO_INT_FIRST_LINENO // Ruby 3.2+
|
|
395
|
+
if (lineno) {
|
|
396
|
+
*lineno = ISEQ_BODY(iseq)->location.first_lineno;
|
|
397
|
+
}
|
|
398
|
+
#else
|
|
399
|
+
if (lineno) {
|
|
400
|
+
*lineno = FIX2INT(ISEQ_BODY(iseq)->location.first_lineno);
|
|
401
|
+
}
|
|
402
|
+
#endif
|
|
337
403
|
#ifdef USE_ISEQ_NODE_ID
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
return 1;
|
|
404
|
+
if (node_id) {
|
|
405
|
+
*node_id = -1;
|
|
341
406
|
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
407
|
+
#endif
|
|
408
|
+
return 1;
|
|
409
|
+
} else {
|
|
410
|
+
ptrdiff_t n = pc - ISEQ_BODY(iseq)->iseq_encoded;
|
|
411
|
+
VM_ASSERT(n <= ISEQ_BODY(iseq)->iseq_size);
|
|
412
|
+
VM_ASSERT(n >= 0);
|
|
413
|
+
size_t pos = n; /* no overflow */
|
|
414
|
+
if (LIKELY(pos)) {
|
|
415
|
+
/* use pos-1 because PC points next instruction at the beginning of instruction */
|
|
416
|
+
pos--;
|
|
417
|
+
} else {
|
|
352
418
|
#if VMDEBUG && defined(HAVE_BUILTIN___BUILTIN_TRAP)
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
__builtin_trap();
|
|
357
|
-
}
|
|
419
|
+
/* SDR() is not possible; that causes infinite loop. */
|
|
420
|
+
rb_print_backtrace();
|
|
421
|
+
__builtin_trap();
|
|
358
422
|
#endif
|
|
423
|
+
}
|
|
359
424
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
425
|
+
// In PROF-11475 we spotted a crash when calling `rb_iseq_line_no` from this method.
|
|
426
|
+
// We were only able to reproduce this issue on Ruby 2.6 and 2.7, not 2.5 or the 3.x series (tried 3.0, 3.2 and 3.4).
|
|
427
|
+
// Note that going out of bounds doesn't crash every time, as usual with C we may just read garbage or get lucky.
|
|
428
|
+
//
|
|
429
|
+
// For those problematic Rubies, we observed that when we try to take a sample in the middle of processing the
|
|
430
|
+
// VM `LEAVE` instruction, the value of `n` can violate the documented assumptions above and be
|
|
431
|
+
// `n > ISEQ_BODY(iseq)->iseq_size)`.
|
|
432
|
+
//
|
|
433
|
+
// To work around this and any other potential issues, we validate here that the bytecode position is sane.
|
|
434
|
+
if (RB_UNLIKELY(n < 0 || n > ISEQ_BODY(iseq)->iseq_size)) {
|
|
435
|
+
return 0;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (lineno) {
|
|
439
|
+
*lineno = rb_iseq_line_no(iseq, pos);
|
|
440
|
+
}
|
|
372
441
|
#ifdef USE_ISEQ_NODE_ID
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
return 1;
|
|
442
|
+
if (node_id) {
|
|
443
|
+
*node_id = rb_iseq_node_id(iseq, pos);
|
|
376
444
|
}
|
|
445
|
+
#endif
|
|
446
|
+
return 1;
|
|
447
|
+
}
|
|
377
448
|
}
|
|
378
449
|
#pragma GCC diagnostic pop
|
|
379
450
|
|
|
@@ -382,11 +453,12 @@ calc_pos(const rb_iseq_t *iseq, const VALUE *pc, int *lineno, int *node_id)
|
|
|
382
453
|
// to support our custom rb_profile_frames (see below)
|
|
383
454
|
// Modifications: None
|
|
384
455
|
static inline int
|
|
385
|
-
calc_lineno(const rb_iseq_t *iseq, const VALUE *pc)
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
456
|
+
calc_lineno(const rb_iseq_t *iseq, const VALUE *pc) {
|
|
457
|
+
int lineno;
|
|
458
|
+
if (calc_pos(iseq, pc, &lineno, NULL)) {
|
|
459
|
+
return lineno;
|
|
460
|
+
}
|
|
461
|
+
return 0;
|
|
390
462
|
}
|
|
391
463
|
|
|
392
464
|
// Taken from upstream vm_backtrace.c at commit 5f10bd634fb6ae8f74a4ea730176233b0ca96954 (March 2022, Ruby 3.2 trunk)
|
|
@@ -445,183 +517,211 @@ calc_lineno(const rb_iseq_t *iseq, const VALUE *pc)
|
|
|
445
517
|
// disagree, and quite a few of them seem oversights/bugs (speculation from my part) rather than deliberate
|
|
446
518
|
// decisions.
|
|
447
519
|
int ddtrace_rb_profile_frames(VALUE thread, int start, int limit, frame_info *stack_buffer) {
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
520
|
+
int i;
|
|
521
|
+
// Modified from upstream: Instead of using `GET_EC` to collect info from the current thread,
|
|
522
|
+
// support sampling any thread (including the current) passed as an argument
|
|
523
|
+
rb_thread_t *th = thread_struct_from_object(thread);
|
|
524
|
+
const rb_execution_context_t *ec = th->ec;
|
|
525
|
+
|
|
526
|
+
// As of this writing, we don't support profiling with MN enabled, and this only happens in that mode, but as we
|
|
527
|
+
// probably want to experiment with it in the future, I've decided to import https://github.com/ruby/ruby/pull/9310
|
|
528
|
+
// here.
|
|
529
|
+
if (ec == NULL) {
|
|
530
|
+
return 0;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// Avoid sampling dead threads
|
|
534
|
+
if (th->status == THREAD_KILLED) {
|
|
535
|
+
return 0;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
const rb_control_frame_t *cfp = ec->cfp;
|
|
539
|
+
|
|
540
|
+
// This happens on newly-created threads (we even had a flaky test because of it)
|
|
541
|
+
if (cfp == NULL) {
|
|
542
|
+
return PLACEHOLDER_STACK_IN_NATIVE_CODE;
|
|
543
|
+
}
|
|
453
544
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
545
|
+
// I suspect this won't happen for ddtrace, but just-in-case we've imported a potential fix for
|
|
546
|
+
// https://github.com/ruby/ruby/pull/13643 by assuming that these can be NULL/zero with the cfp being non-NULL yet.
|
|
547
|
+
if (ec->vm_stack == NULL || ec->vm_stack_size == 0) {
|
|
548
|
+
return 0;
|
|
549
|
+
}
|
|
458
550
|
|
|
459
|
-
|
|
460
|
-
|
|
551
|
+
const rb_control_frame_t *end_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
|
|
552
|
+
#ifndef NO_JIT_RETURN
|
|
553
|
+
const rb_control_frame_t *top = cfp;
|
|
554
|
+
#endif
|
|
555
|
+
const rb_callable_method_entry_t *cme;
|
|
461
556
|
|
|
462
|
-
|
|
557
|
+
// `vm_backtrace.c` includes this check in several methods. This happens on newly-created threads, and may
|
|
558
|
+
// also (not entirely sure) happen on dead threads
|
|
559
|
+
if (end_cfp == NULL) {
|
|
560
|
+
return PLACEHOLDER_STACK_IN_NATIVE_CODE;
|
|
561
|
+
}
|
|
463
562
|
|
|
464
|
-
|
|
465
|
-
|
|
563
|
+
// Fix: Skip dummy frame that shows up in main thread.
|
|
564
|
+
//
|
|
565
|
+
// According to a comment in `backtrace_each` (`vm_backtrace.c`), there's two dummy frames that we should ignore
|
|
566
|
+
// at the base of every thread's stack.
|
|
567
|
+
// (see https://github.com/ruby/ruby/blob/4bd38e8120f2fdfdd47a34211720e048502377f1/vm_backtrace.c#L890-L914 )
|
|
568
|
+
//
|
|
569
|
+
// One is being pointed to by `RUBY_VM_END_CONTROL_FRAME(ec)`, and so we need to advance to the next one, and
|
|
570
|
+
// reaching it will be used as a condition to break out of the loop below.
|
|
571
|
+
//
|
|
572
|
+
// Note that in `backtrace_each` there's two calls to `RUBY_VM_NEXT_CONTROL_FRAME`, but the loop bounds there
|
|
573
|
+
// are computed in a different way, so the two calls really are equivalent to one here.
|
|
574
|
+
end_cfp = RUBY_VM_NEXT_CONTROL_FRAME(end_cfp);
|
|
466
575
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
576
|
+
// See comment on `record_placeholder_stack_in_native_code` for a full explanation of what this means (and why we don't just return 0)
|
|
577
|
+
if (end_cfp <= cfp) {
|
|
578
|
+
return PLACEHOLDER_STACK_IN_NATIVE_CODE;
|
|
579
|
+
}
|
|
470
580
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
581
|
+
// This is the position just after the top of the stack -- e.g. where a new frame pushed on the stack would end up.
|
|
582
|
+
const rb_control_frame_t *top_sentinel = RUBY_VM_NEXT_CONTROL_FRAME(cfp);
|
|
583
|
+
|
|
584
|
+
// We iterate the stack from bottom (beginning of thread) to the top (currently-active frame). This is different
|
|
585
|
+
// from upstream rb_profile_frames, but actually matches what `backtrace_each` does (yes, different Ruby VM APIs
|
|
586
|
+
// iterate in different directions).
|
|
587
|
+
// We do this to better take advantage of the `same_frame` caching mechanism: By starting from the bottom of the
|
|
588
|
+
// stack towards the top, we can usually keep most of the stack intact when the code is only going up and down
|
|
589
|
+
// a few methods at the top. Before this change, the cache was really only useful if between samples the app had
|
|
590
|
+
// not moved from the current stack, as adding or removing one frame would invalidate the existing cache (because
|
|
591
|
+
// every position would shift).
|
|
592
|
+
cfp = RUBY_VM_NEXT_CONTROL_FRAME(end_cfp);
|
|
593
|
+
|
|
594
|
+
for (i=0; i<limit && cfp != top_sentinel; cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) {
|
|
595
|
+
const VALUE *pc = cfp->pc;
|
|
596
|
+
#ifdef HAVE_ZJIT_FRAME
|
|
597
|
+
const rb_iseq_t *iseq = cfp->_iseq;
|
|
598
|
+
#else
|
|
599
|
+
const rb_iseq_t *iseq = cfp->iseq;
|
|
474
600
|
#endif
|
|
475
|
-
const rb_callable_method_entry_t *cme;
|
|
476
601
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
602
|
+
#if defined(HAVE_ZJIT_FRAME) && USE_ZJIT
|
|
603
|
+
// Based on CFP_ZJIT_FRAME, which we currently can't use directly.
|
|
604
|
+
if (CFP_ZJIT_FRAME_P(cfp)) {
|
|
605
|
+
if ((VALUE)cfp->jit_return == ZJIT_JIT_RETURN_C_FRAME) {
|
|
606
|
+
// ZJIT uses this sentinel for C method frames, which have no Ruby ISEQ or bytecode PC.
|
|
607
|
+
// Set both to NULL explicitly because ZJIT leaves those fields untouched, so they may contain stale data.
|
|
608
|
+
iseq = NULL;
|
|
609
|
+
pc = NULL;
|
|
610
|
+
} else {
|
|
611
|
+
const zjit_jit_frame_t *jit_frame = (const zjit_jit_frame_t *)((VALUE *)cfp->jit_return)[-1];
|
|
612
|
+
iseq = jit_frame->iseq;
|
|
613
|
+
pc = jit_frame->pc;
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
#endif
|
|
480
617
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
618
|
+
#ifndef NO_T_MOVED
|
|
619
|
+
if (iseq && RB_TYPE_P((VALUE) iseq, T_MOVED)) {
|
|
620
|
+
// The profiler is not supposed to sample during GC compaction, so T_MOVED is not expected here.
|
|
621
|
+
// Yet, crash tracking also uses this walker and may run at any time. For now, we choose to skip these frames.
|
|
622
|
+
continue;
|
|
623
|
+
}
|
|
624
|
+
#endif
|
|
625
|
+
|
|
626
|
+
if (iseq && !pc) {
|
|
627
|
+
// Fix: Do nothing -- this frame should not be used
|
|
628
|
+
//
|
|
629
|
+
// rb_profile_frames does not do this check, but `backtrace_each` (`vm_backtrace.c`) does. This frame is not
|
|
630
|
+
// exposed by the Ruby backtrace APIs and for now we want to match its behavior 1:1
|
|
631
|
+
} else if (cfp->ep == NULL) {
|
|
632
|
+
// Do nothing -- this frame should not be used
|
|
633
|
+
//
|
|
634
|
+
// We're not sure this can ever happen, but we've seen a crash inside `VM_FRAME_RUBYFRAME_P` below (which
|
|
635
|
+
// dereferences `cfp->ep`), so "just in case" we're adding this extra sanity check to avoid crashing on a
|
|
636
|
+
// NULL `ep`.
|
|
637
|
+
} else if (VM_FRAME_RUBYFRAME_P(cfp)) {
|
|
638
|
+
if (start > 0) {
|
|
639
|
+
start--;
|
|
640
|
+
continue;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
cme = safe_vm_frame_method_entry(cfp);
|
|
644
|
+
|
|
645
|
+
// Upstream (Ruby 4.0) does:
|
|
646
|
+
// if (cme && cme->def->type == VM_METHOD_TYPE_ISEQ) {
|
|
647
|
+
// buff[i] = (VALUE)cme;
|
|
648
|
+
// } else {
|
|
649
|
+
// buff[i] = (VALUE)cfp->iseq;
|
|
650
|
+
// }
|
|
651
|
+
// We get both the iseq and CME because we need both to format like Ruby backtraces
|
|
652
|
+
|
|
653
|
+
stack_buffer[i].same_frame =
|
|
654
|
+
stack_buffer[i].is_ruby_frame &&
|
|
655
|
+
stack_buffer[i].as.ruby_frame.iseq == iseq &&
|
|
656
|
+
stack_buffer[i].as.ruby_frame.caching_pc == pc &&
|
|
657
|
+
stack_buffer[i].cme == cme;
|
|
658
|
+
|
|
659
|
+
if (stack_buffer[i].same_frame) { // Nothing to do, buffer already contains this frame
|
|
660
|
+
i++;
|
|
661
|
+
continue;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
stack_buffer[i].as.ruby_frame.iseq = iseq;
|
|
665
|
+
stack_buffer[i].as.ruby_frame.caching_pc = (void *) pc;
|
|
666
|
+
stack_buffer[i].cme = cme;
|
|
667
|
+
|
|
668
|
+
// The topmost frame may not have an updated PC because the JIT
|
|
669
|
+
// may not have set one. The JIT compiler will update the PC
|
|
670
|
+
// before entering a new function (so that `caller` will work),
|
|
671
|
+
// so only the topmost frame could possibly have an out of date PC
|
|
672
|
+
#ifndef NO_JIT_RETURN
|
|
673
|
+
if (cfp == top && cfp->jit_return) {
|
|
674
|
+
stack_buffer[i].as.ruby_frame.line = 0;
|
|
675
|
+
} else {
|
|
676
|
+
stack_buffer[i].as.ruby_frame.line = calc_lineno(iseq, pc);
|
|
516
677
|
}
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
i++;
|
|
530
|
-
continue;
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
// dd-trace-rb NOTE:
|
|
534
|
-
// Upstream Ruby has code here to retrieve the rb_callable_method_entry_t (cme) and in some cases to use it
|
|
535
|
-
// instead of the iseq.
|
|
536
|
-
// In practice, they are usually the same; the difference is that when you have e.g. block, one gets you a
|
|
537
|
-
// reference to the block, and the other to the method containing the block.
|
|
538
|
-
// This would be important if we used `rb_profile_frame_label` and wanted the "block in foo" label instead
|
|
539
|
-
// of just "foo". But we're currently using `rb_profile_frame_base_label` which I believe is always the same
|
|
540
|
-
// between the rb_callable_method_entry_t and the iseq. Thus, to simplify a bit our logic and reduce a bit
|
|
541
|
-
// the overhead, we always use the iseq here.
|
|
542
|
-
//
|
|
543
|
-
// @ivoanjo: I've left the upstream Ruby code commented out below for reference, so it's more obvious that
|
|
544
|
-
// we're diverging, and we can easily compare and experiment with the upstream version in the future.
|
|
545
|
-
//
|
|
546
|
-
// cme = rb_vm_frame_method_entry(cfp);
|
|
547
|
-
|
|
548
|
-
// if (cme && cme->def->type == VM_METHOD_TYPE_ISEQ &&
|
|
549
|
-
// // Fix: Do not use callable method entry when iseq is for an eval.
|
|
550
|
-
// // TL;DR: This fix is needed for us to match the Ruby reference API information in the
|
|
551
|
-
// // "when sampling an eval/instance eval inside an object" spec.
|
|
552
|
-
// cfp->iseq->body->type != ISEQ_TYPE_EVAL) {
|
|
553
|
-
// buff[i] = (VALUE)cme;
|
|
554
|
-
// }
|
|
555
|
-
// else {
|
|
556
|
-
stack_buffer[i].as.ruby_frame.iseq = (VALUE)cfp->iseq;
|
|
557
|
-
stack_buffer[i].as.ruby_frame.caching_pc = (void *) cfp->pc;
|
|
558
|
-
// }
|
|
559
|
-
|
|
560
|
-
// The topmost frame may not have an updated PC because the JIT
|
|
561
|
-
// may not have set one. The JIT compiler will update the PC
|
|
562
|
-
// before entering a new function (so that `caller` will work),
|
|
563
|
-
// so only the topmost frame could possibly have an out of date PC
|
|
564
|
-
#ifndef NO_JIT_RETURN
|
|
565
|
-
if (cfp == top && cfp->jit_return) {
|
|
566
|
-
stack_buffer[i].as.ruby_frame.line = 0;
|
|
567
|
-
} else {
|
|
568
|
-
stack_buffer[i].as.ruby_frame.line = calc_lineno(cfp->iseq, cfp->pc);
|
|
569
|
-
}
|
|
570
|
-
#else // Ruby < 3.1
|
|
571
|
-
stack_buffer[i].as.ruby_frame.line = calc_lineno(cfp->iseq, cfp->pc);
|
|
572
|
-
#endif
|
|
573
|
-
|
|
574
|
-
stack_buffer[i].is_ruby_frame = true;
|
|
575
|
-
i++;
|
|
678
|
+
#else // Ruby < 3.1
|
|
679
|
+
stack_buffer[i].as.ruby_frame.line = calc_lineno(iseq, pc);
|
|
680
|
+
#endif
|
|
681
|
+
|
|
682
|
+
stack_buffer[i].is_ruby_frame = true;
|
|
683
|
+
i++;
|
|
684
|
+
} else {
|
|
685
|
+
cme = get_cfunc_method_entry(cfp);
|
|
686
|
+
if (cme && cme->def->type == VM_METHOD_TYPE_CFUNC) {
|
|
687
|
+
if (start > 0) {
|
|
688
|
+
start--;
|
|
689
|
+
continue;
|
|
576
690
|
}
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
stack_buffer[i].same_frame =
|
|
586
|
-
!stack_buffer[i].is_ruby_frame &&
|
|
587
|
-
stack_buffer[i].as.native_frame.caching_cme == (VALUE) cme;
|
|
588
|
-
|
|
589
|
-
if (stack_buffer[i].same_frame) { // Nothing to do, buffer already contains this frame
|
|
590
|
-
i++;
|
|
591
|
-
continue;
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
stack_buffer[i].as.native_frame.caching_cme = (VALUE)cme;
|
|
595
|
-
stack_buffer[i].as.native_frame.method_id = cme->def->original_id;
|
|
596
|
-
stack_buffer[i].as.native_frame.function = cme->def->body.cfunc.func;
|
|
597
|
-
stack_buffer[i].is_ruby_frame = false;
|
|
598
|
-
i++;
|
|
599
|
-
}
|
|
691
|
+
|
|
692
|
+
stack_buffer[i].same_frame =
|
|
693
|
+
!stack_buffer[i].is_ruby_frame &&
|
|
694
|
+
stack_buffer[i].cme == cme;
|
|
695
|
+
|
|
696
|
+
if (stack_buffer[i].same_frame) { // Nothing to do, buffer already contains this frame
|
|
697
|
+
i++;
|
|
698
|
+
continue;
|
|
600
699
|
}
|
|
700
|
+
|
|
701
|
+
stack_buffer[i].cme = cme;
|
|
702
|
+
stack_buffer[i].is_ruby_frame = false;
|
|
703
|
+
i++;
|
|
704
|
+
}
|
|
601
705
|
}
|
|
706
|
+
}
|
|
602
707
|
|
|
603
|
-
|
|
708
|
+
return i;
|
|
604
709
|
}
|
|
605
710
|
|
|
606
|
-
// Support code for older Rubies that cannot use the MJIT header
|
|
607
|
-
#ifndef RUBY_MJIT_HEADER
|
|
608
|
-
|
|
609
|
-
#define MJIT_STATIC // No-op on older Rubies
|
|
610
|
-
|
|
611
711
|
// Taken from upstream include/ruby/backward/2/bool.h at commit 5f10bd634fb6ae8f74a4ea730176233b0ca96954 (March 2022, Ruby 3.2 trunk)
|
|
612
712
|
// Copyright (C) Ruby developers <ruby-core@ruby-lang.org>
|
|
613
713
|
// to support our custom rb_profile_frames (see above)
|
|
614
714
|
// Modifications: None
|
|
615
715
|
#ifndef FALSE
|
|
616
|
-
#
|
|
716
|
+
#define FALSE false
|
|
617
717
|
#elif FALSE
|
|
618
|
-
#
|
|
718
|
+
#error FALSE must be false
|
|
619
719
|
#endif
|
|
620
720
|
|
|
621
721
|
#ifndef TRUE
|
|
622
|
-
#
|
|
722
|
+
#define TRUE true
|
|
623
723
|
#elif ! TRUE
|
|
624
|
-
#
|
|
724
|
+
#error TRUE must be true
|
|
625
725
|
#endif
|
|
626
726
|
|
|
627
727
|
// Taken from upstream vm_insnhelper.c at commit 5f10bd634fb6ae8f74a4ea730176233b0ca96954 (March 2022, Ruby 3.2 trunk)
|
|
@@ -629,87 +729,104 @@ int ddtrace_rb_profile_frames(VALUE thread, int start, int limit, frame_info *st
|
|
|
629
729
|
// to support our custom rb_profile_frames (see above)
|
|
630
730
|
// Modifications:
|
|
631
731
|
// * Removed debug checks (they were ifdef'd out anyway)
|
|
732
|
+
// * Optimized to avoid recursion
|
|
632
733
|
static rb_callable_method_entry_t *
|
|
633
|
-
check_method_entry(VALUE obj, int can_be_svar)
|
|
634
|
-
{
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
}
|
|
646
|
-
// fallthrough
|
|
647
|
-
default:
|
|
648
|
-
return NULL;
|
|
734
|
+
check_method_entry(VALUE obj, int can_be_svar) {
|
|
735
|
+
if (obj == Qfalse) {
|
|
736
|
+
return NULL;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
enum imemo_type type = imemo_type(obj);
|
|
740
|
+
if (type == imemo_ment) {
|
|
741
|
+
return (rb_callable_method_entry_t *)obj;
|
|
742
|
+
} else if (can_be_svar && type == imemo_svar) {
|
|
743
|
+
VALUE cref_or_me = ((struct vm_svar *)obj)->cref_or_me;
|
|
744
|
+
if (imemo_type(cref_or_me) == imemo_ment) {
|
|
745
|
+
return (rb_callable_method_entry_t *)cref_or_me;
|
|
649
746
|
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
return NULL;
|
|
650
750
|
}
|
|
651
751
|
|
|
652
|
-
//
|
|
653
|
-
//
|
|
654
|
-
//
|
|
752
|
+
// Identical to upstream rb_vm_frame_method_entry (vm_insnhelper.c) with two additions:
|
|
753
|
+
// 1. FIXNUM_P check on ep[FLAGS] before each iteration to detect torn EPs
|
|
754
|
+
// 2. NULL check on ep after VM_ENV_PREV_EP
|
|
655
755
|
//
|
|
656
|
-
//
|
|
657
|
-
//
|
|
658
|
-
//
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
756
|
+
// When the profiler's signal handler interrupts vm_make_env_each (vm.c) mid-escape,
|
|
757
|
+
// a child frame's SPECVAL can still point to the parent's old stack EP whose flags
|
|
758
|
+
// slot has been overwritten with (VALUE)env for GC marking.
|
|
759
|
+
static const rb_callable_method_entry_t *
|
|
760
|
+
safe_vm_frame_method_entry(const rb_control_frame_t *cfp) {
|
|
761
|
+
const VALUE *ep = cfp->ep;
|
|
762
|
+
rb_callable_method_entry_t *me;
|
|
763
|
+
|
|
764
|
+
// Torn-EP check before VM_ENV_LOCAL_P, check_method_entry, and VM_ENV_PREV_EP
|
|
765
|
+
// dereference ep
|
|
766
|
+
while (FIXNUM_P(ep[VM_ENV_DATA_INDEX_FLAGS]) && !VM_ENV_LOCAL_P(ep)) {
|
|
767
|
+
if ((me = check_method_entry(ep[VM_ENV_DATA_INDEX_ME_CREF], FALSE)) != NULL) {
|
|
768
|
+
return me;
|
|
669
769
|
}
|
|
770
|
+
ep = VM_ENV_PREV_EP(ep);
|
|
771
|
+
if (ep == NULL) {
|
|
772
|
+
return NULL;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
670
775
|
|
|
671
|
-
|
|
776
|
+
// If we exited because of a torn EP (failed FIXNUM_P), bail out
|
|
777
|
+
if (!FIXNUM_P(ep[VM_ENV_DATA_INDEX_FLAGS])) {
|
|
778
|
+
return NULL;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
return check_method_entry(ep[VM_ENV_DATA_INDEX_ME_CREF], TRUE);
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
// Optimized version of rb_vm_frame_method_entry() for cfunc frames.
|
|
785
|
+
// Cfunc frames always have VM_ENV_FLAG_LOCAL set, so ep[-2] is the cme directly
|
|
786
|
+
// with no EP chain walk needed. The only complication is cfuncs that set $~ or $_
|
|
787
|
+
// (e.g. Regexp#match, String#gsub) which replace ep[-2] with an imemo_svar wrapping
|
|
788
|
+
// the cme - in that case svar->cref_or_me is always the cme (never a cref).
|
|
789
|
+
static inline const rb_callable_method_entry_t *
|
|
790
|
+
get_cfunc_method_entry(const rb_control_frame_t *cfp) {
|
|
791
|
+
return check_method_entry(cfp->ep[VM_ENV_DATA_INDEX_ME_CREF], TRUE);
|
|
672
792
|
}
|
|
673
|
-
#endif // RUBY_MJIT_HEADER
|
|
674
793
|
|
|
675
794
|
#ifndef NO_RACTORS
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
795
|
+
// This API and definition are exported as a public symbol by the VM BUT the function header is not defined in any public header, so we
|
|
796
|
+
// repeat it here to be able to use in our code.
|
|
797
|
+
#ifndef USE_RACTOR_INTERNAL_APIS_DIRECTLY
|
|
798
|
+
// Disable fast path for detecting multiple Ractors. Unfortunately this symbol is no longer visible on modern Ruby
|
|
799
|
+
// versions, so we need to do a bit more work.
|
|
800
|
+
struct rb_ractor_struct *ruby_single_main_ractor = NULL;
|
|
801
|
+
|
|
802
|
+
// Alternative implementation of rb_ractor_main_p_ that avoids relying on non-public symbols
|
|
803
|
+
bool rb_ractor_main_p_(void) {
|
|
804
|
+
// We need to get the main ractor in a bit of a roundabout way, since Ruby >= 3.3 hid `GET_VM()`
|
|
805
|
+
return ddtrace_get_ractor() == thread_struct_from_object(rb_thread_current())->vm->ractor.main_ractor;
|
|
806
|
+
}
|
|
807
|
+
#else
|
|
808
|
+
// Directly access Ruby internal fast path for detecting multiple Ractors.
|
|
809
|
+
extern struct rb_ractor_struct *ruby_single_main_ractor;
|
|
691
810
|
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
811
|
+
// Ruby 3.0 to 3.2 directly expose this symbol, we just need to tell the compiler it exists.
|
|
812
|
+
bool rb_ractor_main_p_(void);
|
|
813
|
+
#endif
|
|
695
814
|
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
{
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
else {
|
|
706
|
-
return rb_ractor_main_p_();
|
|
707
|
-
}
|
|
815
|
+
// Taken from upstream ractor_core.h at commit d9cf0388599a3234b9f3c06ddd006cd59a58ab8b (November 2022, Ruby 3.2 trunk)
|
|
816
|
+
// to allow us to ensure that we're always operating on the main ractor (if Ruby has ractors)
|
|
817
|
+
// Modifications:
|
|
818
|
+
// * None
|
|
819
|
+
bool ddtrace_rb_ractor_main_p(void) {
|
|
820
|
+
if (ruby_single_main_ractor) {
|
|
821
|
+
return true;
|
|
822
|
+
} else {
|
|
823
|
+
return rb_ractor_main_p_();
|
|
708
824
|
}
|
|
825
|
+
}
|
|
709
826
|
#else
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
827
|
+
// Simplify callers on older Rubies, instead of having them probe if the VM supports Ractors we just tell them that yes
|
|
828
|
+
// they're always on the main Ractor
|
|
829
|
+
bool ddtrace_rb_ractor_main_p(void) { return true; }
|
|
713
830
|
#endif // NO_RACTORS
|
|
714
831
|
|
|
715
832
|
// This is a tweaked and inlined version of
|
|
@@ -721,17 +838,23 @@ static const rb_iseq_t *maybe_thread_invoke_proc_iseq(VALUE thread_value) {
|
|
|
721
838
|
rb_thread_t *thread = thread_struct_from_object(thread_value);
|
|
722
839
|
|
|
723
840
|
#ifndef NO_THREAD_INVOKE_ARG // Ruby 2.6+
|
|
724
|
-
if (thread->invoke_type != thread_invoke_type_proc)
|
|
841
|
+
if (thread->invoke_type != thread_invoke_type_proc) {
|
|
842
|
+
return NULL;
|
|
843
|
+
}
|
|
725
844
|
|
|
726
845
|
VALUE proc = thread->invoke_arg.proc.proc;
|
|
727
846
|
#else
|
|
728
|
-
if (thread->first_func || !thread->first_proc)
|
|
847
|
+
if (thread->first_func || !thread->first_proc) {
|
|
848
|
+
return NULL;
|
|
849
|
+
}
|
|
729
850
|
|
|
730
851
|
VALUE proc = thread->first_proc;
|
|
731
852
|
#endif
|
|
732
853
|
|
|
733
854
|
const rb_iseq_t *iseq = rb_proc_get_iseq(proc, 0);
|
|
734
|
-
if (iseq == NULL)
|
|
855
|
+
if (iseq == NULL) {
|
|
856
|
+
return NULL;
|
|
857
|
+
}
|
|
735
858
|
|
|
736
859
|
rb_iseq_check(iseq);
|
|
737
860
|
return iseq;
|
|
@@ -740,10 +863,12 @@ static const rb_iseq_t *maybe_thread_invoke_proc_iseq(VALUE thread_value) {
|
|
|
740
863
|
VALUE invoke_location_for(VALUE thread, int *line_location) {
|
|
741
864
|
const rb_iseq_t *iseq = maybe_thread_invoke_proc_iseq(thread);
|
|
742
865
|
|
|
743
|
-
if (iseq == NULL)
|
|
866
|
+
if (iseq == NULL) {
|
|
867
|
+
return Qnil;
|
|
868
|
+
}
|
|
744
869
|
|
|
745
870
|
*line_location = NUM2INT(rb_iseq_first_lineno(iseq));
|
|
746
|
-
return
|
|
871
|
+
return ddtrace_iseq_path(iseq);
|
|
747
872
|
}
|
|
748
873
|
|
|
749
874
|
void self_test_mn_enabled(void) {
|
|
@@ -756,139 +881,351 @@ void self_test_mn_enabled(void) {
|
|
|
756
881
|
#endif
|
|
757
882
|
}
|
|
758
883
|
|
|
759
|
-
// Taken from upstream imemo.h at commit 6ebcf25de2859b5b6402b7e8b181066c32d0e0bf (November 2023, master branch)
|
|
760
|
-
// (See the Ruby project copyright and license above)
|
|
761
|
-
// to enable calling rb_imemo_name
|
|
762
|
-
//
|
|
763
|
-
// Modifications:
|
|
764
|
-
// * Added IMEMO_MASK define
|
|
765
|
-
// * Changed return type to int to avoid having to define `enum imemo_type`
|
|
766
|
-
static inline int ddtrace_imemo_type(VALUE imemo) {
|
|
767
|
-
// This mask is the same between Ruby 2.5 and 3.3-preview3. Furthermore, the intention of this method is to be used
|
|
768
|
-
// to call `rb_imemo_name` which correctly handles invalid numbers so even if the mask changes in the future, at most
|
|
769
|
-
// we'll get incorrect results (and never a VM crash)
|
|
770
|
-
#define IMEMO_MASK 0x0f
|
|
771
|
-
return (RBASIC(imemo)->flags >> FL_USHIFT) & IMEMO_MASK;
|
|
772
|
-
}
|
|
773
|
-
|
|
774
884
|
// Safety: This function assumes the object passed in is of the imemo type. But in the worst case, you'll just get
|
|
775
885
|
// a string that doesn't make any sense.
|
|
776
886
|
#ifndef NO_IMEMO_NAME
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
887
|
+
const char *imemo_kind(VALUE imemo) {
|
|
888
|
+
return rb_imemo_name(imemo_type(imemo));
|
|
889
|
+
}
|
|
780
890
|
#else
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
891
|
+
const char *imemo_kind(__attribute__((unused)) VALUE imemo) {
|
|
892
|
+
return NULL;
|
|
893
|
+
}
|
|
784
894
|
#endif
|
|
785
895
|
|
|
786
896
|
// This is used to workaround a VM bug. See "handle_sampling_signal" in "collectors_cpu_and_wall_time_worker" for details.
|
|
787
897
|
#ifdef NO_POSTPONED_TRIGGER
|
|
788
|
-
|
|
789
|
-
|
|
898
|
+
void *objspace_ptr_for_gc_finalize_deferred_workaround(void) {
|
|
899
|
+
return GET_VM()->objspace;
|
|
900
|
+
}
|
|
901
|
+
#endif
|
|
902
|
+
|
|
903
|
+
#ifndef HAVE_RUBY_THREAD_STORAGE_API
|
|
904
|
+
#include "gvl_profiling_helper.h"
|
|
905
|
+
|
|
906
|
+
// Hack: In Ruby 3.3+ we attach gvl profiling state to Ruby threads using the
|
|
907
|
+
// rb_internal_thread_specific_* APIs. These APIs did not exist on Ruby <= 3.2. On Ruby <= 3.2 we instead store the
|
|
908
|
+
// needed data inside the `rb_thread_t` structure, specifically in `stat_insn_usage` as a Ruby FIXNUM.
|
|
909
|
+
//
|
|
910
|
+
// Why `stat_insn_usage`? We needed some per-thread storage, and while looking at the Ruby VM sources I noticed
|
|
911
|
+
// that `stat_insn_usage` has been in `rb_thread_t` for a long time, but is not used anywhere in the VM
|
|
912
|
+
// code. There's a comment attached to it "/* statistics data for profiler */" but other than marking this
|
|
913
|
+
// field for GC, I could not find any place in the VM commit history or on GitHub where this has ever been used.
|
|
914
|
+
//
|
|
915
|
+
// Thus, since this hack is only for Ruby <= 3.2, which presumably will never see this field either removed or used
|
|
916
|
+
// we... kinda take it for our own usage. It's ugly, I know...
|
|
917
|
+
//
|
|
918
|
+
// 64-bit pointers actually use 48-bit virtual addresses (https://muxup.com/2023q4/storing-data-in-pointers),
|
|
919
|
+
// so we are sure the addresses fit in Fixnums.
|
|
920
|
+
per_thread_context *get_per_thread_context(VALUE thread) {
|
|
921
|
+
VALUE current_value = thread_struct_from_object(thread)->stat_insn_usage;
|
|
922
|
+
return RB_FIXNUM_P(current_value) ? (per_thread_context *) FIX2LONG(current_value) : NULL;
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
void set_per_thread_context(VALUE thread, per_thread_context *value) {
|
|
926
|
+
if (!RB_FIXABLE((intptr_t) value)) {
|
|
927
|
+
rb_bug("per_thread_context pointer does not fit in a Fixnum: %p", value);
|
|
790
928
|
}
|
|
929
|
+
thread_struct_from_object(thread)->stat_insn_usage = value ? LONG2FIX((intptr_t) value) : Qfalse;
|
|
930
|
+
}
|
|
791
931
|
#endif
|
|
792
932
|
|
|
793
|
-
|
|
794
|
-
|
|
933
|
+
// Is the VM smack in the middle of raising an exception?
|
|
934
|
+
bool is_raised_flag_set(VALUE thread) { return thread_struct_from_object(thread)->ec->raised_flag > 0; }
|
|
795
935
|
|
|
796
|
-
|
|
797
|
-
|
|
936
|
+
#ifndef NO_CURRENT_FIBER_FOR
|
|
937
|
+
// The following three declarations are all
|
|
938
|
+
// taken from upstream cont.c at commit d97884a58be32e829fd03a80cd521f4733d65c79 (February 2025, master branch)
|
|
939
|
+
// (See the Ruby project copyright and license above)
|
|
940
|
+
// to enable building `current_fiber_for`.
|
|
941
|
+
//
|
|
942
|
+
// We needed to copy them because they aren't otherwise exposed in any VM APIs or headers.
|
|
943
|
+
// @ivoanjo: I manually checked the Ruby 3.1, 3.2, 3.3 and 3.4 branches + master, and the parts we care about in these
|
|
944
|
+
// structures have not changed in many years (in fact, last change I spotted was for 2.7).
|
|
945
|
+
enum context_type {
|
|
946
|
+
CONTINUATION_CONTEXT = 0,
|
|
947
|
+
FIBER_CONTEXT = 1
|
|
948
|
+
};
|
|
949
|
+
|
|
950
|
+
typedef struct rb_context_struct { // This declaration is incomplete -- only contains up to `self` which is the part we care about
|
|
951
|
+
enum context_type type;
|
|
952
|
+
int argc;
|
|
953
|
+
int kw_splat;
|
|
954
|
+
VALUE self;
|
|
955
|
+
} rb_context_t;
|
|
956
|
+
|
|
957
|
+
struct rb_fiber_struct { // This declaration is incomplete -- only contains the first entry which is the part we care about
|
|
958
|
+
rb_context_t cont;
|
|
959
|
+
};
|
|
960
|
+
|
|
961
|
+
VALUE current_fiber_for(VALUE thread) {
|
|
962
|
+
VALUE self = thread_struct_from_object(thread)->ec->fiber_ptr->cont.self;
|
|
963
|
+
return self == 0 ? Qnil : self;
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
void self_test_current_fiber_for(void) {
|
|
967
|
+
VALUE expected_current_fiber = current_fiber_for(rb_thread_current());
|
|
968
|
+
VALUE actual_current_fiber = rb_fiber_current();
|
|
969
|
+
|
|
970
|
+
if (expected_current_fiber == Qnil) {
|
|
971
|
+
// On purpose above we tried reading before calling `rb_fiber_current()` so the fiber may have not existed yet.
|
|
972
|
+
// But now it should be there.
|
|
973
|
+
expected_current_fiber = current_fiber_for(rb_thread_current());
|
|
798
974
|
}
|
|
799
975
|
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
// during its remaining maintenance release period we... kinda take it for our own usage. It's ugly, I know...
|
|
811
|
-
intptr_t gvl_profiling_state_get(gvl_profiling_thread thread) {
|
|
812
|
-
if (thread.thread == NULL) return 0;
|
|
976
|
+
if (expected_current_fiber != actual_current_fiber) {
|
|
977
|
+
rb_raise(rb_eRuntimeError, "current_fiber_for() self-test failed");
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
#else
|
|
981
|
+
NORETURN(VALUE current_fiber_for(DDTRACE_UNUSED VALUE thread));
|
|
982
|
+
|
|
983
|
+
VALUE current_fiber_for(DDTRACE_UNUSED VALUE thread) { rb_raise(rb_eRuntimeError, "Not implemented for Ruby < 3.1"); }
|
|
984
|
+
void self_test_current_fiber_for(void) { } // Nothing to do
|
|
985
|
+
#endif
|
|
813
986
|
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
987
|
+
// Variant of functions related to Thread::Backtrace::Location#label in Ruby 4.0
|
|
988
|
+
// (location_label(), rb_gen_method_name(), calculate_iseq_label()),
|
|
989
|
+
// but formatting using a C buffer instead of allocating Ruby Strings.
|
|
990
|
+
// Also, those functions are static functions in vm_backtrace.c so not reusable.
|
|
991
|
+
// There is also AFAIK no reasonable way to create a rb_backtrace_location_t from outside that file.
|
|
992
|
+
|
|
993
|
+
// Return true if a given location is a C method or supposed to behave like one.
|
|
994
|
+
static bool location_cfunc_p(const rb_callable_method_entry_t *cme) {
|
|
995
|
+
if (!cme) {
|
|
996
|
+
return false;
|
|
817
997
|
}
|
|
818
998
|
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
999
|
+
switch (cme->def->type) {
|
|
1000
|
+
case VM_METHOD_TYPE_CFUNC:
|
|
1001
|
+
return true;
|
|
1002
|
+
// Upstream, but we don't want that behavior:
|
|
1003
|
+
// case VM_METHOD_TYPE_ISEQ:
|
|
1004
|
+
// return is_internal_location(loc->cme->def->body.iseq.iseqptr);
|
|
1005
|
+
default:
|
|
1006
|
+
return false;
|
|
822
1007
|
}
|
|
1008
|
+
}
|
|
823
1009
|
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
1010
|
+
// RCLASS_SINGLETON_P() is only defined on Ruby 3.4+, so we have a copy for older versions
|
|
1011
|
+
static bool ddtrace_RCLASS_SINGLETON_P(VALUE klass) {
|
|
1012
|
+
return RB_TYPE_P(klass, T_CLASS) && FL_TEST_RAW(klass, FL_SINGLETON);
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
static VALUE get_class_attached_object(VALUE klass) {
|
|
1016
|
+
#ifndef NO_CLASS_ATTACHED_OBJECT
|
|
1017
|
+
return rb_class_attached_object(klass);
|
|
1018
|
+
#else
|
|
1019
|
+
return rb_ivar_get(klass, rb_intern("__attached__"));
|
|
1020
|
+
#endif
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
static bool is_metaclass(VALUE mod, VALUE* attached) {
|
|
1024
|
+
if (ddtrace_RCLASS_SINGLETON_P(mod)) {
|
|
1025
|
+
VALUE attached_object = get_class_attached_object(mod);
|
|
1026
|
+
if (RB_TYPE_P(attached_object, T_CLASS) || RB_TYPE_P(attached_object, T_MODULE)) {
|
|
1027
|
+
*attached = attached_object;
|
|
1028
|
+
return true;
|
|
838
1029
|
}
|
|
1030
|
+
}
|
|
1031
|
+
return false;
|
|
1032
|
+
}
|
|
839
1033
|
|
|
840
|
-
|
|
1034
|
+
VALUE ddtrace_alloc_free_rb_mod_name(VALUE mod) {
|
|
1035
|
+
#ifdef NO_ALLOC_FREE_MOD_NAME
|
|
1036
|
+
VALUE name = rb_attr_get(mod, rb_intern("__classpath__"));
|
|
1037
|
+
#else
|
|
1038
|
+
VALUE name = rb_mod_name(mod);
|
|
1039
|
+
#endif
|
|
1040
|
+
// While Module#const_set rejects empty strings,
|
|
1041
|
+
// an empty String is possible if `rb_const_set(mod, "", val)` was used
|
|
1042
|
+
// but that's not understandable so consider those anonymous too.
|
|
1043
|
+
if (name == Qnil || RSTRING_LEN(name) == 0) {
|
|
1044
|
+
return Qnil;
|
|
1045
|
+
} else {
|
|
1046
|
+
return name;
|
|
841
1047
|
}
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
// Ruby 3.3+ has a `permanent_classpath` flag on rb_classext_struct.
|
|
1051
|
+
// Checking for '#' in the name is equivalent on older Rubies:
|
|
1052
|
+
// non-permanent names contain '#' from `#<Module:0x...>` or `#<Class:0x...>` prefixes.
|
|
1053
|
+
static bool has_permanent_classpath(DDTRACE_UNUSED VALUE mod, DDTRACE_UNUSED VALUE mod_name) {
|
|
1054
|
+
#if defined(RCLASS_EXT_PRIME) // 4.0+
|
|
1055
|
+
// We can't actually use RCLASS_PERMANENT_CLASSPATH_P(mod) because that uses
|
|
1056
|
+
// RCLASS_EXT_READABLE() which uses rb_current_box(), which is a private symbol:
|
|
1057
|
+
// https://github.com/DataDog/dd-trace-rb/issues/6338
|
|
1058
|
+
// Instead we use `RCLASS_EXT_PRIME(mod)->permanent_classpath`, which is equivalent for our usage:
|
|
1059
|
+
// the two can only differ for boxable (= core) modules with no permanent name, i.e. metaclasses like
|
|
1060
|
+
// String.singleton_class, and is_metaclass() already replaced those with the attached module, so we display
|
|
1061
|
+
// `String.foo` and not `#<Class:String>#foo`. Same for the name in ddtrace_alloc_free_rb_mod_name().
|
|
1062
|
+
return RCLASS_EXT_PRIME(mod)->permanent_classpath;
|
|
1063
|
+
#elif defined(HAVE_PERMANENT_CLASSPATH) // 3.3 - 3.4
|
|
1064
|
+
return RCLASS_EXT(mod)->permanent_classpath;
|
|
1065
|
+
#else // 3.2 and older
|
|
1066
|
+
return memchr(RSTRING_PTR(mod_name), '#', RSTRING_LEN(mod_name)) == NULL;
|
|
842
1067
|
#endif
|
|
1068
|
+
}
|
|
843
1069
|
|
|
844
|
-
|
|
845
|
-
|
|
1070
|
+
VALUE ddtrace_permanent_mod_name(VALUE mod) {
|
|
1071
|
+
VALUE name = ddtrace_alloc_free_rb_mod_name(mod);
|
|
846
1072
|
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
CONTINUATION_CONTEXT = 0,
|
|
858
|
-
FIBER_CONTEXT = 1
|
|
859
|
-
};
|
|
860
|
-
|
|
861
|
-
typedef struct rb_context_struct { // This declaration is incomplete -- only contains up to `self` which is the part we care about
|
|
862
|
-
enum context_type type;
|
|
863
|
-
int argc;
|
|
864
|
-
int kw_splat;
|
|
865
|
-
VALUE self;
|
|
866
|
-
} rb_context_t;
|
|
867
|
-
|
|
868
|
-
struct rb_fiber_struct { // This declaration is incomplete -- only contains the first entry which is the part we care about
|
|
869
|
-
rb_context_t cont;
|
|
870
|
-
};
|
|
871
|
-
|
|
872
|
-
VALUE current_fiber_for(VALUE thread) {
|
|
873
|
-
VALUE self = thread_struct_from_object(thread)->ec->fiber_ptr->cont.self;
|
|
874
|
-
return self == 0 ? Qnil : self;
|
|
875
|
-
}
|
|
876
|
-
|
|
877
|
-
void self_test_current_fiber_for(void) {
|
|
878
|
-
VALUE expected_current_fiber = current_fiber_for(rb_thread_current());
|
|
879
|
-
VALUE actual_current_fiber = rb_fiber_current();
|
|
880
|
-
|
|
881
|
-
if (expected_current_fiber == Qnil) {
|
|
882
|
-
// On purpose above we tried reading before calling `rb_fiber_current()` so the fiber may have not existed yet.
|
|
883
|
-
// But now it should be there.
|
|
884
|
-
expected_current_fiber = current_fiber_for(rb_thread_current());
|
|
885
|
-
}
|
|
1073
|
+
if (NIL_P(name) || !has_permanent_classpath(mod, name)) {
|
|
1074
|
+
return Qnil;
|
|
1075
|
+
} else {
|
|
1076
|
+
return name;
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
#define ONLY_METHOD_NAME ((ssize_t) -1)
|
|
1081
|
+
#define BUFFER_OUT_OF_SPACE ((ssize_t) -2)
|
|
1082
|
+
#define NO_METHOD_NAME ((ssize_t) -3)
|
|
886
1083
|
|
|
887
|
-
|
|
1084
|
+
static ssize_t rb_gen_method_name(VALUE owner, VALUE method_name, char *buf, size_t buf_size) {
|
|
1085
|
+
if (!(RB_TYPE_P(owner, T_CLASS) || RB_TYPE_P(owner, T_MODULE))) {
|
|
1086
|
+
return ONLY_METHOD_NAME;
|
|
888
1087
|
}
|
|
889
|
-
#else
|
|
890
|
-
NORETURN(VALUE current_fiber_for(DDTRACE_UNUSED VALUE thread));
|
|
891
1088
|
|
|
892
|
-
VALUE
|
|
893
|
-
|
|
1089
|
+
VALUE mod = owner;
|
|
1090
|
+
char separator = '#';
|
|
1091
|
+
if (is_metaclass(owner, &mod)) {
|
|
1092
|
+
separator = '.';
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
VALUE mod_name = ddtrace_permanent_mod_name(mod);
|
|
1096
|
+
|
|
1097
|
+
// Exclude non-permanent names (e.g. `#<Module:0x0123>::Foo`) which break flamegraph aggregation
|
|
1098
|
+
// since they contain addresses that differ across processes/runs.
|
|
1099
|
+
if (NIL_P(mod_name)) {
|
|
1100
|
+
return ONLY_METHOD_NAME;
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
size_t mod_name_len = RSTRING_LEN(mod_name);
|
|
1104
|
+
size_t method_name_len = RSTRING_LEN(method_name);
|
|
1105
|
+
size_t total = mod_name_len + 1 + method_name_len;
|
|
1106
|
+
if (total <= buf_size) {
|
|
1107
|
+
memcpy(buf, RSTRING_PTR(mod_name), mod_name_len);
|
|
1108
|
+
buf[mod_name_len] = separator;
|
|
1109
|
+
memcpy(buf + mod_name_len + 1, RSTRING_PTR(method_name), method_name_len);
|
|
1110
|
+
return total;
|
|
1111
|
+
} else {
|
|
1112
|
+
return BUFFER_OUT_OF_SPACE;
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
static ssize_t calculate_iseq_label(VALUE owner, const rb_iseq_t *iseq, char *buf, size_t buf_size) {
|
|
1117
|
+
switch (ISEQ_BODY(iseq)->type) {
|
|
1118
|
+
case ISEQ_TYPE_TOP:
|
|
1119
|
+
case ISEQ_TYPE_CLASS:
|
|
1120
|
+
case ISEQ_TYPE_MAIN:
|
|
1121
|
+
// Just the method name, not `Object#<top (required)>`
|
|
1122
|
+
return ONLY_METHOD_NAME;
|
|
1123
|
+
|
|
1124
|
+
case ISEQ_TYPE_METHOD:
|
|
1125
|
+
return rb_gen_method_name(owner, ISEQ_BODY(iseq)->location.label, buf, buf_size);
|
|
1126
|
+
|
|
1127
|
+
#ifdef ISEQ_TYPE_PLAIN /* 2.5 does not have it */
|
|
1128
|
+
case ISEQ_TYPE_PLAIN:
|
|
894
1129
|
#endif
|
|
1130
|
+
case ISEQ_TYPE_BLOCK: {
|
|
1131
|
+
// CRuby uses "block in Foo#bar" and ""block (N levels) in Foo#bar" in backtraces.
|
|
1132
|
+
// We use "Foo#bar (block)" because it's much faster and looks better in the UI.
|
|
1133
|
+
const rb_iseq_t* method_iseq = ISEQ_BODY(iseq)->local_iseq;
|
|
1134
|
+
|
|
1135
|
+
static const char suffix[] = " (block)";
|
|
1136
|
+
size_t suffix_len = sizeof(suffix) - 1;
|
|
1137
|
+
|
|
1138
|
+
// Only use the result if there is enough space for both parts
|
|
1139
|
+
ssize_t written = calculate_iseq_label(owner, method_iseq, buf, buf_size);
|
|
1140
|
+
if (written > 0 && (written + suffix_len) <= buf_size) {
|
|
1141
|
+
memcpy(buf + written, suffix, suffix_len);
|
|
1142
|
+
return written + suffix_len;
|
|
1143
|
+
} else if (written == ONLY_METHOD_NAME) {
|
|
1144
|
+
VALUE method_name = rb_iseq_base_label(method_iseq);
|
|
1145
|
+
size_t method_name_len = RSTRING_LEN(method_name);
|
|
1146
|
+
if ((method_name_len + suffix_len) <= buf_size) {
|
|
1147
|
+
memcpy(buf, RSTRING_PTR(method_name), method_name_len);
|
|
1148
|
+
memcpy(buf + method_name_len, suffix, suffix_len);
|
|
1149
|
+
return method_name_len + suffix_len;
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
return BUFFER_OUT_OF_SPACE;
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
case ISEQ_TYPE_RESCUE:
|
|
1157
|
+
case ISEQ_TYPE_ENSURE:
|
|
1158
|
+
case ISEQ_TYPE_EVAL:
|
|
1159
|
+
iseq = ISEQ_BODY(iseq)->parent_iseq;
|
|
1160
|
+
return calculate_iseq_label(owner, iseq, buf, buf_size);
|
|
1161
|
+
|
|
1162
|
+
default:
|
|
1163
|
+
// Upstream: rb_bug("calculate_iseq_label: unreachable");
|
|
1164
|
+
return ONLY_METHOD_NAME;
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
// MRI: location_label()
|
|
1169
|
+
// C methods don't have an iseq, only Ruby methods have
|
|
1170
|
+
ssize_t ddtrace_location_label(const rb_callable_method_entry_t *cme, const rb_iseq_t *iseq, char *buf, size_t buf_size) {
|
|
1171
|
+
if (location_cfunc_p(cme)) {
|
|
1172
|
+
VALUE method_name = rb_id2str(cme->def->original_id);
|
|
1173
|
+
if (method_name == Qfalse) {
|
|
1174
|
+
return NO_METHOD_NAME;
|
|
1175
|
+
}
|
|
1176
|
+
return rb_gen_method_name(cme->owner, method_name, buf, buf_size);
|
|
1177
|
+
} else {
|
|
1178
|
+
VALUE owner = cme ? cme->owner : Qnil;
|
|
1179
|
+
return calculate_iseq_label(owner, iseq, buf, buf_size);
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
// Returns a String or Qfalse (like rb_id2str())
|
|
1184
|
+
VALUE ddtrace_location_base_label(const rb_callable_method_entry_t *cme, const rb_iseq_t *iseq) {
|
|
1185
|
+
if (location_cfunc_p(cme)) {
|
|
1186
|
+
return rb_id2str(cme->def->original_id);
|
|
1187
|
+
} else {
|
|
1188
|
+
return rb_iseq_base_label(iseq);
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
// Always returns a String
|
|
1193
|
+
VALUE ddtrace_iseq_base_label(const rb_iseq_t *iseq) {
|
|
1194
|
+
return rb_iseq_base_label(iseq);
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
// Always returns a String
|
|
1198
|
+
// See https://github.com/ruby/ruby/blob/75aeb225b8558ff908ea78bf608dfbba09bdc2f9/iseq.c#L564-L565
|
|
1199
|
+
VALUE ddtrace_iseq_path(const rb_iseq_t *iseq) {
|
|
1200
|
+
return rb_iseq_path(iseq);
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
size_t sizeof_rb_iseq_t(void) {
|
|
1204
|
+
return sizeof(rb_iseq_t);
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
size_t sizeof_rb_callable_method_entry_t(void) {
|
|
1208
|
+
return sizeof(rb_callable_method_entry_t);
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
void* ddtrace_cme_cfunc_func(const rb_callable_method_entry_t *cme) {
|
|
1212
|
+
return cme->def->body.cfunc.func;
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
const char *ddtrace_cme_original_method_name(const rb_callable_method_entry_t *cme) {
|
|
1216
|
+
return rb_id2name(cme->def->original_id);
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
// This function is not present in the VM headers, but is a public symbol that can be invoked.
|
|
1220
|
+
int rb_objspace_internal_object_p(VALUE obj);
|
|
1221
|
+
|
|
1222
|
+
bool ddtrace_is_internal_object_p(VALUE obj) {
|
|
1223
|
+
if (RB_SPECIAL_CONST_P(obj)) {
|
|
1224
|
+
// Ruby special constants are not internal, except Qundef.
|
|
1225
|
+
// See enum ruby_special_consts in CRuby.
|
|
1226
|
+
return obj == Qundef;
|
|
1227
|
+
} else {
|
|
1228
|
+
// rb_objspace_internal_object_p() assumes non-immediate, so check that first above
|
|
1229
|
+
return rb_objspace_internal_object_p(obj);
|
|
1230
|
+
}
|
|
1231
|
+
}
|