datadog 2.38.0 → 2.47.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 +279 -35
- 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/collectors_cpu_and_wall_time_worker.c +256 -117
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +1 -5
- data/ext/datadog_profiling_native_extension/collectors_gc_profiling_helper.c +0 -2
- data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +19 -20
- data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.h +5 -1
- data/ext/datadog_profiling_native_extension/collectors_stack.c +267 -171
- data/ext/datadog_profiling_native_extension/collectors_stack.h +17 -3
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +307 -217
- data/ext/datadog_profiling_native_extension/collectors_thread_context.h +10 -5
- data/ext/datadog_profiling_native_extension/crashtracking_runtime_stacks.c +5 -4
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +19 -11
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +7 -10
- data/ext/datadog_profiling_native_extension/extconf.rb +68 -100
- data/ext/datadog_profiling_native_extension/heap_recorder.c +353 -257
- data/ext/datadog_profiling_native_extension/heap_recorder.h +50 -31
- data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +3 -27
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +853 -496
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +42 -15
- data/ext/datadog_profiling_native_extension/profiling.c +30 -23
- data/ext/datadog_profiling_native_extension/ruby_helpers.c +4 -80
- data/ext/datadog_profiling_native_extension/ruby_helpers.h +4 -7
- data/ext/datadog_profiling_native_extension/stack_recorder.c +116 -89
- data/ext/datadog_profiling_native_extension/stack_recorder.h +12 -5
- data/ext/datadog_profiling_native_extension/time_helpers.c +2 -4
- data/ext/datadog_profiling_native_extension/time_helpers.h +15 -15
- data/ext/libdatadog_api/datadog_ruby_common.c +19 -11
- data/ext/libdatadog_api/datadog_ruby_common.h +7 -10
- data/ext/libdatadog_api/di.c +43 -3
- data/ext/libdatadog_api/extconf.rb +29 -24
- data/ext/libdatadog_api/feature_flags.c +34 -0
- data/ext/libdatadog_api/init.c +9 -1
- data/ext/libdatadog_api/otel_thread_context.c +274 -0
- data/ext/libdatadog_api/otel_thread_context.h +5 -0
- data/ext/libdatadog_api/process_discovery.c +15 -1
- data/ext/libdatadog_api/trace_exporter.c +2078 -0
- data/ext/libdatadog_api/trace_exporter.h +5 -0
- data/ext/libdatadog_extconf_helpers.rb +22 -17
- data/lib/datadog/ai_guard/component.rb +24 -15
- data/lib/datadog/ai_guard/configuration/ext.rb +2 -0
- data/lib/datadog/ai_guard/configuration.rb +13 -0
- data/lib/datadog/ai_guard/contrib/ruby_llm/chat_instrumentation.rb +48 -55
- 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 +12 -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 +6 -6
- data/lib/datadog/ai_guard/evaluation/outcome.rb +24 -0
- data/lib/datadog/ai_guard/evaluation/request.rb +8 -64
- data/lib/datadog/ai_guard/evaluation/response.rb +33 -0
- data/lib/datadog/ai_guard/evaluation/result.rb +11 -18
- data/lib/datadog/ai_guard/evaluation/tool_call.rb +15 -2
- data/lib/datadog/ai_guard/evaluation.rb +36 -14
- data/lib/datadog/ai_guard/ext.rb +4 -1
- data/lib/datadog/ai_guard/{api_client.rb → http_client.rb} +9 -7
- 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 +58 -57
- 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 +11 -11
- 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 +3 -3
- data/lib/datadog/appsec/component.rb +15 -15
- data/lib/datadog/appsec/compressed_json.rb +6 -6
- data/lib/datadog/appsec/configuration.rb +70 -61
- data/lib/datadog/appsec/context.rb +7 -7
- 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 +7 -7
- data/lib/datadog/appsec/contrib/aws_lambda/integration.rb +2 -2
- data/lib/datadog/appsec/contrib/aws_lambda/patcher.rb +2 -2
- data/lib/datadog/appsec/contrib/aws_lambda/waf_addresses.rb +36 -34
- 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 +12 -12
- 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 +26 -26
- 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 +22 -22
- data/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +4 -4
- data/lib/datadog/appsec/contrib/graphql/gateway/multiplex.rb +2 -2
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +7 -7
- data/lib/datadog/appsec/contrib/graphql/integration.rb +9 -9
- data/lib/datadog/appsec/contrib/graphql/patcher.rb +3 -3
- data/lib/datadog/appsec/contrib/rack/buffered_input.rb +1 -1
- data/lib/datadog/appsec/contrib/rack/ext.rb +29 -29
- data/lib/datadog/appsec/contrib/rack/gateway/request.rb +14 -18
- data/lib/datadog/appsec/contrib/rack/gateway/response.rb +1 -1
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +24 -24
- data/lib/datadog/appsec/contrib/rack/input_peeker.rb +6 -6
- 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 +26 -26
- data/lib/datadog/appsec/contrib/rack/response_body.rb +1 -1
- data/lib/datadog/appsec/contrib/rails/gateway/request.rb +10 -10
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +38 -11
- 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 +10 -9
- 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 +23 -23
- 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 +28 -16
- 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 +10 -9
- data/lib/datadog/appsec/contrib/sinatra/request_middleware.rb +2 -1
- data/lib/datadog/appsec/counter_sampler.rb +1 -1
- data/lib/datadog/appsec/event.rb +14 -14
- data/lib/datadog/appsec/ext.rb +11 -11
- data/lib/datadog/appsec/extensions.rb +2 -2
- data/lib/datadog/appsec/instrumentation/gateway.rb +1 -1
- data/lib/datadog/appsec/metrics/exporter.rb +8 -8
- data/lib/datadog/appsec/metrics/telemetry.rb +7 -7
- 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 +16 -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 +6 -6
- data/lib/datadog/appsec/response.rb +22 -22
- data/lib/datadog/appsec/route_normalizer/rails_route_pattern.rb +11 -11
- data/lib/datadog/appsec/route_normalizer/route_pattern.rb +18 -18
- data/lib/datadog/appsec/route_normalizer/route_text.rb +3 -3
- data/lib/datadog/appsec/route_normalizer.rb +15 -15
- data/lib/datadog/appsec/security_engine/engine.rb +41 -40
- data/lib/datadog/appsec/security_engine/runner.rb +2 -2
- data/lib/datadog/appsec/security_event.rb +2 -2
- data/lib/datadog/appsec/utils/http/body.rb +11 -8
- data/lib/datadog/appsec/utils/http/body_reader.rb +1 -1
- data/lib/datadog/appsec/utils/http/media_range.rb +15 -15
- data/lib/datadog/appsec/utils/http/media_type.rb +4 -4
- data/lib/datadog/appsec/utils/http/url_encoded.rb +80 -25
- data/lib/datadog/appsec.rb +16 -16
- 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/base.rb +2 -2
- data/lib/datadog/core/configuration/components.rb +82 -47
- data/lib/datadog/core/configuration/components_state.rb +8 -1
- data/lib/datadog/core/configuration/config_helper.rb +3 -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 +16 -16
- data/lib/datadog/core/configuration/option_definition.rb +5 -5
- data/lib/datadog/core/configuration/options.rb +2 -2
- data/lib/datadog/core/configuration/settings.rb +95 -100
- data/lib/datadog/core/configuration/stable_config.rb +1 -1
- data/lib/datadog/core/configuration/supported_configurations.rb +20 -3
- data/lib/datadog/core/configuration.rb +8 -8
- data/lib/datadog/core/contrib/rails/railtie.rb +3 -3
- data/lib/datadog/core/crashtracking/component.rb +14 -10
- 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 +42 -7
- 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 +9 -9
- data/lib/datadog/core/environment/execution.rb +3 -3
- data/lib/datadog/core/environment/ext.rb +18 -18
- 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 +10 -10
- data/lib/datadog/core/environment/platform.rb +8 -8
- data/lib/datadog/core/environment/process.rb +3 -3
- data/lib/datadog/core/environment/socket.rb +2 -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 +2 -2
- data/lib/datadog/core/extensions.rb +1 -1
- data/lib/datadog/core/feature_flags.rb +2 -2
- data/lib/datadog/core/git/ext.rb +4 -4
- data/lib/datadog/core/logger.rb +3 -3
- data/lib/datadog/core/logging/ext.rb +1 -1
- data/lib/datadog/core/metrics/client.rb +20 -20
- 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 +13 -9
- data/lib/datadog/core/rate_limiter.rb +1 -1
- data/lib/datadog/core/remote/client/capabilities.rb +60 -33
- data/lib/datadog/core/remote/client.rb +61 -20
- data/lib/datadog/core/remote/component.rb +48 -17
- 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/dispatcher.rb +47 -6
- 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 +7 -7
- 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 +9 -9
- 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 +13 -13
- data/lib/datadog/core/telemetry/configuration_value.rb +38 -0
- data/lib/datadog/core/telemetry/emitter.rb +4 -4
- data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +8 -6
- 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 +2 -2
- 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 +36 -55
- 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 -16
- data/lib/datadog/core/telemetry/ext.rb +11 -11
- 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 -6
- data/lib/datadog/core/telemetry/transport/http/telemetry.rb +14 -14
- 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 +6 -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 +5 -5
- 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 -9
- 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 +3 -3
- data/lib/datadog/core/utils/duration.rb +1 -1
- data/lib/datadog/core/utils/forking.rb +2 -2
- 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_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 +2 -2
- data/lib/datadog/core/utils/time.rb +16 -54
- data/lib/datadog/core/utils/url.rb +1 -1
- data/lib/datadog/core/utils.rb +4 -4
- data/lib/datadog/core/workers/async.rb +1 -1
- data/lib/datadog/core/workers/polling.rb +2 -2
- data/lib/datadog/core/workers/runtime_metrics.rb +5 -5
- data/lib/datadog/core.rb +4 -4
- data/lib/datadog/data_streams/configuration.rb +3 -3
- 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 +25 -27
- data/lib/datadog/data_streams/processor.rb +92 -61
- 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 +4 -4
- data/lib/datadog/di/boot.rb +26 -25
- data/lib/datadog/di/capture_expression_evaluator/result.rb +30 -0
- data/lib/datadog/di/capture_expression_evaluator.rb +39 -9
- data/lib/datadog/di/code_tracker.rb +6 -6
- data/lib/datadog/di/component.rb +119 -6
- data/lib/datadog/di/configuration.rb +54 -3
- data/lib/datadog/di/context.rb +7 -2
- data/lib/datadog/di/contrib/active_record.rb +8 -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 +113 -37
- 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/evaluation_failure.rb +28 -0
- data/lib/datadog/di/guardrails_telemetry/reason.rb +87 -0
- data/lib/datadog/di/guardrails_telemetry.rb +203 -0
- data/lib/datadog/di/instrumenter.rb +124 -23
- data/lib/datadog/di/logger.rb +32 -10
- data/lib/datadog/di/preload.rb +1 -1
- data/lib/datadog/di/probe.rb +9 -1
- data/lib/datadog/di/probe_builder.rb +25 -24
- data/lib/datadog/di/probe_file_loader/railtie.rb +1 -1
- data/lib/datadog/di/probe_file_loader.rb +5 -5
- data/lib/datadog/di/probe_manager.rb +57 -9
- data/lib/datadog/di/probe_notification_builder.rb +46 -43
- data/lib/datadog/di/probe_notifier_worker.rb +62 -12
- data/lib/datadog/di/probe_repository.rb +1 -1
- data/lib/datadog/di/proc_responder.rb +1 -1
- data/lib/datadog/di/remote.rb +52 -8
- data/lib/datadog/di/serializer.rb +185 -68
- data/lib/datadog/di/snapshot_event.rb +38 -0
- 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 +23 -13
- data/lib/datadog/di/transport/input.rb +41 -16
- data/lib/datadog/di/utils.rb +4 -4
- data/lib/datadog/di.rb +5 -5
- data/lib/datadog/error_tracking/collector.rb +2 -2
- data/lib/datadog/error_tracking/component.rb +12 -12
- data/lib/datadog/error_tracking/configuration.rb +2 -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 +40 -40
- data/lib/datadog/kit/appsec/events.rb +25 -25
- data/lib/datadog/kit/enable_core_dumps.rb +2 -2
- data/lib/datadog/kit/identity.rb +18 -18
- data/lib/datadog/kit/tracing/method_tracer.rb +7 -7
- data/lib/datadog/kit.rb +1 -1
- data/lib/datadog/open_feature/activation.rb +268 -0
- 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 +112 -31
- 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 +139 -2
- data/lib/datadog/open_feature/evaluation_engine.rb +36 -10
- 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 -8
- data/lib/datadog/open_feature/flag_evaluation/aggregator.rb +242 -86
- data/lib/datadog/open_feature/flag_evaluation/writer.rb +211 -100
- data/lib/datadog/open_feature/hooks/evaluation_telemetry_opt_out_hook.rb +25 -0
- data/lib/datadog/open_feature/hooks/flag_eval_evp_hook.rb +28 -24
- data/lib/datadog/open_feature/hooks/flag_eval_metrics_hook.rb +3 -1
- 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 +24 -24
- data/lib/datadog/open_feature/native_evaluator.rb +24 -10
- data/lib/datadog/open_feature/noop_evaluator.rb +8 -3
- data/lib/datadog/open_feature/provider.rb +357 -17
- data/lib/datadog/open_feature/remote.rb +7 -7
- data/lib/datadog/open_feature/resolution_details.rb +4 -2
- data/lib/datadog/open_feature/transport.rb +19 -14
- data/lib/datadog/open_feature.rb +33 -3
- 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 +41 -41
- data/lib/datadog/opentelemetry/ext.rb +1 -1
- data/lib/datadog/opentelemetry/logs.rb +5 -5
- data/lib/datadog/opentelemetry/metrics.rb +7 -7
- data/lib/datadog/opentelemetry/sdk/configurator.rb +8 -8
- data/lib/datadog/opentelemetry/sdk/id_generator.rb +2 -2
- data/lib/datadog/opentelemetry/sdk/logs_exporter.rb +6 -6
- data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +5 -5
- data/lib/datadog/opentelemetry/sdk/propagator.rb +8 -8
- data/lib/datadog/opentelemetry/sdk/span_processor.rb +15 -15
- data/lib/datadog/opentelemetry/sdk/trace/span.rb +32 -32
- data/lib/datadog/opentelemetry/sdk.rb +2 -2
- data/lib/datadog/opentelemetry/signal_configuration.rb +20 -16
- data/lib/datadog/opentelemetry/trace.rb +4 -1
- data/lib/datadog/opentelemetry.rb +8 -8
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +10 -2
- data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +5 -7
- data/lib/datadog/profiling/collectors/info.rb +40 -13
- data/lib/datadog/profiling/collectors/thread_context.rb +6 -17
- data/lib/datadog/profiling/component.rb +33 -39
- data/lib/datadog/profiling/exporter.rb +11 -11
- data/lib/datadog/profiling/http_transport.rb +1 -1
- data/lib/datadog/profiling/sequence_tracker.rb +1 -1
- data/lib/datadog/profiling/tag_builder.rb +19 -19
- data/lib/datadog/profiling/tasks/exec.rb +1 -1
- data/lib/datadog/profiling.rb +31 -27
- data/lib/datadog/single_step_instrument.rb +1 -1
- data/lib/datadog/symbol_database/component.rb +15 -15
- data/lib/datadog/symbol_database/configuration.rb +3 -3
- data/lib/datadog/symbol_database/extensions.rb +2 -2
- data/lib/datadog/symbol_database/extractor.rb +141 -159
- data/lib/datadog/symbol_database/file_hash.rb +3 -3
- data/lib/datadog/symbol_database/logger.rb +1 -1
- data/lib/datadog/symbol_database/remote.rb +21 -6
- data/lib/datadog/symbol_database/scope.rb +2 -2
- data/lib/datadog/symbol_database/scope_batcher.rb +2 -2
- data/lib/datadog/symbol_database/service_version.rb +4 -4
- data/lib/datadog/symbol_database/symbol.rb +1 -1
- data/lib/datadog/symbol_database/transport/http/endpoint.rb +1 -1
- data/lib/datadog/symbol_database/transport/http.rb +6 -6
- data/lib/datadog/symbol_database/transport.rb +4 -4
- data/lib/datadog/symbol_database/uploader.rb +22 -22
- data/lib/datadog/symbol_database.rb +2 -2
- data/lib/datadog/tracing/analytics.rb +1 -1
- data/lib/datadog/tracing/buffer.rb +5 -5
- data/lib/datadog/tracing/client_ip.rb +4 -4
- data/lib/datadog/tracing/component.rb +51 -9
- 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 +46 -42
- data/lib/datadog/tracing/configuration/http.rb +2 -2
- data/lib/datadog/tracing/configuration/settings.rb +52 -16
- data/lib/datadog/tracing/context.rb +25 -3
- data/lib/datadog/tracing/context_provider.rb +19 -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 +5 -5
- data/lib/datadog/tracing/contrib/action_cable/events/perform_action.rb +4 -4
- data/lib/datadog/tracing/contrib/action_cable/events/transmit.rb +5 -5
- 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 +4 -4
- 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 +3 -3
- 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 +9 -9
- data/lib/datadog/tracing/contrib/action_pack/action_controller/patcher.rb +2 -2
- data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +4 -4
- data/lib/datadog/tracing/contrib/action_pack/action_dispatch/patcher.rb +4 -4
- 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 +6 -6
- data/lib/datadog/tracing/contrib/action_view/events/render_template.rb +6 -6
- 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 +2 -2
- data/lib/datadog/tracing/contrib/active_job/event.rb +3 -3
- data/lib/datadog/tracing/contrib/active_job/events/discard.rb +5 -5
- data/lib/datadog/tracing/contrib/active_job/events/enqueue.rb +5 -5
- data/lib/datadog/tracing/contrib/active_job/events/enqueue_at.rb +5 -5
- data/lib/datadog/tracing/contrib/active_job/events/enqueue_retry.rb +5 -5
- data/lib/datadog/tracing/contrib/active_job/events/perform.rb +5 -5
- data/lib/datadog/tracing/contrib/active_job/events/retry_stopped.rb +5 -5
- 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 +7 -7
- 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 +6 -6
- data/lib/datadog/tracing/contrib/active_model_serializers/events/serialize.rb +6 -6
- 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 +7 -7
- 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 +8 -8
- data/lib/datadog/tracing/contrib/active_record/events/sql.rb +10 -9
- 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 +3 -3
- data/lib/datadog/tracing/contrib/active_support/cache/event.rb +1 -1
- data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +12 -12
- data/lib/datadog/tracing/contrib/active_support/cache/events.rb +1 -1
- data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +4 -4
- 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 +1 -1
- 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 +5 -5
- 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/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 +2 -2
- 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 +5 -5
- 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 +2 -2
- 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 +5 -5
- 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 +10 -10
- data/lib/datadog/tracing/contrib/elasticsearch/quantize.rb +3 -3
- data/lib/datadog/tracing/contrib/ethon/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +18 -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 +3 -3
- 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 +17 -10
- data/lib/datadog/tracing/contrib/excon/patcher.rb +2 -2
- data/lib/datadog/tracing/contrib/ext.rb +18 -18
- data/lib/datadog/tracing/contrib/extensions.rb +2 -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 +17 -11
- 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 +51 -24
- 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 +37 -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 +8 -8
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +8 -8
- 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 +9 -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 +6 -6
- data/lib/datadog/tracing/contrib/hanami/action_tracer.rb +3 -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 +3 -3
- data/lib/datadog/tracing/contrib/hanami/router_tracing.rb +5 -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 +8 -8
- data/lib/datadog/tracing/contrib/http/ext.rb +11 -11
- data/lib/datadog/tracing/contrib/http/instrumentation.rb +22 -7
- 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 +6 -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 +13 -7
- 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 +16 -10
- 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 +3 -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 +2 -2
- data/lib/datadog/tracing/contrib/kafka/instrumentation/producer.rb +4 -4
- 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 +9 -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 +8 -8
- data/lib/datadog/tracing/contrib/karafka.rb +6 -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 +5 -5
- data/lib/datadog/tracing/contrib/mongodb/patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +13 -13
- 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 +6 -6
- 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 +13 -13
- data/lib/datadog/tracing/contrib/opensearch/quantize.rb +4 -4
- 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 +6 -6
- 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 +2 -2
- 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 +17 -17
- data/lib/datadog/tracing/contrib/propagation/sql_comment/mode.rb +1 -1
- 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 +2 -2
- data/lib/datadog/tracing/contrib/racecar/configuration/settings.rb +3 -3
- data/lib/datadog/tracing/contrib/racecar/event.rb +4 -4
- 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 +3 -3
- data/lib/datadog/tracing/contrib/rack/ext.rb +33 -33
- data/lib/datadog/tracing/contrib/rack/header_collection.rb +3 -3
- data/lib/datadog/tracing/contrib/rack/header_tagging.rb +4 -4
- data/lib/datadog/tracing/contrib/rack/integration.rb +6 -6
- data/lib/datadog/tracing/contrib/rack/middlewares.rb +24 -24
- data/lib/datadog/tracing/contrib/rack/patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/rack/request_queue.rb +3 -3
- data/lib/datadog/tracing/contrib/rack/route_inference.rb +11 -11
- data/lib/datadog/tracing/contrib/rack/trace_proxy_middleware.rb +16 -16
- 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/middlewares.rb +1 -1
- data/lib/datadog/tracing/contrib/rails/patcher.rb +8 -8
- data/lib/datadog/tracing/contrib/rails/railtie.rb +4 -4
- data/lib/datadog/tracing/contrib/rails/runner.rb +1 -1
- 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 +4 -4
- 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 +39 -5
- data/lib/datadog/tracing/contrib/redis/tags.rb +5 -5
- data/lib/datadog/tracing/contrib/redis/trace_middleware.rb +14 -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 +5 -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 +15 -8
- data/lib/datadog/tracing/contrib/roda/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/roda/ext.rb +6 -6
- data/lib/datadog/tracing/contrib/roda/instrumentation.rb +4 -4
- 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 +6 -10
- data/lib/datadog/tracing/contrib/sequel/dataset.rb +5 -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 +101 -9
- 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 +2 -2
- data/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +8 -8
- data/lib/datadog/tracing/contrib/sidekiq/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/sidekiq/distributed/propagation.rb +10 -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_tracer.rb +13 -13
- data/lib/datadog/tracing/contrib/sidekiq/utils.rb +9 -9
- data/lib/datadog/tracing/contrib/sidekiq.rb +6 -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 +1 -1
- 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 +10 -10
- data/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb +8 -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 +4 -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 +1 -1
- 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 +3 -3
- 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 +4 -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 +6 -6
- 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_formatter.rb +2 -2
- data/lib/datadog/tracing/contrib/utils/quantization/http.rb +118 -13
- data/lib/datadog/tracing/contrib/waterdrop/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/waterdrop/distributed/propagation.rb +9 -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 +6 -6
- data/lib/datadog/tracing/contrib.rb +54 -54
- data/lib/datadog/tracing/correlation.rb +12 -12
- data/lib/datadog/tracing/diagnostics/environment_logger.rb +12 -11
- 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 +27 -29
- data/lib/datadog/tracing/distributed/datadog.rb +23 -23
- 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 +15 -12
- data/lib/datadog/tracing/distributed/propagation_policy.rb +5 -0
- data/lib/datadog/tracing/distributed/trace_context.rb +21 -278
- 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 +1 -1
- data/lib/datadog/tracing/ext.rb +1 -1
- 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 +72 -69
- 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 +3 -3
- data/lib/datadog/tracing/metadata.rb +4 -4
- data/lib/datadog/tracing/otel_thread_context.rb +97 -0
- data/lib/datadog/tracing/pipeline/span_filter.rb +2 -2
- data/lib/datadog/tracing/pipeline.rb +2 -2
- data/lib/datadog/tracing/remote.rb +250 -44
- data/lib/datadog/tracing/sampling/all_sampler.rb +1 -1
- data/lib/datadog/tracing/sampling/ext.rb +8 -8
- data/lib/datadog/tracing/sampling/matcher.rb +4 -4
- data/lib/datadog/tracing/sampling/priority_sampler.rb +4 -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 +4 -4
- data/lib/datadog/tracing/sampling/rule_sampler.rb +14 -12
- 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 +8 -8
- data/lib/datadog/tracing/span.rb +9 -9
- data/lib/datadog/tracing/span_event.rb +5 -5
- data/lib/datadog/tracing/span_operation.rb +22 -22
- data/lib/datadog/tracing/sync_writer.rb +12 -7
- data/lib/datadog/tracing/trace_digest.rb +22 -4
- data/lib/datadog/tracing/trace_operation.rb +33 -21
- data/lib/datadog/tracing/trace_segment.rb +10 -10
- data/lib/datadog/tracing/tracer.rb +43 -22
- 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/telemetry.rb +94 -0
- data/lib/datadog/tracing/transport/http/traces.rb +10 -8
- data/lib/datadog/tracing/transport/http.rb +10 -10
- data/lib/datadog/tracing/transport/io/client.rb +2 -2
- 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/telemetry.rb +17 -0
- data/lib/datadog/tracing/transport/native.rb +395 -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/telemetry.rb +62 -0
- data/lib/datadog/tracing/transport/trace_formatter.rb +23 -13
- data/lib/datadog/tracing/transport/traces.rb +93 -46
- data/lib/datadog/tracing/utils.rb +2 -2
- data/lib/datadog/tracing/workers.rb +2 -2
- 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 +13 -13
- metadata +55 -13
- data/lib/datadog/ai_guard/evaluation/content_builder.rb +0 -31
- data/lib/datadog/appsec/utils/hash_coercion.rb +0 -23
- data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +0 -69
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
//
|
|
43
43
|
// When `thread_context_collector_on_gc_start` gets called, the current cpu and wall-time get recorded to the thread
|
|
44
44
|
// context: `cpu_time_at_gc_start_ns` and `wall_time_at_gc_start_ns`.
|
|
45
|
+
// (Ruby won't switch threads during GC, so `gc_start` and `gc_finish` will happen on the same thread)
|
|
45
46
|
//
|
|
46
47
|
// While `cpu_time_at_gc_start_ns` is set, we don't expect the thread to be sampled: the VM is doing GC
|
|
47
48
|
// on the thread holding the GVL so no other samples can/will be triggered until GC finishes.
|
|
@@ -74,6 +75,11 @@
|
|
|
74
75
|
#define THREAD_ID_LIMIT_CHARS 44 // Why 44? "#{2**64} (#{2**64})".size + 1 for \0
|
|
75
76
|
#define THREAD_INVOKE_LOCATION_LIMIT_CHARS 512
|
|
76
77
|
#define MISSING_TRACER_CONTEXT_KEY 0
|
|
78
|
+
|
|
79
|
+
// Used as markers in the code
|
|
80
|
+
#define OTEL_CURRENT_SPAN_KEY_NOT_EXTRACTED INT2FIX(1)
|
|
81
|
+
#define OTEL_CURRENT_SPAN_KEY_EXTRACTION_NEEDED INT2FIX(2)
|
|
82
|
+
|
|
77
83
|
#define TIME_BETWEEN_GC_EVENTS_NS MILLIS_AS_NS(10)
|
|
78
84
|
#define GVL_SUSPENDED ((uint64_t)1)
|
|
79
85
|
#define GVL_RUNNING ((uint64_t)0)
|
|
@@ -106,7 +112,7 @@ static ID otel_fiber_context_storage_id; // id of :@opentelemetry_context in Rub
|
|
|
106
112
|
|
|
107
113
|
// This is mutable and gets set last-writer-wins style by
|
|
108
114
|
// `thread_context_collector_reset_all_per_thread_contexts`, which is called whenever
|
|
109
|
-
// profiling is starting or
|
|
115
|
+
// profiling is starting or restarting.
|
|
110
116
|
//
|
|
111
117
|
// Note: We must be careful to not change this value while the profiler is still running,
|
|
112
118
|
// otherwise new threads can get the new value and cause profiling to stop with an
|
|
@@ -148,17 +154,18 @@ typedef struct {
|
|
|
148
154
|
// Used to identify the main thread, to give it a fallback name
|
|
149
155
|
VALUE main_thread;
|
|
150
156
|
// Used when extracting trace identifiers from otel spans. Lazily initialized.
|
|
151
|
-
//
|
|
152
|
-
//
|
|
157
|
+
// * `OTEL_CURRENT_SPAN_KEY_NOT_EXTRACTED`: we've not needed it yet
|
|
158
|
+
// * `OTEL_CURRENT_SPAN_KEY_EXTRACTION_NEEDED`: a sample needed it, and it's waiting to be extracted
|
|
159
|
+
// * anything else: the extracted value, or Qnil if we tried to extract it and failed
|
|
153
160
|
VALUE otel_current_span_key;
|
|
154
161
|
// Used to enable native filenames in stack traces
|
|
155
162
|
bool native_filenames_enabled;
|
|
163
|
+
// Used to include class/module names in method names (e.g. "Foo#bar" instead of "bar")
|
|
164
|
+
bool show_classes;
|
|
156
165
|
// Used to cache native filename lookup results (Map[void *function_pointer, char *filename])
|
|
157
166
|
st_table *native_filenames_cache;
|
|
158
167
|
// Used to attribute overhead during sampling to this component
|
|
159
168
|
VALUE overhead_filename;
|
|
160
|
-
// Minimum duration of a "Waiting for GVL" period to trigger a sample
|
|
161
|
-
uint32_t waiting_for_gvl_threshold_ns;
|
|
162
169
|
|
|
163
170
|
struct stats {
|
|
164
171
|
// Track how many regular samples we've taken. Does not include garbage collection samples.
|
|
@@ -167,6 +174,8 @@ typedef struct {
|
|
|
167
174
|
unsigned int gc_samples;
|
|
168
175
|
// See thread_context_collector_on_gc_start for details
|
|
169
176
|
unsigned int gc_samples_missed_due_to_missing_context;
|
|
177
|
+
// See thread_context_collector_sample_after_gc for details
|
|
178
|
+
unsigned int gc_samples_skipped_nothing_to_flush;
|
|
170
179
|
// How many per-thread samples were skipped because the thread has been continuously suspended
|
|
171
180
|
// (no GVL) since its previous sample, so its Ruby stack cannot have changed.
|
|
172
181
|
unsigned int inactive_thread_samples_skipped;
|
|
@@ -260,7 +269,7 @@ struct per_thread_context {
|
|
|
260
269
|
bool was_skipped_at_last_sample;
|
|
261
270
|
// Set as true for CpuAndWallTimeWorker and IdleSamplingHelper threads.
|
|
262
271
|
// When true, per-tick samples are skipped entirely; the thread is sampled only once per
|
|
263
|
-
// reporting period during
|
|
272
|
+
// reporting period during prepare_serialize.
|
|
264
273
|
//
|
|
265
274
|
// These threads are always in native code so their stacks aren't interesting;
|
|
266
275
|
// the Profiling::Scheduler thread on the other hand does a lot of different
|
|
@@ -298,12 +307,11 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
|
|
|
298
307
|
static VALUE _native_sample(VALUE self, VALUE collector_instance, VALUE allow_exception);
|
|
299
308
|
static VALUE _native_on_gc_start(VALUE self, VALUE collector_instance);
|
|
300
309
|
static VALUE _native_on_gc_finish(VALUE self, VALUE collector_instance);
|
|
301
|
-
static VALUE _native_sample_after_gc(DDTRACE_UNUSED VALUE self, VALUE collector_instance
|
|
310
|
+
static VALUE _native_sample_after_gc(DDTRACE_UNUSED VALUE self, VALUE collector_instance);
|
|
302
311
|
static void update_metrics_and_sample(
|
|
303
312
|
thread_context_collector_state *state,
|
|
304
313
|
VALUE thread_being_sampled,
|
|
305
314
|
per_thread_context *thread_context,
|
|
306
|
-
long current_cpu_time_ns,
|
|
307
315
|
long current_monotonic_wall_time_ns,
|
|
308
316
|
bool force_sample
|
|
309
317
|
);
|
|
@@ -315,13 +323,12 @@ static void trigger_sample_for_thread(
|
|
|
315
323
|
long current_monotonic_wall_time_ns,
|
|
316
324
|
ddog_CharSlice *ruby_vm_type,
|
|
317
325
|
ddog_CharSlice *class_name,
|
|
318
|
-
bool is_gvl_waiting_state
|
|
319
|
-
bool is_safe_to_allocate_objects
|
|
326
|
+
bool is_gvl_waiting_state
|
|
320
327
|
);
|
|
321
328
|
static VALUE _native_thread_list(VALUE self);
|
|
322
329
|
static void check_frozen_thread(VALUE thread);
|
|
323
|
-
static per_thread_context *get_or_create_context_for(VALUE thread);
|
|
324
|
-
static void initialize_context(VALUE thread, per_thread_context *thread_context);
|
|
330
|
+
static per_thread_context *get_or_create_context_for(VALUE thread, long current_monotonic_wall_time_ns);
|
|
331
|
+
static void initialize_context(VALUE thread, per_thread_context *thread_context, long current_monotonic_wall_time_ns);
|
|
325
332
|
static VALUE _native_inspect(VALUE self, VALUE collector_instance);
|
|
326
333
|
static VALUE per_thread_context_to_ruby_hash(per_thread_context *thread_context);
|
|
327
334
|
static VALUE stats_to_ruby_hash(thread_context_collector_state *state, VALUE hash);
|
|
@@ -336,8 +343,7 @@ static VALUE _native_gc_tracking(VALUE self, VALUE collector_instance);
|
|
|
336
343
|
static void trace_identifiers_for(
|
|
337
344
|
thread_context_collector_state *state,
|
|
338
345
|
VALUE thread,
|
|
339
|
-
trace_identifiers *trace_identifiers_result
|
|
340
|
-
bool is_safe_to_allocate_objects
|
|
346
|
+
trace_identifiers *trace_identifiers_result
|
|
341
347
|
);
|
|
342
348
|
static bool should_collect_resource(VALUE root_span);
|
|
343
349
|
static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE collector_instance);
|
|
@@ -351,8 +357,7 @@ static void ddtrace_otel_trace_identifiers_for(
|
|
|
351
357
|
VALUE *root_span,
|
|
352
358
|
VALUE *numeric_span_id,
|
|
353
359
|
VALUE active_span,
|
|
354
|
-
VALUE otel_values
|
|
355
|
-
bool is_safe_to_allocate_objects
|
|
360
|
+
VALUE otel_values
|
|
356
361
|
);
|
|
357
362
|
static VALUE _native_sample_skipped_allocation_samples(DDTRACE_UNUSED VALUE self, VALUE collector_instance, VALUE skipped_samples);
|
|
358
363
|
static bool handle_gvl_waiting(
|
|
@@ -365,22 +370,24 @@ static VALUE _native_on_gvl_waiting(DDTRACE_UNUSED VALUE self, VALUE thread);
|
|
|
365
370
|
static VALUE _native_on_gvl_released(DDTRACE_UNUSED VALUE self, VALUE thread);
|
|
366
371
|
#ifndef NO_GVL_INSTRUMENTATION
|
|
367
372
|
static VALUE _native_gvl_waiting_at_for(DDTRACE_UNUSED VALUE self, VALUE thread);
|
|
368
|
-
static VALUE _native_on_gvl_running(DDTRACE_UNUSED VALUE self, VALUE
|
|
369
|
-
static VALUE _native_sample_after_gvl_running(DDTRACE_UNUSED VALUE self, VALUE collector_instance, VALUE thread
|
|
373
|
+
static VALUE _native_on_gvl_running(DDTRACE_UNUSED VALUE self, VALUE thread, VALUE waiting_for_gvl_threshold_ns);
|
|
374
|
+
static VALUE _native_sample_after_gvl_running(DDTRACE_UNUSED VALUE self, VALUE collector_instance, VALUE thread);
|
|
370
375
|
#endif
|
|
371
|
-
static VALUE
|
|
376
|
+
static VALUE _native_apply_delta_to_time_at_previous_sample_ns(int argc, VALUE *argv, DDTRACE_UNUSED VALUE self);
|
|
377
|
+
static VALUE _native_apply_delta_to_gvl_waiting_at_for(DDTRACE_UNUSED VALUE self, VALUE thread, VALUE delta_ns);
|
|
372
378
|
static void otel_without_ddtrace_trace_identifiers_for(
|
|
373
379
|
thread_context_collector_state *state,
|
|
374
380
|
VALUE thread,
|
|
375
|
-
trace_identifiers *trace_identifiers_result
|
|
376
|
-
bool is_safe_to_allocate_objects
|
|
381
|
+
trace_identifiers *trace_identifiers_result
|
|
377
382
|
);
|
|
378
383
|
static otel_span otel_span_from(VALUE otel_context, VALUE otel_current_span_key);
|
|
384
|
+
static bool is_otel_current_span_key_needed(thread_context_collector_state *state);
|
|
379
385
|
static uint64_t otel_span_id_to_uint(VALUE otel_span_id);
|
|
380
386
|
static VALUE safely_lookup_hash_without_going_into_ruby_code(VALUE hash, VALUE key);
|
|
381
387
|
static VALUE _native_system_epoch_time_now_ns(DDTRACE_UNUSED VALUE self, VALUE collector_instance);
|
|
382
388
|
static VALUE _native_prepare_sample_inside_signal_handler(DDTRACE_UNUSED VALUE self);
|
|
383
389
|
static VALUE _native_mark_thread_as_profiler_internal(DDTRACE_UNUSED VALUE self, VALUE thread);
|
|
390
|
+
static VALUE _native_prepare_serialize(DDTRACE_UNUSED VALUE self, VALUE collector_instance);
|
|
384
391
|
static VALUE _native_remove_per_thread_context_for(DDTRACE_UNUSED VALUE self, VALUE thread);
|
|
385
392
|
static VALUE _native_global_reset_per_thread_context(DDTRACE_UNUSED VALUE self, VALUE collector_instance);
|
|
386
393
|
static bool skip_sample(thread_context_collector_state *state, per_thread_context *thread_context, bool is_gvl_waiting_state, bool force_sample);
|
|
@@ -410,7 +417,7 @@ void collectors_thread_context_init(VALUE profiling_module) {
|
|
|
410
417
|
rb_define_singleton_method(testing_module, "_native_sample_allocation", _native_sample_allocation, 3);
|
|
411
418
|
rb_define_singleton_method(testing_module, "_native_on_gc_start", _native_on_gc_start, 1);
|
|
412
419
|
rb_define_singleton_method(testing_module, "_native_on_gc_finish", _native_on_gc_finish, 1);
|
|
413
|
-
rb_define_singleton_method(testing_module, "_native_sample_after_gc", _native_sample_after_gc,
|
|
420
|
+
rb_define_singleton_method(testing_module, "_native_sample_after_gc", _native_sample_after_gc, 1);
|
|
414
421
|
rb_define_singleton_method(testing_module, "_native_thread_list", _native_thread_list, 0);
|
|
415
422
|
rb_define_singleton_method(testing_module, "_native_per_thread_context", _native_per_thread_context, 1);
|
|
416
423
|
rb_define_singleton_method(testing_module, "_native_stats", _native_stats, 1);
|
|
@@ -422,14 +429,16 @@ void collectors_thread_context_init(VALUE profiling_module) {
|
|
|
422
429
|
rb_define_singleton_method(testing_module, "_native_remove_per_thread_context_for", _native_remove_per_thread_context_for, 1);
|
|
423
430
|
rb_define_singleton_method(testing_module, "_native_global_reset_per_thread_context", _native_global_reset_per_thread_context, 1);
|
|
424
431
|
rb_define_singleton_method(testing_module, "_native_mark_thread_as_profiler_internal", _native_mark_thread_as_profiler_internal, 1);
|
|
432
|
+
rb_define_singleton_method(testing_module, "_native_prepare_serialize", _native_prepare_serialize, 1);
|
|
425
433
|
rb_define_singleton_method(testing_module, "_native_on_gvl_waiting", _native_on_gvl_waiting, 1);
|
|
426
434
|
rb_define_singleton_method(testing_module, "_native_on_gvl_released", _native_on_gvl_released, 1);
|
|
427
435
|
#ifndef NO_GVL_INSTRUMENTATION
|
|
428
436
|
rb_define_singleton_method(testing_module, "_native_gvl_waiting_at_for", _native_gvl_waiting_at_for, 1);
|
|
429
437
|
rb_define_singleton_method(testing_module, "_native_on_gvl_running", _native_on_gvl_running, 2);
|
|
430
|
-
rb_define_singleton_method(testing_module, "_native_sample_after_gvl_running", _native_sample_after_gvl_running,
|
|
438
|
+
rb_define_singleton_method(testing_module, "_native_sample_after_gvl_running", _native_sample_after_gvl_running, 2);
|
|
431
439
|
#endif
|
|
432
|
-
rb_define_singleton_method(testing_module, "
|
|
440
|
+
rb_define_singleton_method(testing_module, "_native_apply_delta_to_time_at_previous_sample_ns", _native_apply_delta_to_time_at_previous_sample_ns, -1);
|
|
441
|
+
rb_define_singleton_method(testing_module, "_native_apply_delta_to_gvl_waiting_at_for", _native_apply_delta_to_gvl_waiting_at_for, 2);
|
|
433
442
|
|
|
434
443
|
at_active_span_id = rb_intern_const("@active_span");
|
|
435
444
|
at_active_trace_id = rb_intern_const("@active_trace");
|
|
@@ -493,7 +502,7 @@ static void thread_context_collector_typed_data_free(void *state_ptr) {
|
|
|
493
502
|
|
|
494
503
|
// Important: Remember that we're only guaranteed to see here what's been set in _native_new, aka
|
|
495
504
|
// pointers that have been set NULL there may still be NULL here.
|
|
496
|
-
|
|
505
|
+
sample_locations_free(&state->locations);
|
|
497
506
|
|
|
498
507
|
st_free_table(state->native_filenames_cache);
|
|
499
508
|
|
|
@@ -550,21 +559,20 @@ static VALUE _native_new(VALUE klass) {
|
|
|
550
559
|
// being leaked.
|
|
551
560
|
|
|
552
561
|
// Update this when modifying state struct
|
|
553
|
-
state->locations.ptr = NULL;
|
|
554
|
-
state->locations.len = 0;
|
|
555
562
|
state->recorder_instance = Qnil;
|
|
556
563
|
state->tracer_context_key = MISSING_TRACER_CONTEXT_KEY;
|
|
557
564
|
VALUE thread_list_buffer = rb_ary_new();
|
|
558
565
|
state->thread_list_buffer = thread_list_buffer;
|
|
559
566
|
state->endpoint_collection_enabled = true;
|
|
560
567
|
state->native_filenames_enabled = false;
|
|
568
|
+
state->show_classes = false;
|
|
561
569
|
state->native_filenames_cache = st_init_numtable();
|
|
562
570
|
state->otel_context_enabled = OTEL_CONTEXT_ENABLED_FALSE;
|
|
563
571
|
state->otel_context_source = OTEL_CONTEXT_SOURCE_UNKNOWN;
|
|
564
572
|
state->time_converter_state = (monotonic_to_system_epoch_state) MONOTONIC_TO_SYSTEM_EPOCH_INITIALIZER;
|
|
565
573
|
VALUE main_thread = rb_thread_main();
|
|
566
574
|
state->main_thread = main_thread;
|
|
567
|
-
state->otel_current_span_key =
|
|
575
|
+
state->otel_current_span_key = OTEL_CURRENT_SPAN_KEY_NOT_EXTRACTED;
|
|
568
576
|
state->gc_tracking.wall_time_at_previous_gc_ns = INVALID_TIME;
|
|
569
577
|
state->gc_tracking.wall_time_at_last_flushed_gc_event_ns = 0;
|
|
570
578
|
|
|
@@ -590,15 +598,15 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
|
|
|
590
598
|
VALUE max_frames = rb_hash_fetch(options, ID2SYM(rb_intern("max_frames")));
|
|
591
599
|
VALUE tracer_context_key = rb_hash_fetch(options, ID2SYM(rb_intern("tracer_context_key")));
|
|
592
600
|
VALUE endpoint_collection_enabled = rb_hash_fetch(options, ID2SYM(rb_intern("endpoint_collection_enabled")));
|
|
593
|
-
VALUE waiting_for_gvl_threshold_ns = rb_hash_fetch(options, ID2SYM(rb_intern("waiting_for_gvl_threshold_ns")));
|
|
594
601
|
VALUE otel_context_enabled = rb_hash_fetch(options, ID2SYM(rb_intern("otel_context_enabled")));
|
|
595
602
|
VALUE native_filenames_enabled = rb_hash_fetch(options, ID2SYM(rb_intern("native_filenames_enabled")));
|
|
603
|
+
VALUE show_classes = rb_hash_fetch(options, ID2SYM(rb_intern("show_classes")));
|
|
596
604
|
VALUE overhead_filename = rb_hash_fetch(options, ID2SYM(rb_intern("overhead_filename")));
|
|
597
605
|
|
|
598
606
|
ENFORCE_TYPE(max_frames, T_FIXNUM);
|
|
599
607
|
ENFORCE_BOOLEAN(endpoint_collection_enabled);
|
|
600
|
-
ENFORCE_TYPE(waiting_for_gvl_threshold_ns, T_FIXNUM);
|
|
601
608
|
ENFORCE_BOOLEAN(native_filenames_enabled);
|
|
609
|
+
ENFORCE_BOOLEAN(show_classes);
|
|
602
610
|
ENFORCE_TYPE(overhead_filename, T_STRING);
|
|
603
611
|
|
|
604
612
|
uint16_t max_frame_int = sampling_buffer_check_max_frames(NUM2INT(max_frames));
|
|
@@ -607,12 +615,11 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
|
|
|
607
615
|
TypedData_Get_Struct(self_instance, thread_context_collector_state, &thread_context_collector_typed_data, state);
|
|
608
616
|
|
|
609
617
|
// Update this when modifying state struct
|
|
610
|
-
state->locations
|
|
611
|
-
state->locations.ptr = ruby_xcalloc(max_frame_int, sizeof(ddog_prof_Location));
|
|
618
|
+
sample_locations_initialize(&state->locations, max_frame_int, show_classes == Qtrue);
|
|
612
619
|
state->recorder_instance = enforce_recorder_instance(recorder_instance);
|
|
613
|
-
recorder_install_on_serialize(recorder_instance, self_instance);
|
|
614
620
|
state->endpoint_collection_enabled = (endpoint_collection_enabled == Qtrue);
|
|
615
621
|
state->native_filenames_enabled = (native_filenames_enabled == Qtrue);
|
|
622
|
+
state->show_classes = (show_classes == Qtrue);
|
|
616
623
|
state->overhead_filename = overhead_filename;
|
|
617
624
|
if (otel_context_enabled == Qfalse || otel_context_enabled == Qnil) {
|
|
618
625
|
state->otel_context_enabled = OTEL_CONTEXT_ENABLED_FALSE;
|
|
@@ -624,8 +631,6 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
|
|
|
624
631
|
raise_error(rb_eArgError, "Unexpected value for otel_context_enabled: %+" PRIsVALUE, otel_context_enabled);
|
|
625
632
|
}
|
|
626
633
|
|
|
627
|
-
state->waiting_for_gvl_threshold_ns = NUM2UINT(waiting_for_gvl_threshold_ns);
|
|
628
|
-
|
|
629
634
|
if (RTEST(tracer_context_key)) {
|
|
630
635
|
ENFORCE_TYPE(tracer_context_key, T_SYMBOL);
|
|
631
636
|
// Note about rb_to_id and dynamic symbols: calling `rb_to_id` prevents symbols from ever being garbage collected.
|
|
@@ -649,10 +654,14 @@ static VALUE _native_sample(DDTRACE_UNUSED VALUE _self, VALUE collector_instance
|
|
|
649
654
|
|
|
650
655
|
if (allow_exception == Qfalse) debug_enter_unsafe_context();
|
|
651
656
|
|
|
652
|
-
|
|
657
|
+
bool needs_otel_span_key =
|
|
658
|
+
thread_context_collector_sample(collector_instance, monotonic_wall_time_now_ns());
|
|
653
659
|
|
|
654
660
|
if (allow_exception == Qfalse) debug_leave_unsafe_context();
|
|
655
661
|
|
|
662
|
+
// Same as the CpuAndWallTimeWorker does: this can't happen during a sample (and thus not inside the unsafe context)
|
|
663
|
+
if (needs_otel_span_key) thread_context_collector_resolve_otel_span_key_may_lose_gvl(collector_instance);
|
|
664
|
+
|
|
656
665
|
return Qtrue;
|
|
657
666
|
}
|
|
658
667
|
|
|
@@ -680,21 +689,19 @@ static VALUE _native_on_gc_finish(DDTRACE_UNUSED VALUE self, VALUE collector_ins
|
|
|
680
689
|
return Qtrue;
|
|
681
690
|
}
|
|
682
691
|
|
|
683
|
-
static VALUE _native_sample_after_gc(DDTRACE_UNUSED VALUE self, VALUE collector_instance
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
if (allow_exception == Qfalse) debug_enter_unsafe_context();
|
|
692
|
+
static VALUE _native_sample_after_gc(DDTRACE_UNUSED VALUE self, VALUE collector_instance) {
|
|
693
|
+
debug_enter_unsafe_context();
|
|
687
694
|
|
|
688
695
|
thread_context_collector_sample_after_gc(collector_instance);
|
|
689
696
|
|
|
690
|
-
|
|
697
|
+
debug_leave_unsafe_context();
|
|
691
698
|
|
|
692
699
|
return Qtrue;
|
|
693
700
|
}
|
|
694
701
|
|
|
695
702
|
// Record profiler sampling overhead as a placeholder stack
|
|
696
703
|
static void record_sampling_overhead(thread_context_collector_state *state, per_thread_context *current_thread_context) {
|
|
697
|
-
long wall_time_after_sampling = monotonic_wall_time_now_ns(
|
|
704
|
+
long wall_time_after_sampling = monotonic_wall_time_now_ns();
|
|
698
705
|
long cpu_time_after_sampling = cpu_time_now_ns(current_thread_context);
|
|
699
706
|
|
|
700
707
|
long overhead_cpu_time_ns = update_cpu_time_since_previous_sample(current_thread_context, cpu_time_after_sampling);
|
|
@@ -737,32 +744,38 @@ static void record_sampling_overhead(thread_context_collector_state *state, per_
|
|
|
737
744
|
// Assumption 3: This function IS NOT called from a signal handler. This function is not async-signal-safe.
|
|
738
745
|
// Assumption 4: This function IS NOT called in a reentrant way.
|
|
739
746
|
// Assumption 5: This function is called from the main Ractor (if Ruby has support for Ractors).
|
|
747
|
+
// Assumption 6: When called while the profiler is active, `during_sample` MUST be set.
|
|
740
748
|
//
|
|
741
|
-
|
|
749
|
+
bool thread_context_collector_sample(VALUE self_instance, long current_monotonic_wall_time_ns) {
|
|
742
750
|
thread_context_collector_state *state;
|
|
743
751
|
TypedData_Get_Struct(self_instance, thread_context_collector_state, &thread_context_collector_typed_data, state);
|
|
744
752
|
|
|
745
753
|
VALUE current_thread = rb_thread_current();
|
|
746
|
-
per_thread_context *current_thread_context = get_or_create_context_for(current_thread);
|
|
747
|
-
|
|
754
|
+
per_thread_context *current_thread_context = get_or_create_context_for(current_thread, current_monotonic_wall_time_ns);
|
|
755
|
+
|
|
756
|
+
// Sample the current thread (which will use the current CPU-time) first.
|
|
757
|
+
// This ensures any CPU-time the profiler spends sampling (e.g. the rest of the function) is not wrongly blamed on this thread,
|
|
758
|
+
// and instead is separately accounted by `record_sampling_overhead()` below.
|
|
759
|
+
update_metrics_and_sample(
|
|
760
|
+
state,
|
|
761
|
+
current_thread,
|
|
762
|
+
current_thread_context,
|
|
763
|
+
current_monotonic_wall_time_ns,
|
|
764
|
+
false);
|
|
748
765
|
|
|
749
766
|
VALUE threads = thread_list(state);
|
|
750
767
|
|
|
751
768
|
const long thread_count = RARRAY_LEN(threads);
|
|
752
769
|
for (long i = 0; i < thread_count; i++) {
|
|
753
|
-
VALUE thread =
|
|
754
|
-
|
|
770
|
+
VALUE thread = rb_ary_entry(threads, i);
|
|
771
|
+
ENFORCE_THREAD(thread);
|
|
755
772
|
|
|
756
|
-
|
|
757
|
-
// to avoid blaming the time the profiler took on whatever is currently running on the thread,
|
|
758
|
-
// and instead we report that time the profiler took as sampling overhead below.
|
|
759
|
-
long current_cpu_time_ns = (thread == current_thread) ? cpu_time_at_sample_start_for_current_thread : cpu_time_now_ns(thread_context);
|
|
773
|
+
if (thread == current_thread) continue; // Already sampled above
|
|
760
774
|
|
|
761
775
|
update_metrics_and_sample(
|
|
762
776
|
state,
|
|
763
777
|
thread,
|
|
764
|
-
|
|
765
|
-
current_cpu_time_ns,
|
|
778
|
+
get_or_create_context_for(thread, current_monotonic_wall_time_ns),
|
|
766
779
|
current_monotonic_wall_time_ns,
|
|
767
780
|
false);
|
|
768
781
|
}
|
|
@@ -778,41 +791,44 @@ void thread_context_collector_sample(VALUE self_instance, long current_monotonic
|
|
|
778
791
|
if (!current_thread_context->is_profiler_internal_thread) {
|
|
779
792
|
record_sampling_overhead(state, current_thread_context);
|
|
780
793
|
}
|
|
794
|
+
|
|
795
|
+
return is_otel_current_span_key_needed(state);
|
|
781
796
|
}
|
|
782
797
|
|
|
783
798
|
static void update_metrics_and_sample(
|
|
784
799
|
thread_context_collector_state *state,
|
|
785
800
|
VALUE thread_being_sampled,
|
|
786
801
|
per_thread_context *thread_context,
|
|
787
|
-
long current_cpu_time_ns,
|
|
788
802
|
long current_monotonic_wall_time_ns,
|
|
789
803
|
bool force_sample
|
|
790
804
|
) {
|
|
805
|
+
long current_cpu_time_ns = cpu_time_now_ns(thread_context);
|
|
791
806
|
bool is_gvl_waiting_state =
|
|
792
807
|
handle_gvl_waiting(state, thread_being_sampled, thread_context, current_cpu_time_ns);
|
|
793
808
|
|
|
794
809
|
if (skip_sample(state, thread_context, is_gvl_waiting_state, force_sample)) return;
|
|
795
810
|
|
|
796
|
-
// Don't assign/update cpu during "Waiting for GVL"
|
|
797
|
-
long cpu_time_elapsed_ns = is_gvl_waiting_state ? 0 : update_cpu_time_since_previous_sample(thread_context, current_cpu_time_ns);
|
|
798
|
-
|
|
799
|
-
long wall_time_elapsed_ns = update_wall_time_since_previous_sample(thread_context, current_monotonic_wall_time_ns);
|
|
800
|
-
|
|
801
811
|
// A thread enters "Waiting for GVL", well, as the name implies, without the GVL.
|
|
802
812
|
//
|
|
803
|
-
// As a consequence, it's possible
|
|
813
|
+
// As a consequence, it's possible for another thread to enter "Waiting for GVL" in parallel with the current thread working
|
|
804
814
|
// on sampling, and thus for the `current_monotonic_wall_time_ns` (which is recorded at the start of sampling)
|
|
805
|
-
// to be
|
|
815
|
+
// to be <= the time we observe for a "Waiting for GVL".
|
|
806
816
|
//
|
|
807
|
-
//
|
|
808
|
-
//
|
|
809
|
-
//
|
|
817
|
+
// When that happens, `handle_gvl_waiting` has already accounted for all wall-time up to the (later) start of the
|
|
818
|
+
// wait via the extra sample it pushes (see comments on that function), so there may be no remaining time
|
|
819
|
+
// to account for here.
|
|
820
|
+
// Thus, in this case, we don't want to produce a sample representing "Waiting for GVL" with a wall-time of 0 (nor negative!), and
|
|
810
821
|
// thus we skip creating such a sample.
|
|
811
|
-
if (is_gvl_waiting_state &&
|
|
822
|
+
if (is_gvl_waiting_state && current_monotonic_wall_time_ns <= thread_context->wall_time_at_previous_sample_ns) return;
|
|
812
823
|
// ...you may also wonder: is there any other situation where it makes sense to produce a sample with
|
|
813
824
|
// wall_time_elapsed_ns == 0? I believe that yes, because the sample still includes a timestamp and a stack, but we
|
|
814
825
|
// may revisit/change our minds on this in the future.
|
|
815
826
|
|
|
827
|
+
// Don't assign/update cpu during "Waiting for GVL"
|
|
828
|
+
long cpu_time_elapsed_ns = is_gvl_waiting_state ? 0 : update_cpu_time_since_previous_sample(thread_context, current_cpu_time_ns);
|
|
829
|
+
|
|
830
|
+
long wall_time_elapsed_ns = update_wall_time_since_previous_sample(thread_context, current_monotonic_wall_time_ns);
|
|
831
|
+
|
|
816
832
|
trigger_sample_for_thread(
|
|
817
833
|
state,
|
|
818
834
|
thread_being_sampled,
|
|
@@ -821,8 +837,7 @@ static void update_metrics_and_sample(
|
|
|
821
837
|
current_monotonic_wall_time_ns,
|
|
822
838
|
NULL,
|
|
823
839
|
NULL,
|
|
824
|
-
is_gvl_waiting_state
|
|
825
|
-
/* is_safe_to_allocate_objects: */ true // We called from a context that's safe to run any regular code, including allocations
|
|
840
|
+
is_gvl_waiting_state
|
|
826
841
|
);
|
|
827
842
|
}
|
|
828
843
|
|
|
@@ -838,7 +853,7 @@ static bool skip_sample(thread_context_collector_state *state, per_thread_contex
|
|
|
838
853
|
// Skip this per-tick sample entirely when the thread does not have the GVL and did not acquire
|
|
839
854
|
// it since the previous sample: its Ruby-level stack has not changed. The skipped wall-time will
|
|
840
855
|
// be picked up by either by an extra sample when the thread acquires the GVL, or by
|
|
841
|
-
//
|
|
856
|
+
// prepare_serialize (using was_skipped_at_last_sample).
|
|
842
857
|
// The check is gated by `!is_gvl_waiting_state` so the existing "Waiting for GVL" machinery
|
|
843
858
|
// in handle_gvl_waiting (situation 1 extra sample, situation 2 regular sample) keeps running.
|
|
844
859
|
// TODO: we could probably also skip while "Waiting for GVL"
|
|
@@ -883,11 +898,14 @@ void thread_context_collector_on_gc_start(VALUE self_instance) {
|
|
|
883
898
|
}
|
|
884
899
|
|
|
885
900
|
// Here we record the wall-time first and in on_gc_finish we record it second to try to avoid having wall-time be slightly < cpu-time
|
|
886
|
-
thread_context->gc_tracking.wall_time_at_start_ns = monotonic_wall_time_now_ns(
|
|
901
|
+
thread_context->gc_tracking.wall_time_at_start_ns = monotonic_wall_time_now_ns();
|
|
887
902
|
thread_context->gc_tracking.cpu_time_at_start_ns = cpu_time_now_ns(thread_context);
|
|
888
903
|
}
|
|
889
904
|
|
|
890
905
|
// This function gets called when Ruby has finished running the Garbage Collector on the current thread.
|
|
906
|
+
// (Note: The `GC_EXIT` event gets emitted by the VM while `during_gc` is still set to true -- the flag
|
|
907
|
+
// is only cleared after the event gets emitted -- see top of the file for more details)
|
|
908
|
+
//
|
|
891
909
|
// It records the cpu/wall-time observed during GC, which will be used to later
|
|
892
910
|
// create an event including the cpu/wall time spent from the start of garbage collector work until now.
|
|
893
911
|
//
|
|
@@ -912,7 +930,8 @@ bool thread_context_collector_on_gc_finish(VALUE self_instance) {
|
|
|
912
930
|
long cpu_time_at_start_ns = thread_context->gc_tracking.cpu_time_at_start_ns;
|
|
913
931
|
long wall_time_at_start_ns = thread_context->gc_tracking.wall_time_at_start_ns;
|
|
914
932
|
|
|
915
|
-
|
|
933
|
+
// Both fields are always set and cleared together, so checking one is enough
|
|
934
|
+
if (cpu_time_at_start_ns == INVALID_TIME) {
|
|
916
935
|
// If this happened, it means that on_gc_start was either never called for the thread OR it was called but no thread
|
|
917
936
|
// context existed at the time. The former can be the result of a bug, but since we can't distinguish them, we just
|
|
918
937
|
// do nothing.
|
|
@@ -925,16 +944,13 @@ bool thread_context_collector_on_gc_finish(VALUE self_instance) {
|
|
|
925
944
|
|
|
926
945
|
// Here we record the wall-time second and in on_gc_start we record it first to try to avoid having wall-time be slightly < cpu-time
|
|
927
946
|
long cpu_time_at_finish_ns = cpu_time_now_ns(thread_context);
|
|
928
|
-
long wall_time_at_finish_ns = monotonic_wall_time_now_ns(
|
|
929
|
-
|
|
930
|
-
// If our end timestamp is not OK, we bail out
|
|
931
|
-
if (wall_time_at_finish_ns == 0) return false;
|
|
947
|
+
long wall_time_at_finish_ns = monotonic_wall_time_now_ns();
|
|
932
948
|
|
|
933
949
|
long gc_cpu_time_elapsed_ns = cpu_time_at_finish_ns - cpu_time_at_start_ns;
|
|
934
950
|
long gc_wall_time_elapsed_ns = wall_time_at_finish_ns - wall_time_at_start_ns;
|
|
935
951
|
|
|
936
|
-
//
|
|
937
|
-
//
|
|
952
|
+
// @ivoanjo: We don't expect these clocks to ever go backwards (and in other code paths we enforce that with an exception)
|
|
953
|
+
// but during GC it's really really awkward to signal back failures so for now I left the clamping.
|
|
938
954
|
gc_cpu_time_elapsed_ns = long_max_of(gc_cpu_time_elapsed_ns, 0);
|
|
939
955
|
gc_wall_time_elapsed_ns = long_max_of(gc_wall_time_elapsed_ns, 0);
|
|
940
956
|
|
|
@@ -949,7 +965,7 @@ bool thread_context_collector_on_gc_finish(VALUE self_instance) {
|
|
|
949
965
|
|
|
950
966
|
// Update cpu-time accounting so it doesn't include the cpu-time spent in GC during the next sample.
|
|
951
967
|
// We don't do the same for wall-time, because GC is just like any other reason a thread didn't make
|
|
952
|
-
// progress -- time always goes forward regardless of the thread making progress on what it wanted.
|
|
968
|
+
// progress -- time always goes forward regardless of the thread making progress on what it wanted.
|
|
953
969
|
if (thread_context->cpu_time_at_previous_sample_ns != INVALID_TIME) {
|
|
954
970
|
thread_context->cpu_time_at_previous_sample_ns += gc_cpu_time_elapsed_ns;
|
|
955
971
|
}
|
|
@@ -957,10 +973,10 @@ bool thread_context_collector_on_gc_finish(VALUE self_instance) {
|
|
|
957
973
|
// Let the caller know if it should schedule a flush or not. Returning true every time would cause a lot of overhead
|
|
958
974
|
// on the application (see GC tracking introduction at the top of the file), so instead we try to accumulate a few
|
|
959
975
|
// samples first.
|
|
960
|
-
bool
|
|
976
|
+
bool over_flush_time_threshold =
|
|
961
977
|
(wall_time_at_finish_ns - state->gc_tracking.wall_time_at_last_flushed_gc_event_ns) >= TIME_BETWEEN_GC_EVENTS_NS;
|
|
962
978
|
|
|
963
|
-
if (
|
|
979
|
+
if (over_flush_time_threshold) {
|
|
964
980
|
return true;
|
|
965
981
|
} else {
|
|
966
982
|
return gc_profiling_has_major_gc_finished();
|
|
@@ -975,12 +991,20 @@ bool thread_context_collector_on_gc_finish(VALUE self_instance) {
|
|
|
975
991
|
// Assumption 2: This function is allowed to raise exceptions. Caller is responsible for handling them, if needed.
|
|
976
992
|
// Assumption 3: Unlike `on_gc_start` and `on_gc_finish`, this method is allowed to allocate memory as needed.
|
|
977
993
|
// Assumption 4: This function is called from the main Ractor (if Ruby has support for Ractors).
|
|
994
|
+
// Assumption 5: When called while the profiler is active, `during_sample` MUST be set.
|
|
978
995
|
VALUE thread_context_collector_sample_after_gc(VALUE self_instance) {
|
|
979
996
|
thread_context_collector_state *state;
|
|
980
997
|
TypedData_Get_Struct(self_instance, thread_context_collector_state, &thread_context_collector_typed_data, state);
|
|
981
998
|
|
|
982
999
|
if (state->gc_tracking.wall_time_at_previous_gc_ns == INVALID_TIME) {
|
|
983
|
-
|
|
1000
|
+
// Rarely, we might be called with nothing to do, as an earlier call already flushed the needed info.
|
|
1001
|
+
// This is because Ruby clears the "pending" flag for an entire batch of postponed jobs BEFORE running any of them
|
|
1002
|
+
// (see `rb_postponed_job_flush`). Thus, if another GC happens while an earlier job in the postponed batch is
|
|
1003
|
+
// running (and other parts of the profiler such as the heap profiler can trigger this)
|
|
1004
|
+
// then `on_gc_finish` records that data and asks for a second flush, even though Ruby has not yet run the
|
|
1005
|
+
// first one. Because of this, Ruby can call us once more with nothing left to do.
|
|
1006
|
+
state->stats.gc_samples_skipped_nothing_to_flush++;
|
|
1007
|
+
return Qnil;
|
|
984
1008
|
}
|
|
985
1009
|
|
|
986
1010
|
int max_labels_needed_for_gc = 7; // Magic number gets validated inside gc_profiling_set_metadata
|
|
@@ -1014,13 +1038,23 @@ VALUE thread_context_collector_sample_after_gc(VALUE self_instance) {
|
|
|
1014
1038
|
|
|
1015
1039
|
state->stats.gc_samples++;
|
|
1016
1040
|
|
|
1017
|
-
// Let recorder do any cleanup/updates it requires after a GC step.
|
|
1018
|
-
recorder_after_gc_step(state->recorder_instance);
|
|
1019
|
-
|
|
1020
1041
|
// Return a VALUE to make it easier to call this function from Ruby APIs that expect a return value (such as rb_rescue2)
|
|
1021
1042
|
return Qnil;
|
|
1022
1043
|
}
|
|
1023
1044
|
|
|
1045
|
+
// Let the recorder do any cleanup/updates it requires after a GC step.
|
|
1046
|
+
//
|
|
1047
|
+
// Assumption 1: This function is called in a thread that is holding the Global VM Lock. Caller is responsible for enforcing this.
|
|
1048
|
+
// Assumption 2: This function is allowed to raise exceptions. Caller is responsible for handling them, if needed.
|
|
1049
|
+
VALUE thread_context_collector_heap_update_may_lose_gvl(VALUE self_instance) {
|
|
1050
|
+
thread_context_collector_state *state;
|
|
1051
|
+
TypedData_Get_Struct(self_instance, thread_context_collector_state, &thread_context_collector_typed_data, state);
|
|
1052
|
+
|
|
1053
|
+
recorder_heap_update_may_lose_gvl(state->recorder_instance);
|
|
1054
|
+
|
|
1055
|
+
return Qnil; // for rb_rescue2
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1024
1058
|
static void trigger_sample_for_thread(
|
|
1025
1059
|
thread_context_collector_state *state,
|
|
1026
1060
|
VALUE thread_being_sampled,
|
|
@@ -1030,10 +1064,7 @@ static void trigger_sample_for_thread(
|
|
|
1030
1064
|
// These two labels are only used for allocation profiling; @ivoanjo: may want to refactor this at some point?
|
|
1031
1065
|
ddog_CharSlice *ruby_vm_type,
|
|
1032
1066
|
ddog_CharSlice *class_name,
|
|
1033
|
-
bool is_gvl_waiting_state
|
|
1034
|
-
// If the Ruby VM is at a state that can allocate objects safely, or not. Added for allocation profiling: we're not
|
|
1035
|
-
// allowed to allocate objects (or raise exceptions) when inside the NEWOBJ tracepoint.
|
|
1036
|
-
bool is_safe_to_allocate_objects
|
|
1067
|
+
bool is_gvl_waiting_state
|
|
1037
1068
|
) {
|
|
1038
1069
|
int max_label_count =
|
|
1039
1070
|
1 + // thread id
|
|
@@ -1071,11 +1102,11 @@ static void trigger_sample_for_thread(
|
|
|
1071
1102
|
}
|
|
1072
1103
|
|
|
1073
1104
|
trace_identifiers trace_identifiers_result = {.valid = false, .trace_endpoint = Qnil};
|
|
1074
|
-
trace_identifiers_for(state, thread_being_sampled, &trace_identifiers_result
|
|
1105
|
+
trace_identifiers_for(state, thread_being_sampled, &trace_identifiers_result);
|
|
1075
1106
|
|
|
1076
1107
|
if (!trace_identifiers_result.valid && state->otel_context_enabled != OTEL_CONTEXT_ENABLED_FALSE) {
|
|
1077
1108
|
// If we couldn't get something with ddtrace, let's see if we can get some trace identifiers from opentelemetry directly
|
|
1078
|
-
otel_without_ddtrace_trace_identifiers_for(state, thread_being_sampled, &trace_identifiers_result
|
|
1109
|
+
otel_without_ddtrace_trace_identifiers_for(state, thread_being_sampled, &trace_identifiers_result);
|
|
1079
1110
|
}
|
|
1080
1111
|
|
|
1081
1112
|
if (trace_identifiers_result.valid) {
|
|
@@ -1157,7 +1188,8 @@ static void trigger_sample_for_thread(
|
|
|
1157
1188
|
.is_gvl_waiting_state = is_gvl_waiting_state,
|
|
1158
1189
|
},
|
|
1159
1190
|
state->native_filenames_enabled,
|
|
1160
|
-
state->native_filenames_cache
|
|
1191
|
+
state->native_filenames_cache,
|
|
1192
|
+
state->show_classes
|
|
1161
1193
|
);
|
|
1162
1194
|
}
|
|
1163
1195
|
|
|
@@ -1183,14 +1215,14 @@ static void check_frozen_thread(VALUE thread) {
|
|
|
1183
1215
|
|
|
1184
1216
|
// See the docs on struct per_thread_context.
|
|
1185
1217
|
// This allocates a Ruby object and therefore needs the GVL and is not safe to call from RUBY_INTERNAL_EVENT_* hooks.
|
|
1186
|
-
static per_thread_context *get_or_create_context_for(VALUE thread) {
|
|
1218
|
+
static per_thread_context *get_or_create_context_for(VALUE thread, long current_monotonic_wall_time_ns) {
|
|
1187
1219
|
per_thread_context *thread_context = get_per_thread_context(thread);
|
|
1188
1220
|
if (thread_context != NULL) return thread_context;
|
|
1189
1221
|
|
|
1190
1222
|
check_frozen_thread(thread);
|
|
1191
1223
|
|
|
1192
1224
|
thread_context = calloc(1, sizeof(per_thread_context)); // See "note on calloc vs ruby_xcalloc use" in heap_recorder.c
|
|
1193
|
-
initialize_context(thread, thread_context);
|
|
1225
|
+
initialize_context(thread, thread_context, current_monotonic_wall_time_ns);
|
|
1194
1226
|
|
|
1195
1227
|
VALUE wrapper = TypedData_Wrap_Struct(rb_cObject, &per_thread_context_typed_data, thread_context);
|
|
1196
1228
|
rb_ivar_set(thread, dd_per_thread_context_id, wrapper);
|
|
@@ -1204,7 +1236,8 @@ static void on_thread_begin_event(VALUE tracepoint_data, DDTRACE_UNUSED void *un
|
|
|
1204
1236
|
|
|
1205
1237
|
VALUE thread = rb_tracearg_self(rb_tracearg_from_tracepoint(tracepoint_data));
|
|
1206
1238
|
ENFORCE_THREAD(thread);
|
|
1207
|
-
|
|
1239
|
+
|
|
1240
|
+
get_or_create_context_for(thread, monotonic_wall_time_now_ns());
|
|
1208
1241
|
}
|
|
1209
1242
|
|
|
1210
1243
|
#define LOGGING_GEM_PATH "/lib/logging/diagnostic_context.rb"
|
|
@@ -1228,7 +1261,7 @@ static bool is_logging_gem_monkey_patch(VALUE invoke_file_location) {
|
|
|
1228
1261
|
return strncmp(invoke_file + invoke_file_len - logging_gem_path_len, LOGGING_GEM_PATH, logging_gem_path_len) == 0;
|
|
1229
1262
|
}
|
|
1230
1263
|
|
|
1231
|
-
static void initialize_context(VALUE thread, per_thread_context *thread_context) {
|
|
1264
|
+
static void initialize_context(VALUE thread, per_thread_context *thread_context, long current_monotonic_wall_time_ns) {
|
|
1232
1265
|
// We always create per_thread_context's with latest_max_frames; that value is kept in sync with the
|
|
1233
1266
|
// active profiler's max_frames by the global reset that runs when profiling starts
|
|
1234
1267
|
// so we expect to always see here the latest correct value to be used.
|
|
@@ -1265,7 +1298,7 @@ static void initialize_context(VALUE thread, per_thread_context *thread_context)
|
|
|
1265
1298
|
|
|
1266
1299
|
thread_context->thread_cpu_time_id = thread_cpu_time_id_for(thread);
|
|
1267
1300
|
|
|
1268
|
-
thread_context->wall_time_at_previous_sample_ns =
|
|
1301
|
+
thread_context->wall_time_at_previous_sample_ns = current_monotonic_wall_time_ns;
|
|
1269
1302
|
thread_context->cpu_time_at_previous_sample_ns = cpu_time_now_ns(thread_context);
|
|
1270
1303
|
|
|
1271
1304
|
// These will only be used during a GC operation
|
|
@@ -1295,22 +1328,26 @@ void thread_context_collector_reset_all_per_thread_contexts(VALUE self_instance)
|
|
|
1295
1328
|
|
|
1296
1329
|
latest_max_frames = state->locations.len;
|
|
1297
1330
|
|
|
1331
|
+
long current_monotonic_wall_time_ns = monotonic_wall_time_now_ns();
|
|
1332
|
+
|
|
1298
1333
|
VALUE threads = thread_list(state);
|
|
1299
1334
|
const long thread_count = RARRAY_LEN(threads);
|
|
1300
1335
|
for (long i = 0; i < thread_count; i++) {
|
|
1301
1336
|
VALUE thread = rb_ary_entry(threads, i);
|
|
1337
|
+
ENFORCE_THREAD(thread);
|
|
1338
|
+
|
|
1302
1339
|
per_thread_context *thread_context = get_per_thread_context(thread);
|
|
1303
1340
|
if (thread_context != NULL) {
|
|
1304
1341
|
bool is_profiler_internal_thread = thread_context->is_profiler_internal_thread;
|
|
1305
1342
|
|
|
1306
1343
|
sampling_buffer_free(&thread_context->sampling_buffer);
|
|
1307
1344
|
memset(thread_context, 0, sizeof(per_thread_context));
|
|
1308
|
-
initialize_context(thread, thread_context);
|
|
1345
|
+
initialize_context(thread, thread_context, current_monotonic_wall_time_ns);
|
|
1309
1346
|
|
|
1310
1347
|
thread_context->is_profiler_internal_thread = is_profiler_internal_thread;
|
|
1311
1348
|
} else {
|
|
1312
1349
|
// If thread didn't have a context, let's trigger its creation
|
|
1313
|
-
get_or_create_context_for(thread);
|
|
1350
|
+
get_or_create_context_for(thread, current_monotonic_wall_time_ns);
|
|
1314
1351
|
}
|
|
1315
1352
|
}
|
|
1316
1353
|
}
|
|
@@ -1329,6 +1366,7 @@ static VALUE _native_inspect(DDTRACE_UNUSED VALUE _self, VALUE collector_instanc
|
|
|
1329
1366
|
rb_str_concat(result, rb_sprintf(" stats=%"PRIsVALUE, stats_to_ruby_hash(state, rb_hash_new())));
|
|
1330
1367
|
rb_str_concat(result, rb_sprintf(" endpoint_collection_enabled=%"PRIsVALUE, state->endpoint_collection_enabled ? Qtrue : Qfalse));
|
|
1331
1368
|
rb_str_concat(result, rb_sprintf(" native_filenames_enabled=%"PRIsVALUE, state->native_filenames_enabled ? Qtrue : Qfalse));
|
|
1369
|
+
rb_str_concat(result, rb_sprintf(" show_classes=%"PRIsVALUE, state->show_classes ? Qtrue : Qfalse));
|
|
1332
1370
|
// Note: `st_table_size()` is available from Ruby 3.2+ but not before
|
|
1333
1371
|
rb_str_concat(result, rb_sprintf(" native_filenames_cache_size=%zu", state->native_filenames_cache->num_entries));
|
|
1334
1372
|
rb_str_concat(result, rb_sprintf(" otel_context_enabled=%d", state->otel_context_enabled));
|
|
@@ -1340,7 +1378,6 @@ static VALUE _native_inspect(DDTRACE_UNUSED VALUE _self, VALUE collector_instanc
|
|
|
1340
1378
|
rb_str_concat(result, rb_sprintf(" main_thread=%"PRIsVALUE, state->main_thread));
|
|
1341
1379
|
rb_str_concat(result, rb_sprintf(" gc_tracking=%"PRIsVALUE, gc_tracking_as_ruby_hash(state)));
|
|
1342
1380
|
rb_str_concat(result, rb_sprintf(" otel_current_span_key=%"PRIsVALUE, state->otel_current_span_key));
|
|
1343
|
-
rb_str_concat(result, rb_sprintf(" waiting_for_gvl_threshold_ns=%u", state->waiting_for_gvl_threshold_ns));
|
|
1344
1381
|
|
|
1345
1382
|
return result;
|
|
1346
1383
|
}
|
|
@@ -1380,6 +1417,7 @@ static VALUE stats_to_ruby_hash(thread_context_collector_state *state, VALUE has
|
|
|
1380
1417
|
ID2SYM(rb_intern("sample_count")), /* => */ UINT2NUM(state->stats.sample_count),
|
|
1381
1418
|
ID2SYM(rb_intern("gc_samples")), /* => */ UINT2NUM(state->stats.gc_samples),
|
|
1382
1419
|
ID2SYM(rb_intern("gc_samples_missed_due_to_missing_context")), /* => */ UINT2NUM(state->stats.gc_samples_missed_due_to_missing_context),
|
|
1420
|
+
ID2SYM(rb_intern("gc_samples_skipped_nothing_to_flush")), /* => */ UINT2NUM(state->stats.gc_samples_skipped_nothing_to_flush),
|
|
1383
1421
|
ID2SYM(rb_intern("inactive_thread_samples_skipped")), /* => */ UINT2NUM(state->stats.inactive_thread_samples_skipped),
|
|
1384
1422
|
ID2SYM(rb_intern("profiler_thread_samples_skipped")), /* => */ UINT2NUM(state->stats.profiler_thread_samples_skipped),
|
|
1385
1423
|
};
|
|
@@ -1412,7 +1450,9 @@ static VALUE _native_per_thread_context(DDTRACE_UNUSED VALUE _self, VALUE collec
|
|
|
1412
1450
|
VALUE threads = thread_list(state);
|
|
1413
1451
|
const long thread_count = RARRAY_LEN(threads);
|
|
1414
1452
|
for (long i = 0; i < thread_count; i++) {
|
|
1415
|
-
VALUE thread =
|
|
1453
|
+
VALUE thread = rb_ary_entry(threads, i);
|
|
1454
|
+
ENFORCE_THREAD(thread);
|
|
1455
|
+
|
|
1416
1456
|
per_thread_context *thread_context = get_per_thread_context(thread);
|
|
1417
1457
|
if (thread_context != NULL) {
|
|
1418
1458
|
rb_hash_aset(result, thread, per_thread_context_to_ruby_hash(thread_context));
|
|
@@ -1422,9 +1462,6 @@ static VALUE _native_per_thread_context(DDTRACE_UNUSED VALUE _self, VALUE collec
|
|
|
1422
1462
|
}
|
|
1423
1463
|
|
|
1424
1464
|
static long update_time_since_previous_sample(long *time_at_previous_sample_ns, long current_time_ns, per_thread_context *thread_context) {
|
|
1425
|
-
// If we didn't have a time for the previous sample, we use the current one
|
|
1426
|
-
if (*time_at_previous_sample_ns == INVALID_TIME) *time_at_previous_sample_ns = current_time_ns;
|
|
1427
|
-
|
|
1428
1465
|
// We don't expect to be sampling a thread (and thus updating these counters) while Ruby is doing GC (between
|
|
1429
1466
|
// `thread_context_collector_on_gc_start` and `thread_context_collector_on_gc_finish`)
|
|
1430
1467
|
if (thread_context->gc_tracking.cpu_time_at_start_ns != INVALID_TIME) {
|
|
@@ -1435,7 +1472,7 @@ static long update_time_since_previous_sample(long *time_at_previous_sample_ns,
|
|
|
1435
1472
|
thread_context->thread_id,
|
|
1436
1473
|
thread_context->gc_tracking.cpu_time_at_start_ns,
|
|
1437
1474
|
thread_context->gc_tracking.wall_time_at_start_ns,
|
|
1438
|
-
monotonic_wall_time_now_ns(
|
|
1475
|
+
monotonic_wall_time_now_ns()
|
|
1439
1476
|
);
|
|
1440
1477
|
}
|
|
1441
1478
|
|
|
@@ -1446,16 +1483,20 @@ static long update_time_since_previous_sample(long *time_at_previous_sample_ns,
|
|
|
1446
1483
|
}
|
|
1447
1484
|
|
|
1448
1485
|
static long update_cpu_time_since_previous_sample(per_thread_context *thread_context, long current_cpu_time_ns) {
|
|
1486
|
+
// A previous `cpu_time_now_ns` may have failed to read the clock and thus invalidated our baseline; in that case we
|
|
1487
|
+
// use the current time, so this sample gets no cpu-time and the next one gets an accurate delta.
|
|
1488
|
+
// Note wall-time never needs this: it is always seeded with a real value in `initialize_context`.
|
|
1489
|
+
if (thread_context->cpu_time_at_previous_sample_ns == INVALID_TIME) {
|
|
1490
|
+
thread_context->cpu_time_at_previous_sample_ns = current_cpu_time_ns;
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1449
1493
|
long elapsed_time_ns = update_time_since_previous_sample(
|
|
1450
1494
|
&thread_context->cpu_time_at_previous_sample_ns,
|
|
1451
1495
|
current_cpu_time_ns,
|
|
1452
1496
|
thread_context
|
|
1453
1497
|
);
|
|
1454
1498
|
|
|
1455
|
-
|
|
1456
|
-
if (elapsed_time_ns < 0) {
|
|
1457
|
-
raise_error(rb_eRuntimeError, "BUG: Unexpected CPU time going backwards between samples");
|
|
1458
|
-
}
|
|
1499
|
+
if (elapsed_time_ns < 0) raise_error(rb_eRuntimeError, "BUG: Unexpected CPU time going backwards between samples");
|
|
1459
1500
|
|
|
1460
1501
|
return elapsed_time_ns;
|
|
1461
1502
|
}
|
|
@@ -1467,11 +1508,9 @@ static long update_wall_time_since_previous_sample(per_thread_context *thread_co
|
|
|
1467
1508
|
thread_context
|
|
1468
1509
|
);
|
|
1469
1510
|
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
// https://github.com/DataDog/dd-trace-rb/pull/2336.
|
|
1474
|
-
return long_max_of(elapsed_time_ns, 0);
|
|
1511
|
+
if (elapsed_time_ns < 0) raise_error(rb_eRuntimeError, "BUG: Unexpected wall time going backwards between samples");
|
|
1512
|
+
|
|
1513
|
+
return elapsed_time_ns;
|
|
1475
1514
|
}
|
|
1476
1515
|
|
|
1477
1516
|
// Safety: This function is assumed never to raise exceptions by callers
|
|
@@ -1510,14 +1549,14 @@ VALUE enforce_thread_context_collector_instance(VALUE object) {
|
|
|
1510
1549
|
return object;
|
|
1511
1550
|
}
|
|
1512
1551
|
|
|
1513
|
-
//
|
|
1514
|
-
//
|
|
1515
|
-
//
|
|
1516
|
-
void
|
|
1552
|
+
// Commit any pending heap allocation recordings.
|
|
1553
|
+
// Recording an allocation only puts it on a pending list, because taking the weak reference the heap profiler needs
|
|
1554
|
+
// can't be done from inside the NEWOBJ tracepoint -- see `heap_recorder_commit_recordings_may_lose_gvl`.
|
|
1555
|
+
void thread_context_collector_commit_heap_recordings_may_lose_gvl(VALUE self_instance) {
|
|
1517
1556
|
thread_context_collector_state *state;
|
|
1518
1557
|
TypedData_Get_Struct(self_instance, thread_context_collector_state, &thread_context_collector_typed_data, state);
|
|
1519
1558
|
|
|
1520
|
-
|
|
1559
|
+
recorder_commit_heap_recordings_may_lose_gvl(state->recorder_instance);
|
|
1521
1560
|
}
|
|
1522
1561
|
|
|
1523
1562
|
// This method exists only to enable testing Datadog::Profiling::Collectors::ThreadContext behavior using RSpec.
|
|
@@ -1542,8 +1581,7 @@ static VALUE _native_gc_tracking(DDTRACE_UNUSED VALUE _self, VALUE collector_ins
|
|
|
1542
1581
|
static void trace_identifiers_for(
|
|
1543
1582
|
thread_context_collector_state *state,
|
|
1544
1583
|
VALUE thread,
|
|
1545
|
-
trace_identifiers *trace_identifiers_result
|
|
1546
|
-
bool is_safe_to_allocate_objects
|
|
1584
|
+
trace_identifiers *trace_identifiers_result
|
|
1547
1585
|
) {
|
|
1548
1586
|
if (state->otel_context_enabled == OTEL_CONTEXT_ENABLED_ONLY) return;
|
|
1549
1587
|
if (state->tracer_context_key == MISSING_TRACER_CONTEXT_KEY) return;
|
|
@@ -1564,7 +1602,7 @@ static void trace_identifiers_for(
|
|
|
1564
1602
|
VALUE numeric_span_id = Qnil;
|
|
1565
1603
|
|
|
1566
1604
|
if (otel_values != Qnil) {
|
|
1567
|
-
ddtrace_otel_trace_identifiers_for(state, &active_trace, &root_span, &numeric_span_id, active_span, otel_values
|
|
1605
|
+
ddtrace_otel_trace_identifiers_for(state, &active_trace, &root_span, &numeric_span_id, active_span, otel_values);
|
|
1568
1606
|
}
|
|
1569
1607
|
|
|
1570
1608
|
if (root_span == Qnil || (active_span == Qnil && numeric_span_id == Qnil)) return;
|
|
@@ -1645,14 +1683,7 @@ static VALUE thread_list(thread_context_collector_state *state) {
|
|
|
1645
1683
|
return result;
|
|
1646
1684
|
}
|
|
1647
1685
|
|
|
1648
|
-
|
|
1649
|
-
// the current thread.
|
|
1650
|
-
//
|
|
1651
|
-
// Assumptions for this function are same as for `thread_context_collector_sample` except that this function is
|
|
1652
|
-
// expected to be called from a signal handler and to be async-signal-safe.
|
|
1653
|
-
//
|
|
1654
|
-
// Also, no allocation (Ruby or malloc) can happen.
|
|
1655
|
-
bool thread_context_collector_prepare_sample_inside_signal_handler(void) {
|
|
1686
|
+
static inline bool thread_context_collector_prepare_sample_internal(void) {
|
|
1656
1687
|
VALUE current_thread = rb_thread_current();
|
|
1657
1688
|
per_thread_context *thread_context = get_per_thread_context(current_thread);
|
|
1658
1689
|
if (thread_context == NULL) return false;
|
|
@@ -1660,13 +1691,26 @@ bool thread_context_collector_prepare_sample_inside_signal_handler(void) {
|
|
|
1660
1691
|
return prepare_sample_thread(current_thread, &thread_context->sampling_buffer);
|
|
1661
1692
|
}
|
|
1662
1693
|
|
|
1663
|
-
//
|
|
1664
|
-
// Ruby
|
|
1694
|
+
// Called from a signal handler on the main Ractor with the GVL held, outside GC and with `during_sample` unset.
|
|
1695
|
+
// Must remain async-signal-safe: no allocation (Ruby or malloc), exceptions, or releasing the GVL.
|
|
1696
|
+
bool thread_context_collector_prepare_sample_inside_signal_handler(void) {
|
|
1697
|
+
return thread_context_collector_prepare_sample_internal();
|
|
1698
|
+
}
|
|
1699
|
+
|
|
1700
|
+
// Called at RUBY_INTERNAL_EVENT_GC_EXIT on the main Ractor with the GVL held; `during_sample` MUST be set to prevent reentrancy.
|
|
1701
|
+
// Ruby is still doing GC: no allocation (Ruby or malloc), exceptions, or releasing the GVL.
|
|
1702
|
+
void thread_context_collector_prepare_sample_on_gc_finish(void) {
|
|
1703
|
+
thread_context_collector_prepare_sample_internal();
|
|
1704
|
+
}
|
|
1705
|
+
|
|
1706
|
+
// This method gets called from inside the RUBY_INTERNAL_EVENT_NEWOBJ tracepoint so it should neither allocate in the
|
|
1707
|
+
// Ruby heap nor release the GVL (https://github.com/DataDog/dd-trace-rb/pull/4240).
|
|
1665
1708
|
//
|
|
1666
|
-
// Returns true if
|
|
1667
|
-
// tracepoint, such as allocate new objects), and false if it doesn't
|
|
1709
|
+
// Returns true if `thread_context_collector_commit_heap_recordings_may_lose_gvl` needs to be called (to do work
|
|
1710
|
+
// that can't be done from inside the tracepoint, such as allocate new objects), and false if it doesn't
|
|
1668
1711
|
//
|
|
1669
|
-
// The callers must ensure thread_context is non-NULL.
|
|
1712
|
+
// Assumption 1: The callers must ensure thread_context is non-NULL.
|
|
1713
|
+
// Assumption 2: When called while the profiler is active, `during_sample` MUST be set.
|
|
1670
1714
|
bool thread_context_collector_sample_allocation(VALUE self_instance, per_thread_context *thread_context, unsigned int sample_weight, VALUE new_object) {
|
|
1671
1715
|
thread_context_collector_state *state;
|
|
1672
1716
|
TypedData_Get_Struct(self_instance, thread_context_collector_state, &thread_context_collector_typed_data, state);
|
|
@@ -1709,13 +1753,10 @@ bool thread_context_collector_sample_allocation(VALUE self_instance, per_thread_
|
|
|
1709
1753
|
// Thus, we need to make sure there's actually a class before getting its name.
|
|
1710
1754
|
|
|
1711
1755
|
if (klass != 0) {
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
if (name_length > 0) {
|
|
1716
|
-
class_name = (ddog_CharSlice) {.ptr = name, .len = name_length};
|
|
1756
|
+
VALUE name = ddtrace_alloc_free_rb_mod_name(klass);
|
|
1757
|
+
if (name != Qnil) {
|
|
1758
|
+
class_name = char_slice_from_ruby_string(name);
|
|
1717
1759
|
} else {
|
|
1718
|
-
// @ivoanjo: I'm not sure this can ever happen, but just-in-case
|
|
1719
1760
|
class_name = ruby_value_type_to_class_name(type);
|
|
1720
1761
|
}
|
|
1721
1762
|
} else {
|
|
@@ -1735,23 +1776,22 @@ bool thread_context_collector_sample_allocation(VALUE self_instance, per_thread_
|
|
|
1735
1776
|
class_name = ruby_vm_type; // For other weird internal things we just use the VM type
|
|
1736
1777
|
}
|
|
1737
1778
|
|
|
1738
|
-
bool needs_after_allocation = track_object(state->recorder_instance, new_object, sample_weight, class_name);
|
|
1739
|
-
|
|
1740
1779
|
VALUE current_thread = rb_thread_current();
|
|
1741
1780
|
|
|
1781
|
+
heap_sample_values heap_sample = {.new_object = new_object, .alloc_class = class_name};
|
|
1782
|
+
|
|
1742
1783
|
trigger_sample_for_thread(
|
|
1743
1784
|
state,
|
|
1744
1785
|
current_thread,
|
|
1745
1786
|
thread_context,
|
|
1746
|
-
(sample_values) {.alloc_samples = sample_weight, .alloc_samples_unscaled = 1, .heap_sample =
|
|
1787
|
+
(sample_values) {.alloc_samples = sample_weight, .alloc_samples_unscaled = 1, .heap_sample = &heap_sample},
|
|
1747
1788
|
INVALID_TIME, // For now we're not collecting timestamps for allocation events, as per profiling team internal discussions
|
|
1748
1789
|
&ruby_vm_type,
|
|
1749
1790
|
&class_name,
|
|
1750
|
-
/* is_gvl_waiting_state: */ false
|
|
1751
|
-
/* is_safe_to_allocate_objects: */ false // Not safe to allocate further inside the NEWOBJ tracepoint
|
|
1791
|
+
/* is_gvl_waiting_state: */ false
|
|
1752
1792
|
);
|
|
1753
1793
|
|
|
1754
|
-
return
|
|
1794
|
+
return heap_sample.out_needs_commit;
|
|
1755
1795
|
}
|
|
1756
1796
|
|
|
1757
1797
|
// This method exists only to enable testing Datadog::Profiling::Collectors::ThreadContext behavior using RSpec.
|
|
@@ -1764,13 +1804,13 @@ static VALUE _native_sample_allocation(DDTRACE_UNUSED VALUE self, VALUE collecto
|
|
|
1764
1804
|
|
|
1765
1805
|
debug_enter_unsafe_context();
|
|
1766
1806
|
|
|
1767
|
-
bool
|
|
1807
|
+
bool needs_commit = thread_context_collector_sample_allocation(collector_instance, thread_context, NUM2UINT(sample_weight), new_object);
|
|
1768
1808
|
|
|
1769
1809
|
debug_leave_unsafe_context();
|
|
1770
1810
|
|
|
1771
1811
|
// We could instead choose to automatically trigger the after allocation here; yet, it seems kinda nice to keep it manual for
|
|
1772
1812
|
// the tests so we can pull on each lever separately and observe "the sausage being made" in steps
|
|
1773
|
-
return
|
|
1813
|
+
return needs_commit ? Qtrue : Qfalse;
|
|
1774
1814
|
}
|
|
1775
1815
|
|
|
1776
1816
|
static VALUE new_empty_thread_inner(DDTRACE_UNUSED void *arg) {
|
|
@@ -1820,26 +1860,57 @@ static VALUE read_otel_current_span_key_const(DDTRACE_UNUSED VALUE _unused) {
|
|
|
1820
1860
|
return rb_const_get(trace_module, rb_intern("CURRENT_SPAN_KEY"));
|
|
1821
1861
|
}
|
|
1822
1862
|
|
|
1823
|
-
static VALUE
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
// Calling read_otel_current_span_key_const below can trigger exceptions and arbitrary Ruby code running (e.g.
|
|
1827
|
-
// `const_missing`, etc). Not safe to call in this situation, so we just skip otel info for this sample.
|
|
1828
|
-
return Qnil;
|
|
1829
|
-
}
|
|
1830
|
-
|
|
1831
|
-
// If this fails, we want to fail gracefully, rather than raise an exception (e.g. if the opentelemetry gem
|
|
1832
|
-
// gets refactored, we should not fall on our face)
|
|
1833
|
-
VALUE span_key = rb_protect(read_otel_current_span_key_const, Qnil, NULL);
|
|
1834
|
-
rb_set_errinfo(Qnil); // **Clear any pending exception after ignoring it**
|
|
1863
|
+
static VALUE otel_current_span_key_not_found(DDTRACE_UNUSED VALUE _unused, DDTRACE_UNUSED VALUE _exception) {
|
|
1864
|
+
return Qnil;
|
|
1865
|
+
}
|
|
1835
1866
|
|
|
1836
|
-
|
|
1837
|
-
|
|
1867
|
+
static VALUE get_otel_current_span_key(thread_context_collector_state *state) {
|
|
1868
|
+
if (state->otel_current_span_key == OTEL_CURRENT_SPAN_KEY_NOT_EXTRACTED) {
|
|
1869
|
+
// Extracting this needs calling into Ruby code, which we don't want to do in the middle of a sample.
|
|
1870
|
+
// So instead we signal that we want this, and let it be resolved separately.
|
|
1871
|
+
state->otel_current_span_key = OTEL_CURRENT_SPAN_KEY_EXTRACTION_NEEDED;
|
|
1872
|
+
return Qnil;
|
|
1838
1873
|
}
|
|
1839
1874
|
|
|
1875
|
+
// We asked for it, but it hasn't been extracted yet
|
|
1876
|
+
if (is_otel_current_span_key_needed(state)) return Qnil;
|
|
1877
|
+
|
|
1840
1878
|
return state->otel_current_span_key;
|
|
1841
1879
|
}
|
|
1842
1880
|
|
|
1881
|
+
static bool is_otel_current_span_key_needed(thread_context_collector_state *state) {
|
|
1882
|
+
return state->otel_current_span_key == OTEL_CURRENT_SPAN_KEY_EXTRACTION_NEEDED;
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1885
|
+
// Extracts `otel_current_span_key`, if a sample asked for it (see `get_otel_current_span_key`).
|
|
1886
|
+
// This is deliberately not done during sampling because we can lose the GVL.
|
|
1887
|
+
//
|
|
1888
|
+
// Assumption 1: This function is called in a thread that is holding the Global VM Lock. Caller is responsible for enforcing this.
|
|
1889
|
+
void thread_context_collector_resolve_otel_span_key_may_lose_gvl(VALUE self_instance) {
|
|
1890
|
+
thread_context_collector_state *state;
|
|
1891
|
+
TypedData_Get_Struct(self_instance, thread_context_collector_state, &thread_context_collector_typed_data, state);
|
|
1892
|
+
|
|
1893
|
+
if (!is_otel_current_span_key_needed(state)) return;
|
|
1894
|
+
|
|
1895
|
+
// If this fails, we want to fail gracefully, rather than raise an exception (e.g. if the opentelemetry gem
|
|
1896
|
+
// gets refactored, we should not fall on our face).
|
|
1897
|
+
//
|
|
1898
|
+
// Note that we use `rb_rescue2` and not `rb_protect` so that we only swallow exceptions: anything else that can
|
|
1899
|
+
// unwind through here (e.g. a `Thread#kill`) is not ours to swallow. `rb_rescue2` also takes care of restoring
|
|
1900
|
+
// any previously-pending exception for us.
|
|
1901
|
+
VALUE span_key = rb_rescue2(
|
|
1902
|
+
read_otel_current_span_key_const,
|
|
1903
|
+
Qnil,
|
|
1904
|
+
otel_current_span_key_not_found,
|
|
1905
|
+
Qnil,
|
|
1906
|
+
rb_eException, // rb_eException is the base class of all Ruby exceptions
|
|
1907
|
+
0 // Required by API to be the last argument
|
|
1908
|
+
);
|
|
1909
|
+
|
|
1910
|
+
// Note that this gets set to Qnil if we failed to extract the correct value, and thus we won't try to extract it again
|
|
1911
|
+
state->otel_current_span_key = span_key;
|
|
1912
|
+
}
|
|
1913
|
+
|
|
1843
1914
|
// This method gets used when ddtrace is being used indirectly via the opentelemetry APIs. Information gets stored slightly
|
|
1844
1915
|
// differently, and this codepath handles it.
|
|
1845
1916
|
static void ddtrace_otel_trace_identifiers_for(
|
|
@@ -1848,8 +1919,7 @@ static void ddtrace_otel_trace_identifiers_for(
|
|
|
1848
1919
|
VALUE *root_span,
|
|
1849
1920
|
VALUE *numeric_span_id,
|
|
1850
1921
|
VALUE active_span,
|
|
1851
|
-
VALUE otel_values
|
|
1852
|
-
bool is_safe_to_allocate_objects
|
|
1922
|
+
VALUE otel_values
|
|
1853
1923
|
) {
|
|
1854
1924
|
VALUE resolved_numeric_span_id =
|
|
1855
1925
|
active_span == Qnil ?
|
|
@@ -1860,7 +1930,7 @@ static void ddtrace_otel_trace_identifiers_for(
|
|
|
1860
1930
|
|
|
1861
1931
|
if (resolved_numeric_span_id == Qnil) return;
|
|
1862
1932
|
|
|
1863
|
-
VALUE otel_current_span_key = get_otel_current_span_key(state
|
|
1933
|
+
VALUE otel_current_span_key = get_otel_current_span_key(state);
|
|
1864
1934
|
if (otel_current_span_key == Qnil) return;
|
|
1865
1935
|
VALUE current_trace = *active_trace;
|
|
1866
1936
|
|
|
@@ -1886,6 +1956,7 @@ static void ddtrace_otel_trace_identifiers_for(
|
|
|
1886
1956
|
*numeric_span_id = resolved_numeric_span_id;
|
|
1887
1957
|
}
|
|
1888
1958
|
|
|
1959
|
+
// Assumption 1: When called while the profiler is active, `during_sample` MUST be set.
|
|
1889
1960
|
void thread_context_collector_sample_skipped_allocation_samples(VALUE self_instance, unsigned int skipped_samples) {
|
|
1890
1961
|
thread_context_collector_state *state;
|
|
1891
1962
|
TypedData_Get_Struct(self_instance, thread_context_collector_state, &thread_context_collector_typed_data, state);
|
|
@@ -1980,15 +2051,14 @@ static VALUE _native_sample_skipped_allocation_samples(DDTRACE_UNUSED VALUE self
|
|
|
1980
2051
|
static void otel_without_ddtrace_trace_identifiers_for(
|
|
1981
2052
|
thread_context_collector_state *state,
|
|
1982
2053
|
VALUE thread,
|
|
1983
|
-
trace_identifiers *trace_identifiers_result
|
|
1984
|
-
bool is_safe_to_allocate_objects
|
|
2054
|
+
trace_identifiers *trace_identifiers_result
|
|
1985
2055
|
) {
|
|
1986
2056
|
VALUE context_storage = otel_context_storage_for(state, thread);
|
|
1987
2057
|
|
|
1988
2058
|
// If it exists, context_storage is expected to be an Array[OpenTelemetry::Context]
|
|
1989
2059
|
if (context_storage == Qnil || !RB_TYPE_P(context_storage, T_ARRAY)) return;
|
|
1990
2060
|
|
|
1991
|
-
VALUE otel_current_span_key = get_otel_current_span_key(state
|
|
2061
|
+
VALUE otel_current_span_key = get_otel_current_span_key(state);
|
|
1992
2062
|
if (otel_current_span_key == Qnil) return;
|
|
1993
2063
|
|
|
1994
2064
|
long active_context_index = RARRAY_LEN(context_storage) - 1;
|
|
@@ -2086,70 +2156,79 @@ static void mark_thread_as_profiler_internal(per_thread_context *ctx) {
|
|
|
2086
2156
|
}
|
|
2087
2157
|
|
|
2088
2158
|
void thread_context_collector_profiler_internal_thread_started(void) {
|
|
2089
|
-
per_thread_context *ctx = get_or_create_context_for(rb_thread_current());
|
|
2159
|
+
per_thread_context *ctx = get_or_create_context_for(rb_thread_current(), monotonic_wall_time_now_ns());
|
|
2090
2160
|
mark_thread_as_profiler_internal(ctx);
|
|
2091
2161
|
}
|
|
2092
2162
|
|
|
2093
2163
|
static VALUE _native_mark_thread_as_profiler_internal(DDTRACE_UNUSED VALUE self, VALUE thread) {
|
|
2094
|
-
per_thread_context *ctx = get_or_create_context_for(thread);
|
|
2164
|
+
per_thread_context *ctx = get_or_create_context_for(thread, monotonic_wall_time_now_ns());
|
|
2095
2165
|
mark_thread_as_profiler_internal(ctx);
|
|
2096
2166
|
return Qnil;
|
|
2097
2167
|
}
|
|
2098
2168
|
|
|
2099
2169
|
// Called via rb_ensure when a profiler-internal thread (worker or idle helper) is about to exit.
|
|
2100
|
-
// Records a final sample so the thread's accumulated cpu/wall time since the last
|
|
2101
|
-
//
|
|
2170
|
+
// Records a final sample so the thread's accumulated cpu/wall time since the last prepare_serialize
|
|
2171
|
+
// is not lost. prepare_serialize (below) also flushes profiler-internal threads during periodic
|
|
2102
2172
|
// serialization, but it can't help at shutdown: by the time the final serialize runs, these
|
|
2103
2173
|
// threads are already dead and absent from thread_list.
|
|
2104
|
-
|
|
2174
|
+
//
|
|
2175
|
+
// Assumption 1: When called while the profiler is active, `during_sample` MUST be set.
|
|
2176
|
+
VALUE thread_context_collector_profiler_internal_thread_done(VALUE self_instance) {
|
|
2105
2177
|
thread_context_collector_state *state;
|
|
2106
2178
|
TypedData_Get_Struct(self_instance, thread_context_collector_state, &thread_context_collector_typed_data, state);
|
|
2107
2179
|
|
|
2108
2180
|
VALUE current_thread = rb_thread_current();
|
|
2109
|
-
|
|
2181
|
+
long current_monotonic_wall_time_ns = monotonic_wall_time_now_ns();
|
|
2182
|
+
per_thread_context *thread_context = get_or_create_context_for(current_thread, current_monotonic_wall_time_ns);
|
|
2110
2183
|
if (!thread_context->is_profiler_internal_thread) {
|
|
2111
2184
|
rb_raise(rb_eRuntimeError, "current thread %"PRIsVALUE" is not profiler-internal thread", current_thread);
|
|
2112
2185
|
}
|
|
2113
2186
|
|
|
2114
|
-
long current_cpu_time_ns = cpu_time_now_ns(thread_context);
|
|
2115
|
-
long current_monotonic_wall_time_ns = monotonic_wall_time_now_ns(RAISE_ON_FAILURE);
|
|
2116
|
-
|
|
2117
2187
|
update_metrics_and_sample(
|
|
2118
2188
|
state,
|
|
2119
2189
|
current_thread,
|
|
2120
2190
|
thread_context,
|
|
2121
|
-
current_cpu_time_ns,
|
|
2122
2191
|
current_monotonic_wall_time_ns,
|
|
2123
2192
|
true);
|
|
2193
|
+
|
|
2194
|
+
return Qnil;
|
|
2124
2195
|
}
|
|
2125
2196
|
|
|
2126
2197
|
// Flushes threads whose last per-tick sample was skipped (either by the SUSPENDED-skip
|
|
2127
2198
|
// optimization, or by is_profiler_internal_thread) so their accumulated time is recorded.
|
|
2128
|
-
// Called
|
|
2129
|
-
|
|
2199
|
+
// Called before serialization so that threads suspended across the whole profile period still get sampled.
|
|
2200
|
+
//
|
|
2201
|
+
// Assumption 1: When called while the profiler is active, `during_sample` MUST be set.
|
|
2202
|
+
VALUE thread_context_prepare_serialize(VALUE self_instance) {
|
|
2130
2203
|
thread_context_collector_state *state;
|
|
2131
2204
|
TypedData_Get_Struct(self_instance, thread_context_collector_state, &thread_context_collector_typed_data, state);
|
|
2132
2205
|
|
|
2133
|
-
long current_monotonic_wall_time_ns = monotonic_wall_time_now_ns(
|
|
2206
|
+
long current_monotonic_wall_time_ns = monotonic_wall_time_now_ns();
|
|
2134
2207
|
VALUE threads = thread_list(state);
|
|
2135
2208
|
const long thread_count = RARRAY_LEN(threads);
|
|
2136
2209
|
|
|
2137
2210
|
for (long i = 0; i < thread_count; i++) {
|
|
2138
|
-
VALUE thread =
|
|
2211
|
+
VALUE thread = rb_ary_entry(threads, i);
|
|
2212
|
+
ENFORCE_THREAD(thread);
|
|
2213
|
+
|
|
2139
2214
|
per_thread_context *thread_context = get_per_thread_context(thread);
|
|
2140
2215
|
|
|
2141
2216
|
if (thread_context != NULL && (thread_context->was_skipped_at_last_sample || thread_context->is_profiler_internal_thread)) {
|
|
2142
|
-
long current_cpu_time_ns = cpu_time_now_ns(thread_context);
|
|
2143
|
-
// We need to force_sample=true otherwise this sample would be skipped too
|
|
2144
2217
|
update_metrics_and_sample(
|
|
2145
2218
|
state,
|
|
2146
2219
|
thread,
|
|
2147
2220
|
thread_context,
|
|
2148
|
-
current_cpu_time_ns,
|
|
2149
2221
|
current_monotonic_wall_time_ns,
|
|
2150
|
-
true
|
|
2222
|
+
true // We need to force_sample=true otherwise this sample would be skipped too
|
|
2223
|
+
);
|
|
2151
2224
|
}
|
|
2152
2225
|
}
|
|
2226
|
+
|
|
2227
|
+
return state->recorder_instance;
|
|
2228
|
+
}
|
|
2229
|
+
|
|
2230
|
+
static VALUE _native_prepare_serialize(DDTRACE_UNUSED VALUE self, VALUE collector_instance) {
|
|
2231
|
+
return thread_context_prepare_serialize(collector_instance);
|
|
2153
2232
|
}
|
|
2154
2233
|
|
|
2155
2234
|
void thread_context_collector_on_gvl_released(per_thread_context *thread_context) {
|
|
@@ -2157,10 +2236,7 @@ void thread_context_collector_on_gvl_released(per_thread_context *thread_context
|
|
|
2157
2236
|
}
|
|
2158
2237
|
|
|
2159
2238
|
void thread_context_collector_on_gvl_waiting(per_thread_context *thread_context) {
|
|
2160
|
-
|
|
2161
|
-
if (current_monotonic_wall_time_ns <= 0) return;
|
|
2162
|
-
|
|
2163
|
-
thread_context->gvl_waiting_at = current_monotonic_wall_time_ns;
|
|
2239
|
+
thread_context->gvl_waiting_at = monotonic_wall_time_now_ns();
|
|
2164
2240
|
}
|
|
2165
2241
|
|
|
2166
2242
|
static VALUE _native_on_gvl_waiting(DDTRACE_UNUSED VALUE self, VALUE thread) {
|
|
@@ -2190,12 +2266,11 @@ static VALUE _native_on_gvl_released(DDTRACE_UNUSED VALUE self, VALUE thread) {
|
|
|
2190
2266
|
}
|
|
2191
2267
|
|
|
2192
2268
|
#ifndef NO_GVL_INSTRUMENTATION
|
|
2193
|
-
//
|
|
2269
|
+
// We must only use async-signal-safe functions here, see notes in the caller
|
|
2270
|
+
//
|
|
2271
|
+
// Assumption 1: When called while the profiler is active, `during_sample` MUST be set.
|
|
2194
2272
|
__attribute__((warn_unused_result))
|
|
2195
|
-
on_gvl_running_result thread_context_collector_on_gvl_running(VALUE
|
|
2196
|
-
thread_context_collector_state *state;
|
|
2197
|
-
TypedData_Get_Struct(self_instance, thread_context_collector_state, &thread_context_collector_typed_data, state);
|
|
2198
|
-
|
|
2273
|
+
on_gvl_running_result thread_context_collector_on_gvl_running(VALUE thread, per_thread_context *thread_context, uint32_t waiting_for_gvl_threshold_ns) {
|
|
2199
2274
|
// Bump the event counter and clears the state bit to "running"
|
|
2200
2275
|
uint64_t counter_portion = thread_context->gvl_state_change_count >> 1;
|
|
2201
2276
|
thread_context->gvl_state_change_count = ((counter_portion + 1) << 1) | GVL_RUNNING;
|
|
@@ -2210,9 +2285,9 @@ static VALUE _native_on_gvl_released(DDTRACE_UNUSED VALUE self, VALUE thread) {
|
|
|
2210
2285
|
return (on_gvl_running_result) {.action = ON_GVL_RUNNING_SAMPLE, .waiting_for_gvl_duration_ns = 0};
|
|
2211
2286
|
}
|
|
2212
2287
|
|
|
2213
|
-
long waiting_for_gvl_duration_ns = monotonic_wall_time_now_ns(
|
|
2288
|
+
long waiting_for_gvl_duration_ns = monotonic_wall_time_now_ns() - gvl_waiting_at;
|
|
2214
2289
|
|
|
2215
|
-
bool should_sample = waiting_for_gvl_duration_ns >=
|
|
2290
|
+
bool should_sample = waiting_for_gvl_duration_ns >= waiting_for_gvl_threshold_ns;
|
|
2216
2291
|
|
|
2217
2292
|
if (should_sample) {
|
|
2218
2293
|
// We flip the gvl_waiting_at to negative to mark that the thread is now running and no longer waiting
|
|
@@ -2270,7 +2345,8 @@ static VALUE _native_on_gvl_released(DDTRACE_UNUSED VALUE self, VALUE thread) {
|
|
|
2270
2345
|
//
|
|
2271
2346
|
// ---
|
|
2272
2347
|
//
|
|
2273
|
-
// Always called with the GVL, either from a postponed_job or from tests.
|
|
2348
|
+
// Assumption 1: Always called with the GVL, either from a postponed_job or from tests.
|
|
2349
|
+
// Assumption 2: When called while the profiler is active, `during_sample` MUST be set.
|
|
2274
2350
|
//
|
|
2275
2351
|
// NOTE: In normal use, current_thread is expected to be == rb_thread_current(); the `current_thread` parameter only
|
|
2276
2352
|
// exists to enable testing.
|
|
@@ -2278,7 +2354,7 @@ static VALUE _native_on_gvl_released(DDTRACE_UNUSED VALUE self, VALUE thread) {
|
|
|
2278
2354
|
thread_context_collector_state *state;
|
|
2279
2355
|
TypedData_Get_Struct(self_instance, thread_context_collector_state, &thread_context_collector_typed_data, state);
|
|
2280
2356
|
|
|
2281
|
-
per_thread_context *thread_context = get_or_create_context_for(current_thread);
|
|
2357
|
+
per_thread_context *thread_context = get_or_create_context_for(current_thread, current_monotonic_wall_time_ns);
|
|
2282
2358
|
|
|
2283
2359
|
long gvl_waiting_at = thread_context->gvl_waiting_at;
|
|
2284
2360
|
|
|
@@ -2290,18 +2366,12 @@ static VALUE _native_on_gvl_released(DDTRACE_UNUSED VALUE self, VALUE thread) {
|
|
|
2290
2366
|
return Qfalse;
|
|
2291
2367
|
}
|
|
2292
2368
|
|
|
2293
|
-
// We don't actually account for cpu-time during Waiting for GVL. BUT, we may choose to push an
|
|
2294
|
-
// extra sample to represent the period prior to Waiting for GVL. To support that, we retrieve the current
|
|
2295
|
-
// cpu-time of the thread and let `update_metrics_and_sample` decide what to do with it.
|
|
2296
|
-
long cpu_time_for_thread = cpu_time_now_ns(thread_context);
|
|
2297
|
-
|
|
2298
2369
|
// TODO: Should we update the dynamic sampling rate overhead tracking with this sample as well?
|
|
2299
2370
|
|
|
2300
2371
|
update_metrics_and_sample(
|
|
2301
2372
|
state,
|
|
2302
2373
|
current_thread,
|
|
2303
2374
|
thread_context,
|
|
2304
|
-
cpu_time_for_thread,
|
|
2305
2375
|
current_monotonic_wall_time_ns,
|
|
2306
2376
|
false);
|
|
2307
2377
|
|
|
@@ -2387,8 +2457,7 @@ static VALUE _native_on_gvl_released(DDTRACE_UNUSED VALUE self, VALUE thread) {
|
|
|
2387
2457
|
gvl_waiting_started_wall_time_ns,
|
|
2388
2458
|
NULL,
|
|
2389
2459
|
NULL,
|
|
2390
|
-
/* is_gvl_waiting_state: */ false
|
|
2391
|
-
/* is_safe_to_allocate_objects: */ true // This is similar to a regular cpu/wall sample, so it's also safe
|
|
2460
|
+
/* is_gvl_waiting_state: */ false // This is the extra sample before the wait begun; only the next sample will be in the gvl waiting state
|
|
2392
2461
|
);
|
|
2393
2462
|
}
|
|
2394
2463
|
|
|
@@ -2408,15 +2477,18 @@ static VALUE _native_on_gvl_released(DDTRACE_UNUSED VALUE self, VALUE thread) {
|
|
|
2408
2477
|
return result;
|
|
2409
2478
|
}
|
|
2410
2479
|
|
|
2411
|
-
static VALUE _native_on_gvl_running(DDTRACE_UNUSED VALUE self, VALUE
|
|
2480
|
+
static VALUE _native_on_gvl_running(DDTRACE_UNUSED VALUE self, VALUE thread, VALUE waiting_for_gvl_threshold_ns) {
|
|
2412
2481
|
ENFORCE_THREAD(thread);
|
|
2482
|
+
ENFORCE_TYPE(waiting_for_gvl_threshold_ns, T_FIXNUM);
|
|
2413
2483
|
|
|
2414
2484
|
debug_enter_unsafe_context();
|
|
2415
2485
|
|
|
2416
2486
|
per_thread_context *thread_context = get_per_thread_context(thread);
|
|
2417
2487
|
VALUE result;
|
|
2418
2488
|
if (thread_context) {
|
|
2419
|
-
|
|
2489
|
+
on_gvl_running_result gvl_running_result =
|
|
2490
|
+
thread_context_collector_on_gvl_running(thread, thread_context, NUM2UINT(waiting_for_gvl_threshold_ns));
|
|
2491
|
+
result = gvl_running_result.action == ON_GVL_RUNNING_SAMPLE ? Qtrue : Qfalse;
|
|
2420
2492
|
} else {
|
|
2421
2493
|
result = Qfalse;
|
|
2422
2494
|
}
|
|
@@ -2426,19 +2498,18 @@ static VALUE _native_on_gvl_released(DDTRACE_UNUSED VALUE self, VALUE thread) {
|
|
|
2426
2498
|
return result;
|
|
2427
2499
|
}
|
|
2428
2500
|
|
|
2429
|
-
static VALUE _native_sample_after_gvl_running(DDTRACE_UNUSED VALUE self, VALUE collector_instance, VALUE thread
|
|
2501
|
+
static VALUE _native_sample_after_gvl_running(DDTRACE_UNUSED VALUE self, VALUE collector_instance, VALUE thread) {
|
|
2430
2502
|
ENFORCE_THREAD(thread);
|
|
2431
|
-
ENFORCE_BOOLEAN(allow_exception);
|
|
2432
2503
|
|
|
2433
|
-
|
|
2504
|
+
debug_enter_unsafe_context();
|
|
2434
2505
|
|
|
2435
2506
|
VALUE result = thread_context_collector_sample_after_gvl_running(
|
|
2436
2507
|
collector_instance,
|
|
2437
2508
|
thread,
|
|
2438
|
-
monotonic_wall_time_now_ns(
|
|
2509
|
+
monotonic_wall_time_now_ns()
|
|
2439
2510
|
);
|
|
2440
2511
|
|
|
2441
|
-
|
|
2512
|
+
debug_leave_unsafe_context();
|
|
2442
2513
|
|
|
2443
2514
|
return result;
|
|
2444
2515
|
}
|
|
@@ -2453,13 +2524,33 @@ static VALUE _native_on_gvl_released(DDTRACE_UNUSED VALUE self, VALUE thread) {
|
|
|
2453
2524
|
|
|
2454
2525
|
#endif // NO_GVL_INSTRUMENTATION
|
|
2455
2526
|
|
|
2456
|
-
static VALUE
|
|
2527
|
+
static VALUE _native_apply_delta_to_time_at_previous_sample_ns(int argc, VALUE *argv, DDTRACE_UNUSED VALUE self) {
|
|
2528
|
+
VALUE thread;
|
|
2529
|
+
VALUE options;
|
|
2530
|
+
rb_scan_args(argc, argv, "1:", &thread, &options);
|
|
2531
|
+
if (options == Qnil) options = rb_hash_new();
|
|
2532
|
+
|
|
2533
|
+
VALUE cpu_time_delta_ns = rb_hash_lookup2(options, ID2SYM(rb_intern("cpu_time")), INT2FIX(0));
|
|
2534
|
+
VALUE wall_time_delta_ns = rb_hash_lookup2(options, ID2SYM(rb_intern("wall_time")), INT2FIX(0));
|
|
2535
|
+
|
|
2536
|
+
ENFORCE_THREAD(thread);
|
|
2537
|
+
|
|
2538
|
+
per_thread_context *thread_context = get_per_thread_context(thread);
|
|
2539
|
+
if (thread_context == NULL) raise_error(rb_eArgError, "Unexpected: This method cannot be used unless the per-thread context for the thread already exists");
|
|
2540
|
+
|
|
2541
|
+
thread_context->cpu_time_at_previous_sample_ns += NUM2LONG(cpu_time_delta_ns);
|
|
2542
|
+
thread_context->wall_time_at_previous_sample_ns += NUM2LONG(wall_time_delta_ns);
|
|
2543
|
+
|
|
2544
|
+
return Qtrue;
|
|
2545
|
+
}
|
|
2546
|
+
|
|
2547
|
+
static VALUE _native_apply_delta_to_gvl_waiting_at_for(DDTRACE_UNUSED VALUE self, VALUE thread, VALUE delta_ns) {
|
|
2457
2548
|
ENFORCE_THREAD(thread);
|
|
2458
2549
|
|
|
2459
2550
|
per_thread_context *thread_context = get_per_thread_context(thread);
|
|
2460
2551
|
if (thread_context == NULL) raise_error(rb_eArgError, "Unexpected: This method cannot be used unless the per-thread context for the thread already exists");
|
|
2461
2552
|
|
|
2462
|
-
thread_context->
|
|
2553
|
+
thread_context->gvl_waiting_at += NUM2LONG(delta_ns);
|
|
2463
2554
|
|
|
2464
2555
|
return Qtrue;
|
|
2465
2556
|
}
|
|
@@ -2502,8 +2593,7 @@ static VALUE _native_system_epoch_time_now_ns(DDTRACE_UNUSED VALUE self, VALUE c
|
|
|
2502
2593
|
thread_context_collector_state *state;
|
|
2503
2594
|
TypedData_Get_Struct(collector_instance, thread_context_collector_state, &thread_context_collector_typed_data, state);
|
|
2504
2595
|
|
|
2505
|
-
long
|
|
2506
|
-
long system_epoch_time_ns = monotonic_to_system_epoch_ns(&state->time_converter_state, current_monotonic_wall_time_ns);
|
|
2596
|
+
long system_epoch_time_ns = monotonic_to_system_epoch_ns(&state->time_converter_state, monotonic_wall_time_now_ns());
|
|
2507
2597
|
|
|
2508
2598
|
return LONG2NUM(system_epoch_time_ns);
|
|
2509
2599
|
}
|