datadog 2.36.0 → 2.40.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 +119 -1
- data/bin/ddprofrb +4 -4
- data/ext/datadog_profiling_native_extension/clock_id_from_mach.c +5 -12
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +105 -18
- data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +17 -3
- data/ext/datadog_profiling_native_extension/collectors_stack.c +228 -162
- data/ext/datadog_profiling_native_extension/collectors_stack.h +16 -3
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +357 -217
- data/ext/datadog_profiling_native_extension/collectors_thread_context.h +3 -0
- 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 -0
- data/ext/datadog_profiling_native_extension/extconf.rb +24 -11
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +261 -62
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +17 -9
- data/ext/datadog_profiling_native_extension/ruby_helpers.c +7 -0
- data/ext/datadog_profiling_native_extension/setup_signal_handler.c +2 -0
- data/ext/datadog_profiling_native_extension/time_helpers.h +12 -7
- data/ext/libdatadog_api/datadog_ruby_common.c +19 -11
- data/ext/libdatadog_api/datadog_ruby_common.h +7 -0
- data/ext/libdatadog_api/di.c +76 -0
- data/ext/libdatadog_api/extconf.rb +29 -23
- data/ext/libdatadog_api/feature_flags.c +26 -0
- data/ext/libdatadog_api/init.c +4 -0
- data/ext/libdatadog_api/trace_exporter.c +974 -0
- data/ext/libdatadog_api/trace_exporter.h +5 -0
- data/ext/libdatadog_extconf_helpers.rb +9 -9
- data/lib/datadog/ai_guard/api_client.rb +8 -6
- data/lib/datadog/ai_guard/component.rb +10 -10
- data/lib/datadog/ai_guard/evaluation.rb +1 -0
- data/lib/datadog/ai_guard/ext.rb +2 -0
- data/lib/datadog/appsec/actions_handler/serializable_backtrace.rb +16 -16
- 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 +1 -1
- data/lib/datadog/appsec/api_security/endpoint_collection/rails_collector.rb +6 -6
- data/lib/datadog/appsec/api_security/endpoint_collection/sinatra_route_serializer.rb +1 -1
- data/lib/datadog/appsec/api_security/route_extractor.rb +18 -15
- data/lib/datadog/appsec/api_security/sampler.rb +5 -5
- data/lib/datadog/appsec/api_security.rb +1 -1
- 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 +73 -58
- data/lib/datadog/appsec/context.rb +9 -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/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 +76 -21
- data/lib/datadog/appsec/contrib/faraday/integration.rb +4 -4
- data/lib/datadog/appsec/contrib/faraday/patcher.rb +4 -4
- data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +72 -18
- data/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +4 -4
- data/lib/datadog/appsec/contrib/graphql/gateway/multiplex.rb +3 -3
- 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 +18 -17
- data/lib/datadog/appsec/contrib/rack/gateway/response.rb +1 -1
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +25 -21
- data/lib/datadog/appsec/contrib/rack/input_peeker.rb +9 -22
- 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 +45 -24
- data/lib/datadog/appsec/contrib/rack/response_body.rb +1 -1
- data/lib/datadog/appsec/contrib/rails/gateway/request.rb +14 -8
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +10 -10
- data/lib/datadog/appsec/contrib/rails/integration.rb +5 -5
- data/lib/datadog/appsec/contrib/rails/patcher.rb +17 -17
- data/lib/datadog/appsec/contrib/rails/patches/process_action_patch.rb +2 -2
- data/lib/datadog/appsec/contrib/rails/patches/render_to_body_patch.rb +3 -3
- data/lib/datadog/appsec/contrib/rails/request.rb +3 -3
- data/lib/datadog/appsec/contrib/rails/request_middleware.rb +2 -1
- data/lib/datadog/appsec/contrib/rest_client/integration.rb +5 -5
- data/lib/datadog/appsec/contrib/rest_client/patcher.rb +1 -1
- data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +74 -21
- data/lib/datadog/appsec/contrib/sinatra/gateway/request.rb +1 -1
- data/lib/datadog/appsec/contrib/sinatra/gateway/route_params.rb +1 -1
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +16 -12
- data/lib/datadog/appsec/contrib/sinatra/integration.rb +5 -5
- data/lib/datadog/appsec/contrib/sinatra/patcher.rb +11 -11
- data/lib/datadog/appsec/contrib/sinatra/patches/json_patch.rb +3 -3
- data/lib/datadog/appsec/contrib/sinatra/request_middleware.rb +2 -1
- data/lib/datadog/appsec/counter_sampler.rb +1 -1
- data/lib/datadog/appsec/event.rb +14 -14
- data/lib/datadog/appsec/ext.rb +11 -10
- data/lib/datadog/appsec/extensions.rb +2 -2
- data/lib/datadog/appsec/instrumentation/gateway.rb +1 -1
- data/lib/datadog/appsec/metrics/collector.rb +18 -1
- data/lib/datadog/appsec/metrics/exporter.rb +17 -11
- data/lib/datadog/appsec/metrics/telemetry.rb +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 +26 -26
- data/lib/datadog/appsec/rate_limiter.rb +1 -1
- data/lib/datadog/appsec/remote.rb +15 -9
- data/lib/datadog/appsec/response.rb +21 -21
- data/lib/datadog/appsec/route_normalizer/rails_route_pattern.rb +176 -0
- data/lib/datadog/appsec/route_normalizer/route_pattern.rb +378 -0
- data/lib/datadog/appsec/route_normalizer/route_text.rb +57 -0
- data/lib/datadog/appsec/route_normalizer.rb +80 -0
- data/lib/datadog/appsec/security_engine/engine.rb +37 -37
- 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 +61 -0
- 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/agentless_settings_resolver.rb +2 -2
- data/lib/datadog/core/configuration/base.rb +2 -2
- data/lib/datadog/core/configuration/components.rb +115 -31
- data/lib/datadog/core/configuration/components_state.rb +6 -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 +4 -4
- data/lib/datadog/core/configuration/options.rb +1 -1
- data/lib/datadog/core/configuration/settings.rb +93 -104
- data/lib/datadog/core/configuration/stable_config.rb +1 -1
- data/lib/datadog/core/configuration/supported_configurations.rb +8 -1
- 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 +9 -9
- 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 +6 -6
- 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 +11 -0
- 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/knuth_sampler.rb +3 -1
- data/lib/datadog/core/logger.rb +3 -3
- data/lib/datadog/core/logging/ext.rb +1 -1
- data/lib/datadog/core/metrics/client.rb +21 -21
- data/lib/datadog/core/metrics/ext.rb +5 -5
- data/lib/datadog/core/metrics/logging.rb +2 -2
- data/lib/datadog/core/metrics/options.rb +3 -3
- data/lib/datadog/core/pin.rb +1 -1
- data/lib/datadog/core/process_discovery.rb +8 -8
- data/lib/datadog/core/rate_limiter.rb +1 -1
- data/lib/datadog/core/remote/client/capabilities.rb +62 -19
- data/lib/datadog/core/remote/client.rb +16 -16
- data/lib/datadog/core/remote/component.rb +20 -12
- 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 +2 -2
- data/lib/datadog/core/remote/configuration/target.rb +9 -9
- data/lib/datadog/core/remote/configuration.rb +4 -4
- data/lib/datadog/core/remote/ext.rb +3 -3
- data/lib/datadog/core/remote/negotiation.rb +1 -1
- data/lib/datadog/core/remote/tie/tracing.rb +7 -7
- data/lib/datadog/core/remote/transport/config.rb +4 -4
- data/lib/datadog/core/remote/transport/http/config.rb +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 +5 -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/emitter.rb +4 -4
- data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +5 -5
- 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 +2 -2
- 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 +41 -34
- 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 +2 -2
- data/lib/datadog/core/telemetry/event/log.rb +4 -4
- 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 +7 -7
- 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 +4 -4
- 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 +6 -6
- data/lib/datadog/core/transport/http/client.rb +2 -2
- data/lib/datadog/core/transport/http/response.rb +1 -1
- data/lib/datadog/core/transport/http.rb +8 -8
- data/lib/datadog/core/transport/transport.rb +1 -1
- data/lib/datadog/core/utils/at_fork_monkey_patch.rb +83 -15
- 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 +18 -52
- 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 +4 -4
- 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 +5 -5
- data/lib/datadog/data_streams/processor.rb +52 -52
- 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 +6 -4
- data/lib/datadog/di/boot.rb +25 -22
- data/lib/datadog/di/capture_expression.rb +21 -0
- data/lib/datadog/di/capture_expression_evaluator.rb +71 -0
- data/lib/datadog/di/capture_limits.rb +41 -0
- data/lib/datadog/di/code_tracker.rb +10 -7
- data/lib/datadog/di/component.rb +122 -40
- data/lib/datadog/di/configuration.rb +7 -1
- data/lib/datadog/di/context.rb +9 -3
- data/lib/datadog/di/contrib/railtie.rb +1 -1
- data/lib/datadog/di/contrib.rb +5 -5
- data/lib/datadog/di/el/compiler.rb +91 -38
- data/lib/datadog/di/el/evaluator.rb +82 -2
- data/lib/datadog/di/el/expression.rb +10 -2
- data/lib/datadog/di/el.rb +3 -3
- data/lib/datadog/di/error.rb +10 -0
- data/lib/datadog/di/fatal_exceptions.rb +26 -0
- data/lib/datadog/di/instrumenter.rb +426 -169
- data/lib/datadog/di/logger.rb +1 -1
- data/lib/datadog/di/preload.rb +1 -1
- data/lib/datadog/di/probe.rb +61 -2
- data/lib/datadog/di/probe_builder.rb +96 -14
- data/lib/datadog/di/probe_file_loader/railtie.rb +1 -1
- data/lib/datadog/di/probe_file_loader.rb +12 -7
- data/lib/datadog/di/probe_manager.rb +67 -9
- data/lib/datadog/di/probe_notification_builder.rb +66 -22
- data/lib/datadog/di/probe_notifier_worker.rb +57 -37
- data/lib/datadog/di/probe_repository.rb +1 -1
- data/lib/datadog/di/redactor.rb +16 -1
- data/lib/datadog/di/remote.rb +178 -17
- data/lib/datadog/di/serializer.rb +47 -28
- data/lib/datadog/di/transport/diagnostics.rb +5 -5
- data/lib/datadog/di/transport/http/diagnostics.rb +3 -3
- data/lib/datadog/di/transport/http/input.rb +2 -2
- data/lib/datadog/di/transport/http.rb +10 -10
- data/lib/datadog/di/transport/input.rb +16 -12
- data/lib/datadog/di/utils.rb +4 -4
- data/lib/datadog/di.rb +66 -3
- 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 +90 -32
- 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/component.rb +53 -21
- data/lib/datadog/open_feature/configuration.rb +22 -1
- data/lib/datadog/open_feature/evaluation_engine.rb +7 -7
- 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 +2 -2
- 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 +13 -6
- data/lib/datadog/open_feature/flag_evaluation/aggregator.rb +286 -0
- data/lib/datadog/open_feature/flag_evaluation/writer.rb +433 -0
- data/lib/datadog/open_feature/hooks/flag_eval_evp_hook.rb +102 -0
- data/lib/datadog/open_feature/hooks/{flag_eval_hook.rb → flag_eval_metrics_hook.rb} +4 -2
- 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 +23 -1
- data/lib/datadog/open_feature/noop_evaluator.rb +3 -3
- data/lib/datadog/open_feature/provider.rb +97 -30
- data/lib/datadog/open_feature/remote.rb +2 -2
- data/lib/datadog/open_feature/resolution_details.rb +4 -2
- data/lib/datadog/open_feature/transport.rb +65 -11
- data/lib/datadog/open_feature.rb +2 -2
- data/lib/datadog/opentelemetry/api/baggage.rb +3 -3
- data/lib/datadog/opentelemetry/api/context.rb +4 -4
- data/lib/datadog/opentelemetry/configuration/settings.rb +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 +10 -17
- data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +8 -15
- data/lib/datadog/opentelemetry/sdk/propagator.rb +7 -7
- 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 +19 -0
- data/lib/datadog/opentelemetry/signal_configuration.rb +11 -11
- data/lib/datadog/opentelemetry/trace.rb +1 -1
- data/lib/datadog/opentelemetry.rb +8 -8
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +6 -1
- data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +5 -3
- data/lib/datadog/profiling/collectors/thread_context.rb +15 -14
- data/lib/datadog/profiling/component.rb +18 -0
- data/lib/datadog/profiling/exporter.rb +1 -1
- 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.rb +31 -27
- data/lib/datadog/single_step_instrument.rb +1 -1
- data/lib/datadog/symbol_database/component.rb +177 -60
- data/lib/datadog/symbol_database/configuration.rb +15 -7
- data/lib/datadog/symbol_database/extensions.rb +19 -0
- data/lib/datadog/symbol_database/extractor.rb +167 -130
- data/lib/datadog/symbol_database/file_hash.rb +5 -3
- data/lib/datadog/symbol_database/logger.rb +1 -1
- data/lib/datadog/symbol_database/remote.rb +28 -8
- data/lib/datadog/symbol_database/scope.rb +2 -2
- data/lib/datadog/symbol_database/scope_batcher.rb +8 -4
- 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 +28 -21
- data/lib/datadog/symbol_database.rb +22 -0
- 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 +28 -7
- data/lib/datadog/tracing/configuration/dynamic.rb +8 -8
- data/lib/datadog/tracing/configuration/ext.rb +43 -42
- data/lib/datadog/tracing/configuration/http.rb +2 -2
- data/lib/datadog/tracing/configuration/settings.rb +32 -16
- data/lib/datadog/tracing/context.rb +1 -1
- data/lib/datadog/tracing/context_provider.rb +2 -2
- 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 +4 -4
- 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 +2 -2
- 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 +8 -8
- 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 +2 -2
- data/lib/datadog/tracing/contrib/action_view/ext.rb +10 -10
- data/lib/datadog/tracing/contrib/action_view/integration.rb +11 -11
- data/lib/datadog/tracing/contrib/action_view/patcher.rb +5 -5
- data/lib/datadog/tracing/contrib/action_view/utils.rb +2 -2
- data/lib/datadog/tracing/contrib/active_job/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/active_job/data_streams.rb +62 -0
- data/lib/datadog/tracing/contrib/active_job/event.rb +3 -3
- data/lib/datadog/tracing/contrib/active_job/events/discard.rb +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 +17 -5
- data/lib/datadog/tracing/contrib/active_model_serializers/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/active_model_serializers/event.rb +4 -4
- data/lib/datadog/tracing/contrib/active_model_serializers/events/render.rb +6 -6
- data/lib/datadog/tracing/contrib/active_model_serializers/events/serialize.rb +7 -8
- data/lib/datadog/tracing/contrib/active_model_serializers/events.rb +2 -2
- 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 +6 -6
- 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 +9 -9
- data/lib/datadog/tracing/contrib/active_record/events.rb +2 -2
- 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 +11 -11
- 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 +25 -25
- 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 +2 -2
- data/lib/datadog/tracing/contrib/ethon/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +8 -8
- 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 +8 -8
- data/lib/datadog/tracing/contrib/excon/patcher.rb +2 -2
- data/lib/datadog/tracing/contrib/ext.rb +15 -15
- 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 +8 -8
- 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 +20 -20
- 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 +7 -7
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +7 -7
- 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 +8 -8
- 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 +6 -6
- 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 +5 -5
- 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 +6 -6
- 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 +9 -9
- 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 +8 -8
- 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 +22 -22
- 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 +3 -3
- data/lib/datadog/tracing/contrib/patcher.rb +2 -2
- 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 +18 -18
- 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 +1 -1
- 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 +3 -3
- 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 +2 -2
- 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 +15 -15
- 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 +2 -2
- 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 +4 -4
- data/lib/datadog/tracing/contrib/redis/tags.rb +5 -5
- data/lib/datadog/tracing/contrib/redis/trace_middleware.rb +5 -5
- 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 +5 -5
- 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/patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/sequel/utils.rb +115 -10
- 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 +9 -9
- 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 +14 -14
- 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 +2 -2
- data/lib/datadog/tracing/contrib/sinatra/env.rb +6 -6
- data/lib/datadog/tracing/contrib/sinatra/ext.rb +17 -17
- data/lib/datadog/tracing/contrib/sinatra/framework.rb +2 -2
- data/lib/datadog/tracing/contrib/sinatra/integration.rb +5 -5
- data/lib/datadog/tracing/contrib/sinatra/patcher.rb +5 -5
- data/lib/datadog/tracing/contrib/sinatra/tracer.rb +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 +3 -3
- 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 +1 -1
- data/lib/datadog/tracing/contrib/utils/quantization/http.rb +10 -10
- data/lib/datadog/tracing/contrib/waterdrop/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/waterdrop/distributed/propagation.rb +8 -8
- 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 +10 -10
- data/lib/datadog/tracing/diagnostics/environment_logger.rb +9 -9
- 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 +28 -27
- data/lib/datadog/tracing/distributed/datadog.rb +21 -21
- data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +3 -3
- 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 +12 -12
- data/lib/datadog/tracing/distributed/propagation_policy.rb +5 -0
- data/lib/datadog/tracing/distributed/trace_context.rb +33 -33
- data/lib/datadog/tracing/event.rb +1 -1
- data/lib/datadog/tracing/ext.rb +9 -0
- data/lib/datadog/tracing/metadata/analytics.rb +2 -2
- data/lib/datadog/tracing/metadata/errors.rb +4 -4
- data/lib/datadog/tracing/metadata/ext.rb +69 -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 +2 -2
- data/lib/datadog/tracing/metadata.rb +4 -4
- data/lib/datadog/tracing/pipeline/span_filter.rb +2 -2
- data/lib/datadog/tracing/pipeline.rb +2 -2
- data/lib/datadog/tracing/remote.rb +45 -7
- 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 +12 -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 +8 -8
- data/lib/datadog/tracing/span_event.rb +5 -5
- data/lib/datadog/tracing/span_operation.rb +21 -21
- data/lib/datadog/tracing/sync_writer.rb +12 -7
- data/lib/datadog/tracing/trace_operation.rb +11 -11
- data/lib/datadog/tracing/trace_segment.rb +10 -10
- data/lib/datadog/tracing/tracer.rb +23 -15
- data/lib/datadog/tracing/transport/http/client.rb +4 -4
- data/lib/datadog/tracing/transport/http/statistics.rb +2 -2
- data/lib/datadog/tracing/transport/http/traces.rb +8 -8
- data/lib/datadog/tracing/transport/http.rb +10 -10
- data/lib/datadog/tracing/transport/io/client.rb +2 -2
- data/lib/datadog/tracing/transport/io/response.rb +1 -1
- data/lib/datadog/tracing/transport/io/traces.rb +4 -4
- data/lib/datadog/tracing/transport/io.rb +3 -3
- data/lib/datadog/tracing/transport/native/response.rb +71 -0
- data/lib/datadog/tracing/transport/native.rb +363 -0
- data/lib/datadog/tracing/transport/serializable_trace.rb +19 -19
- data/lib/datadog/tracing/transport/statistics.rb +2 -2
- data/lib/datadog/tracing/transport/trace_formatter.rb +10 -10
- data/lib/datadog/tracing/transport/traces.rb +8 -8
- data/lib/datadog/tracing/utils.rb +2 -2
- data/lib/datadog/tracing/workers.rb +2 -2
- data/lib/datadog/tracing/writer.rb +21 -8
- data/lib/datadog/tracing.rb +3 -3
- data/lib/datadog/version.rb +4 -4
- data/lib/datadog.rb +13 -12
- metadata +33 -8
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#include <ruby.h>
|
|
2
|
+
#include <ruby/debug.h>
|
|
2
3
|
|
|
3
4
|
#include "datadog_ruby_common.h"
|
|
4
5
|
#include "collectors_thread_context.h"
|
|
@@ -42,11 +43,8 @@
|
|
|
42
43
|
// When `thread_context_collector_on_gc_start` gets called, the current cpu and wall-time get recorded to the thread
|
|
43
44
|
// context: `cpu_time_at_gc_start_ns` and `wall_time_at_gc_start_ns`.
|
|
44
45
|
//
|
|
45
|
-
// While `cpu_time_at_gc_start_ns` is set,
|
|
46
|
-
//
|
|
47
|
-
// Wall-time accounting is not affected by this (e.g. we still record 60 seconds every 60 seconds).
|
|
48
|
-
//
|
|
49
|
-
// (Regular samples can still account for the cpu-time between the previous sample and the start of GC.)
|
|
46
|
+
// While `cpu_time_at_gc_start_ns` is set, we don't expect the thread to be sampled: the VM is doing GC
|
|
47
|
+
// on the thread holding the GVL so no other samples can/will be triggered until GC finishes.
|
|
50
48
|
//
|
|
51
49
|
// When `thread_context_collector_on_gc_finish` gets called, the cpu-time and wall-time spent during GC gets recorded
|
|
52
50
|
// into the global gc_tracking structure, and further samples are not affected. (The `cpu_time_at_previous_sample_ns`
|
|
@@ -75,8 +73,6 @@
|
|
|
75
73
|
|
|
76
74
|
#define THREAD_ID_LIMIT_CHARS 44 // Why 44? "#{2**64} (#{2**64})".size + 1 for \0
|
|
77
75
|
#define THREAD_INVOKE_LOCATION_LIMIT_CHARS 512
|
|
78
|
-
#define IS_WALL_TIME true
|
|
79
|
-
#define IS_CPU_TIME false
|
|
80
76
|
#define MISSING_TRACER_CONTEXT_KEY 0
|
|
81
77
|
#define TIME_BETWEEN_GC_EVENTS_NS MILLIS_AS_NS(10)
|
|
82
78
|
#define GVL_SUSPENDED ((uint64_t)1)
|
|
@@ -108,6 +104,20 @@ static ID server_id; // id of :server in Ruby
|
|
|
108
104
|
static ID otel_context_storage_id; // id of :__opentelemetry_context_storage__ in Ruby
|
|
109
105
|
static ID otel_fiber_context_storage_id; // id of :@opentelemetry_context in Ruby
|
|
110
106
|
|
|
107
|
+
// This is mutable and gets set last-writer-wins style by
|
|
108
|
+
// `thread_context_collector_reset_all_per_thread_contexts`, which is called whenever
|
|
109
|
+
// profiling is starting or restating.
|
|
110
|
+
//
|
|
111
|
+
// Note: We must be careful to not change this value while the profiler is still running,
|
|
112
|
+
// otherwise new threads can get the new value and cause profiling to stop with an
|
|
113
|
+
// exception due to the mismatched size.
|
|
114
|
+
//
|
|
115
|
+
// The initial value should be kept in sync with the default for DD_PROFILING_MAX_FRAMES
|
|
116
|
+
// in settings.rb. See `initialize_context` for details on why this is needed/used.
|
|
117
|
+
static uint16_t latest_max_frames = 400;
|
|
118
|
+
|
|
119
|
+
// Global tracepoint for RUBY_EVENT_THREAD_BEGIN. Created and enabled once when the first ThreadContext collector is initialized.
|
|
120
|
+
static VALUE thread_begin_tracepoint = Qnil;
|
|
111
121
|
|
|
112
122
|
typedef enum { OTEL_CONTEXT_ENABLED_FALSE, OTEL_CONTEXT_ENABLED_ONLY, OTEL_CONTEXT_ENABLED_BOTH } otel_context_enabled;
|
|
113
123
|
typedef enum { OTEL_CONTEXT_SOURCE_UNKNOWN, OTEL_CONTEXT_SOURCE_FIBER_IVAR, OTEL_CONTEXT_SOURCE_FIBER_LOCAL } otel_context_source;
|
|
@@ -143,6 +153,8 @@ typedef struct {
|
|
|
143
153
|
VALUE otel_current_span_key;
|
|
144
154
|
// Used to enable native filenames in stack traces
|
|
145
155
|
bool native_filenames_enabled;
|
|
156
|
+
// Used to include class/module names in method names (e.g. "Foo#bar" instead of "bar")
|
|
157
|
+
bool show_classes;
|
|
146
158
|
// Used to cache native filename lookup results (Map[void *function_pointer, char *filename])
|
|
147
159
|
st_table *native_filenames_cache;
|
|
148
160
|
// Used to attribute overhead during sampling to this component
|
|
@@ -160,6 +172,7 @@ typedef struct {
|
|
|
160
172
|
// How many per-thread samples were skipped because the thread has been continuously suspended
|
|
161
173
|
// (no GVL) since its previous sample, so its Ruby stack cannot have changed.
|
|
162
174
|
unsigned int inactive_thread_samples_skipped;
|
|
175
|
+
unsigned int profiler_thread_samples_skipped;
|
|
163
176
|
} stats;
|
|
164
177
|
|
|
165
178
|
struct {
|
|
@@ -171,7 +184,21 @@ typedef struct {
|
|
|
171
184
|
} gc_tracking;
|
|
172
185
|
} thread_context_collector_state;
|
|
173
186
|
|
|
174
|
-
// Tracks per-thread state
|
|
187
|
+
// Tracks per-thread state.
|
|
188
|
+
// This state is global and lives forever on the Ruby Thread (until the Thread is GC'd).
|
|
189
|
+
// The state is created early on for all threads on the main Ractor
|
|
190
|
+
// (enabling a TracePoint only enables it for the current Ractor).
|
|
191
|
+
// The state is either created when the Thread starts running (via the RUBY_EVENT_THREAD_BEGIN TracePoint),
|
|
192
|
+
// or via `thread_context_collector_reset_all_per_thread_contexts` when the profiler starts.
|
|
193
|
+
//
|
|
194
|
+
// Unfortunately that RUBY_EVENT_THREAD_BEGIN TracePoint still fires after some other events:
|
|
195
|
+
// * RUBY_INTERNAL_THREAD_EVENT_RESUMED for the Thread acquiring the GVL for the first time
|
|
196
|
+
// * an early SIGPROF calling handle_sampling_signal()
|
|
197
|
+
// * Ruby might check for interrupts and run postponed jobs (e.g. thread_context_collector_sample)
|
|
198
|
+
// * another RUBY_EVENT_THREAD_BEGIN TracePoint which might run before ours
|
|
199
|
+
// * etc
|
|
200
|
+
// For those cases we have to ignore those events and we cannot assume the state is always set,
|
|
201
|
+
// however this only matters for a very short period when a thread starts.
|
|
175
202
|
struct per_thread_context {
|
|
176
203
|
sampling_buffer sampling_buffer;
|
|
177
204
|
char thread_id[THREAD_ID_LIMIT_CHARS];
|
|
@@ -179,8 +206,8 @@ struct per_thread_context {
|
|
|
179
206
|
char thread_invoke_location[THREAD_INVOKE_LOCATION_LIMIT_CHARS];
|
|
180
207
|
ddog_CharSlice thread_invoke_location_char_slice;
|
|
181
208
|
thread_cpu_time_id thread_cpu_time_id;
|
|
182
|
-
long cpu_time_at_previous_sample_ns;
|
|
183
|
-
long wall_time_at_previous_sample_ns;
|
|
209
|
+
long cpu_time_at_previous_sample_ns;
|
|
210
|
+
long wall_time_at_previous_sample_ns;
|
|
184
211
|
|
|
185
212
|
// There are 3 possible states for the GVL (per thread), and 3 transitions for which we receive GVL events:
|
|
186
213
|
// Thread holds the GVL
|
|
@@ -233,6 +260,14 @@ struct per_thread_context {
|
|
|
233
260
|
// but this is deemed worth it for this optimization. In any case we don't know exactly
|
|
234
261
|
// at what time a thread was doing CPU work (unless it's on CPU 100% of the time).
|
|
235
262
|
bool was_skipped_at_last_sample;
|
|
263
|
+
// Set as true for CpuAndWallTimeWorker and IdleSamplingHelper threads.
|
|
264
|
+
// When true, per-tick samples are skipped entirely; the thread is sampled only once per
|
|
265
|
+
// reporting period during the on_serialize flush.
|
|
266
|
+
//
|
|
267
|
+
// These threads are always in native code so their stacks aren't interesting;
|
|
268
|
+
// the Profiling::Scheduler thread on the other hand does a lot of different
|
|
269
|
+
// things using a mix of Ruby and native code, so that one isn't considered internal.
|
|
270
|
+
bool is_profiler_internal_thread;
|
|
236
271
|
|
|
237
272
|
struct {
|
|
238
273
|
// Both of these fields are set by on_gc_start and kept until on_gc_finish is called.
|
|
@@ -270,7 +305,6 @@ static void update_metrics_and_sample(
|
|
|
270
305
|
thread_context_collector_state *state,
|
|
271
306
|
VALUE thread_being_sampled,
|
|
272
307
|
per_thread_context *thread_context,
|
|
273
|
-
sampling_buffer* sampling_buffer,
|
|
274
308
|
long current_cpu_time_ns,
|
|
275
309
|
long current_monotonic_wall_time_ns,
|
|
276
310
|
bool force_sample
|
|
@@ -279,7 +313,6 @@ static void trigger_sample_for_thread(
|
|
|
279
313
|
thread_context_collector_state *state,
|
|
280
314
|
VALUE thread_being_sampled,
|
|
281
315
|
per_thread_context *thread_context,
|
|
282
|
-
sampling_buffer* sampling_buffer,
|
|
283
316
|
sample_values values,
|
|
284
317
|
long current_monotonic_wall_time_ns,
|
|
285
318
|
ddog_CharSlice *ruby_vm_type,
|
|
@@ -288,14 +321,16 @@ static void trigger_sample_for_thread(
|
|
|
288
321
|
bool is_safe_to_allocate_objects
|
|
289
322
|
);
|
|
290
323
|
static VALUE _native_thread_list(VALUE self);
|
|
291
|
-
static
|
|
292
|
-
static
|
|
324
|
+
static void check_frozen_thread(VALUE thread);
|
|
325
|
+
static per_thread_context *get_or_create_context_for(VALUE thread);
|
|
326
|
+
static void initialize_context(VALUE thread, per_thread_context *thread_context);
|
|
293
327
|
static VALUE _native_inspect(VALUE self, VALUE collector_instance);
|
|
294
328
|
static VALUE per_thread_context_to_ruby_hash(per_thread_context *thread_context);
|
|
295
329
|
static VALUE stats_to_ruby_hash(thread_context_collector_state *state, VALUE hash);
|
|
296
330
|
static VALUE gc_tracking_as_ruby_hash(thread_context_collector_state *state);
|
|
297
331
|
static VALUE _native_per_thread_context(VALUE self, VALUE collector_instance);
|
|
298
|
-
static long
|
|
332
|
+
static long update_cpu_time_since_previous_sample(per_thread_context *thread_context, long current_cpu_time_ns);
|
|
333
|
+
static long update_wall_time_since_previous_sample(per_thread_context *thread_context, long current_wall_time_ns);
|
|
299
334
|
static long cpu_time_now_ns(per_thread_context *thread_context);
|
|
300
335
|
static long thread_id_for(VALUE thread);
|
|
301
336
|
static VALUE _native_stats(VALUE self, VALUE collector_instance);
|
|
@@ -326,17 +361,16 @@ static bool handle_gvl_waiting(
|
|
|
326
361
|
thread_context_collector_state *state,
|
|
327
362
|
VALUE thread_being_sampled,
|
|
328
363
|
per_thread_context *thread_context,
|
|
329
|
-
sampling_buffer* sampling_buffer,
|
|
330
364
|
long current_cpu_time_ns
|
|
331
365
|
);
|
|
366
|
+
static VALUE _native_on_gvl_waiting(DDTRACE_UNUSED VALUE self, VALUE thread);
|
|
367
|
+
static VALUE _native_on_gvl_released(DDTRACE_UNUSED VALUE self, VALUE thread);
|
|
332
368
|
#ifndef NO_GVL_INSTRUMENTATION
|
|
333
|
-
static VALUE _native_on_gvl_waiting(DDTRACE_UNUSED VALUE self, VALUE thread);
|
|
334
369
|
static VALUE _native_gvl_waiting_at_for(DDTRACE_UNUSED VALUE self, VALUE thread);
|
|
335
370
|
static VALUE _native_on_gvl_running(DDTRACE_UNUSED VALUE self, VALUE collector_instance, VALUE thread);
|
|
336
|
-
static VALUE _native_on_gvl_released(DDTRACE_UNUSED VALUE self, VALUE thread);
|
|
337
371
|
static VALUE _native_sample_after_gvl_running(DDTRACE_UNUSED VALUE self, VALUE collector_instance, VALUE thread, VALUE allow_exception);
|
|
338
|
-
static VALUE _native_apply_delta_to_cpu_time_at_previous_sample_ns(DDTRACE_UNUSED VALUE self, VALUE thread, VALUE delta_ns);
|
|
339
372
|
#endif
|
|
373
|
+
static VALUE _native_apply_delta_to_cpu_time_at_previous_sample_ns(DDTRACE_UNUSED VALUE self, VALUE thread, VALUE delta_ns);
|
|
340
374
|
static void otel_without_ddtrace_trace_identifiers_for(
|
|
341
375
|
thread_context_collector_state *state,
|
|
342
376
|
VALUE thread,
|
|
@@ -348,12 +382,16 @@ static uint64_t otel_span_id_to_uint(VALUE otel_span_id);
|
|
|
348
382
|
static VALUE safely_lookup_hash_without_going_into_ruby_code(VALUE hash, VALUE key);
|
|
349
383
|
static VALUE _native_system_epoch_time_now_ns(DDTRACE_UNUSED VALUE self, VALUE collector_instance);
|
|
350
384
|
static VALUE _native_prepare_sample_inside_signal_handler(DDTRACE_UNUSED VALUE self);
|
|
351
|
-
static VALUE
|
|
352
|
-
static
|
|
385
|
+
static VALUE _native_mark_thread_as_profiler_internal(DDTRACE_UNUSED VALUE self, VALUE thread);
|
|
386
|
+
static VALUE _native_remove_per_thread_context_for(DDTRACE_UNUSED VALUE self, VALUE thread);
|
|
387
|
+
static VALUE _native_global_reset_per_thread_context(DDTRACE_UNUSED VALUE self, VALUE collector_instance);
|
|
388
|
+
static bool skip_sample(thread_context_collector_state *state, per_thread_context *thread_context, bool is_gvl_waiting_state, bool force_sample);
|
|
389
|
+
static void on_thread_begin_event(VALUE tracepoint_data, DDTRACE_UNUSED void *unused);
|
|
353
390
|
|
|
354
391
|
void collectors_thread_context_init(VALUE profiling_module) {
|
|
355
392
|
VALUE collectors_module = rb_define_module_under(profiling_module, "Collectors");
|
|
356
393
|
VALUE collectors_thread_context_class = rb_define_class_under(collectors_module, "ThreadContext", rb_cObject);
|
|
394
|
+
|
|
357
395
|
// Hosts methods used for testing the native code using RSpec
|
|
358
396
|
VALUE testing_module = rb_define_module_under(collectors_thread_context_class, "Testing");
|
|
359
397
|
|
|
@@ -383,15 +421,17 @@ void collectors_thread_context_init(VALUE profiling_module) {
|
|
|
383
421
|
rb_define_singleton_method(testing_module, "_native_sample_skipped_allocation_samples", _native_sample_skipped_allocation_samples, 2);
|
|
384
422
|
rb_define_singleton_method(testing_module, "_native_system_epoch_time_now_ns", _native_system_epoch_time_now_ns, 1);
|
|
385
423
|
rb_define_singleton_method(testing_module, "_native_prepare_sample_inside_signal_handler", _native_prepare_sample_inside_signal_handler, 0);
|
|
386
|
-
rb_define_singleton_method(testing_module, "
|
|
424
|
+
rb_define_singleton_method(testing_module, "_native_remove_per_thread_context_for", _native_remove_per_thread_context_for, 1);
|
|
425
|
+
rb_define_singleton_method(testing_module, "_native_global_reset_per_thread_context", _native_global_reset_per_thread_context, 1);
|
|
426
|
+
rb_define_singleton_method(testing_module, "_native_mark_thread_as_profiler_internal", _native_mark_thread_as_profiler_internal, 1);
|
|
427
|
+
rb_define_singleton_method(testing_module, "_native_on_gvl_waiting", _native_on_gvl_waiting, 1);
|
|
428
|
+
rb_define_singleton_method(testing_module, "_native_on_gvl_released", _native_on_gvl_released, 1);
|
|
387
429
|
#ifndef NO_GVL_INSTRUMENTATION
|
|
388
|
-
rb_define_singleton_method(testing_module, "_native_on_gvl_waiting", _native_on_gvl_waiting, 1);
|
|
389
430
|
rb_define_singleton_method(testing_module, "_native_gvl_waiting_at_for", _native_gvl_waiting_at_for, 1);
|
|
390
431
|
rb_define_singleton_method(testing_module, "_native_on_gvl_running", _native_on_gvl_running, 2);
|
|
391
|
-
rb_define_singleton_method(testing_module, "_native_on_gvl_released", _native_on_gvl_released, 1);
|
|
392
432
|
rb_define_singleton_method(testing_module, "_native_sample_after_gvl_running", _native_sample_after_gvl_running, 3);
|
|
393
|
-
rb_define_singleton_method(testing_module, "_native_apply_delta_to_cpu_time_at_previous_sample_ns", _native_apply_delta_to_cpu_time_at_previous_sample_ns, 2);
|
|
394
433
|
#endif
|
|
434
|
+
rb_define_singleton_method(testing_module, "_native_apply_delta_to_cpu_time_at_previous_sample_ns", _native_apply_delta_to_cpu_time_at_previous_sample_ns, 2);
|
|
395
435
|
|
|
396
436
|
at_active_span_id = rb_intern_const("@active_span");
|
|
397
437
|
at_active_trace_id = rb_intern_const("@active_trace");
|
|
@@ -417,6 +457,8 @@ void collectors_thread_context_init(VALUE profiling_module) {
|
|
|
417
457
|
// This will raise if Ruby already ran out of thread-local keys
|
|
418
458
|
per_thread_context_tls_init();
|
|
419
459
|
|
|
460
|
+
rb_global_variable(&thread_begin_tracepoint);
|
|
461
|
+
|
|
420
462
|
gc_profiling_init();
|
|
421
463
|
}
|
|
422
464
|
|
|
@@ -453,7 +495,7 @@ static void thread_context_collector_typed_data_free(void *state_ptr) {
|
|
|
453
495
|
|
|
454
496
|
// Important: Remember that we're only guaranteed to see here what's been set in _native_new, aka
|
|
455
497
|
// pointers that have been set NULL there may still be NULL here.
|
|
456
|
-
|
|
498
|
+
sample_locations_free(&state->locations);
|
|
457
499
|
|
|
458
500
|
st_free_table(state->native_filenames_cache);
|
|
459
501
|
|
|
@@ -485,17 +527,24 @@ static void per_thread_context_typed_data_free(void *ctx_ptr) {
|
|
|
485
527
|
free(ctx);
|
|
486
528
|
}
|
|
487
529
|
|
|
488
|
-
|
|
530
|
+
// Only for testing: removes the per-thread context without recreating it, so the thread has no context.
|
|
531
|
+
// This simulates situations where we observe a thread running before our RUBY_EVENT_THREAD_BEGIN tracepoint fires,
|
|
532
|
+
// so that we can test our `get_per_thread_context(...) => null` code paths.
|
|
533
|
+
static VALUE _native_remove_per_thread_context_for(DDTRACE_UNUSED VALUE self, VALUE thread) {
|
|
534
|
+
check_frozen_thread(thread);
|
|
489
535
|
per_thread_context *ctx = get_per_thread_context(thread);
|
|
490
536
|
if (ctx != NULL) {
|
|
491
537
|
set_per_thread_context(thread, NULL);
|
|
492
|
-
|
|
493
|
-
rb_ivar_set(thread, dd_per_thread_context_id, Qnil);
|
|
494
|
-
}
|
|
538
|
+
rb_ivar_set(thread, dd_per_thread_context_id, Qnil);
|
|
495
539
|
}
|
|
496
540
|
return Qnil;
|
|
497
541
|
}
|
|
498
542
|
|
|
543
|
+
static VALUE _native_global_reset_per_thread_context(DDTRACE_UNUSED VALUE self, VALUE collector_instance) {
|
|
544
|
+
thread_context_collector_reset_all_per_thread_contexts(collector_instance);
|
|
545
|
+
return Qnil;
|
|
546
|
+
}
|
|
547
|
+
|
|
499
548
|
static VALUE _native_new(VALUE klass) {
|
|
500
549
|
thread_context_collector_state *state = ruby_xcalloc(1, sizeof(thread_context_collector_state));
|
|
501
550
|
|
|
@@ -503,14 +552,13 @@ static VALUE _native_new(VALUE klass) {
|
|
|
503
552
|
// being leaked.
|
|
504
553
|
|
|
505
554
|
// Update this when modifying state struct
|
|
506
|
-
state->locations.ptr = NULL;
|
|
507
|
-
state->locations.len = 0;
|
|
508
555
|
state->recorder_instance = Qnil;
|
|
509
556
|
state->tracer_context_key = MISSING_TRACER_CONTEXT_KEY;
|
|
510
557
|
VALUE thread_list_buffer = rb_ary_new();
|
|
511
558
|
state->thread_list_buffer = thread_list_buffer;
|
|
512
559
|
state->endpoint_collection_enabled = true;
|
|
513
560
|
state->native_filenames_enabled = false;
|
|
561
|
+
state->show_classes = false;
|
|
514
562
|
state->native_filenames_cache = st_init_numtable();
|
|
515
563
|
state->otel_context_enabled = OTEL_CONTEXT_ENABLED_FALSE;
|
|
516
564
|
state->otel_context_source = OTEL_CONTEXT_SOURCE_UNKNOWN;
|
|
@@ -546,24 +594,28 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
|
|
|
546
594
|
VALUE waiting_for_gvl_threshold_ns = rb_hash_fetch(options, ID2SYM(rb_intern("waiting_for_gvl_threshold_ns")));
|
|
547
595
|
VALUE otel_context_enabled = rb_hash_fetch(options, ID2SYM(rb_intern("otel_context_enabled")));
|
|
548
596
|
VALUE native_filenames_enabled = rb_hash_fetch(options, ID2SYM(rb_intern("native_filenames_enabled")));
|
|
597
|
+
VALUE show_classes = rb_hash_fetch(options, ID2SYM(rb_intern("show_classes")));
|
|
549
598
|
VALUE overhead_filename = rb_hash_fetch(options, ID2SYM(rb_intern("overhead_filename")));
|
|
550
599
|
|
|
551
600
|
ENFORCE_TYPE(max_frames, T_FIXNUM);
|
|
552
601
|
ENFORCE_BOOLEAN(endpoint_collection_enabled);
|
|
553
602
|
ENFORCE_TYPE(waiting_for_gvl_threshold_ns, T_FIXNUM);
|
|
554
603
|
ENFORCE_BOOLEAN(native_filenames_enabled);
|
|
604
|
+
ENFORCE_BOOLEAN(show_classes);
|
|
555
605
|
ENFORCE_TYPE(overhead_filename, T_STRING);
|
|
556
606
|
|
|
607
|
+
uint16_t max_frame_int = sampling_buffer_check_max_frames(NUM2INT(max_frames));
|
|
608
|
+
|
|
557
609
|
thread_context_collector_state *state;
|
|
558
610
|
TypedData_Get_Struct(self_instance, thread_context_collector_state, &thread_context_collector_typed_data, state);
|
|
559
611
|
|
|
560
612
|
// Update this when modifying state struct
|
|
561
|
-
state->locations
|
|
562
|
-
state->locations.ptr = ruby_xcalloc(state->locations.len, sizeof(ddog_prof_Location));
|
|
613
|
+
sample_locations_initialize(&state->locations, max_frame_int, show_classes == Qtrue);
|
|
563
614
|
state->recorder_instance = enforce_recorder_instance(recorder_instance);
|
|
564
615
|
recorder_install_on_serialize(recorder_instance, self_instance);
|
|
565
616
|
state->endpoint_collection_enabled = (endpoint_collection_enabled == Qtrue);
|
|
566
617
|
state->native_filenames_enabled = (native_filenames_enabled == Qtrue);
|
|
618
|
+
state->show_classes = (show_classes == Qtrue);
|
|
567
619
|
state->overhead_filename = overhead_filename;
|
|
568
620
|
if (otel_context_enabled == Qfalse || otel_context_enabled == Qnil) {
|
|
569
621
|
state->otel_context_enabled = OTEL_CONTEXT_ENABLED_FALSE;
|
|
@@ -585,6 +637,11 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
|
|
|
585
637
|
state->tracer_context_key = rb_to_id(tracer_context_key);
|
|
586
638
|
}
|
|
587
639
|
|
|
640
|
+
if (thread_begin_tracepoint == Qnil) {
|
|
641
|
+
thread_begin_tracepoint = rb_tracepoint_new(Qnil, RUBY_EVENT_THREAD_BEGIN, on_thread_begin_event, NULL);
|
|
642
|
+
rb_tracepoint_enable(thread_begin_tracepoint);
|
|
643
|
+
}
|
|
644
|
+
|
|
588
645
|
return Qtrue;
|
|
589
646
|
}
|
|
590
647
|
|
|
@@ -643,17 +700,8 @@ static void record_sampling_overhead(thread_context_collector_state *state, per_
|
|
|
643
700
|
long wall_time_after_sampling = monotonic_wall_time_now_ns(RAISE_ON_FAILURE);
|
|
644
701
|
long cpu_time_after_sampling = cpu_time_now_ns(current_thread_context);
|
|
645
702
|
|
|
646
|
-
long overhead_cpu_time_ns =
|
|
647
|
-
|
|
648
|
-
cpu_time_after_sampling,
|
|
649
|
-
current_thread_context->gc_tracking.cpu_time_at_start_ns,
|
|
650
|
-
IS_CPU_TIME);
|
|
651
|
-
|
|
652
|
-
long overhead_wall_time_ns = update_time_since_previous_sample(
|
|
653
|
-
¤t_thread_context->wall_time_at_previous_sample_ns,
|
|
654
|
-
wall_time_after_sampling,
|
|
655
|
-
INVALID_TIME,
|
|
656
|
-
IS_WALL_TIME);
|
|
703
|
+
long overhead_cpu_time_ns = update_cpu_time_since_previous_sample(current_thread_context, cpu_time_after_sampling);
|
|
704
|
+
long overhead_wall_time_ns = update_wall_time_since_previous_sample(current_thread_context, wall_time_after_sampling);
|
|
657
705
|
|
|
658
706
|
ddog_prof_Label overhead_labels[] = {
|
|
659
707
|
{.key = DDOG_CHARSLICE_C("thread id"), .str = DDOG_CHARSLICE_C("0"), .num = 0},
|
|
@@ -698,7 +746,7 @@ void thread_context_collector_sample(VALUE self_instance, long current_monotonic
|
|
|
698
746
|
TypedData_Get_Struct(self_instance, thread_context_collector_state, &thread_context_collector_typed_data, state);
|
|
699
747
|
|
|
700
748
|
VALUE current_thread = rb_thread_current();
|
|
701
|
-
per_thread_context *current_thread_context = get_or_create_context_for(current_thread
|
|
749
|
+
per_thread_context *current_thread_context = get_or_create_context_for(current_thread);
|
|
702
750
|
long cpu_time_at_sample_start_for_current_thread = cpu_time_now_ns(current_thread_context);
|
|
703
751
|
|
|
704
752
|
VALUE threads = thread_list(state);
|
|
@@ -706,7 +754,7 @@ void thread_context_collector_sample(VALUE self_instance, long current_monotonic
|
|
|
706
754
|
const long thread_count = RARRAY_LEN(threads);
|
|
707
755
|
for (long i = 0; i < thread_count; i++) {
|
|
708
756
|
VALUE thread = RARRAY_AREF(threads, i);
|
|
709
|
-
per_thread_context *thread_context = get_or_create_context_for(thread
|
|
757
|
+
per_thread_context *thread_context = get_or_create_context_for(thread);
|
|
710
758
|
|
|
711
759
|
// We account for cpu-time for the current thread in a different way: we use the cpu-time at sampling start,
|
|
712
760
|
// to avoid blaming the time the profiler took on whatever is currently running on the thread,
|
|
@@ -717,44 +765,41 @@ void thread_context_collector_sample(VALUE self_instance, long current_monotonic
|
|
|
717
765
|
state,
|
|
718
766
|
thread,
|
|
719
767
|
thread_context,
|
|
720
|
-
&thread_context->sampling_buffer,
|
|
721
768
|
current_cpu_time_ns,
|
|
722
769
|
current_monotonic_wall_time_ns,
|
|
723
770
|
false);
|
|
724
771
|
}
|
|
725
772
|
|
|
726
773
|
state->stats.sample_count++;
|
|
727
|
-
|
|
774
|
+
|
|
775
|
+
// If the current thread is a profiler-internal thread, we don't use record_sampling_overhead()
|
|
776
|
+
// and accept the sampling overhead is attributed to the profiler-internal thread
|
|
777
|
+
// (both are under the same datadog group in the flamegraph).
|
|
778
|
+
// The reason we need to do this is profiler-internal threads are skipped during per-tick sampling
|
|
779
|
+
// so their timestamps are not updated. record_sampling_overhead() would see the stale previous-sample timestamps and
|
|
780
|
+
// attribute the entire sleep interval incorrectly as overhead instead of just the sampling work.
|
|
781
|
+
if (!current_thread_context->is_profiler_internal_thread) {
|
|
782
|
+
record_sampling_overhead(state, current_thread_context);
|
|
783
|
+
}
|
|
728
784
|
}
|
|
729
785
|
|
|
730
786
|
static void update_metrics_and_sample(
|
|
731
787
|
thread_context_collector_state *state,
|
|
732
788
|
VALUE thread_being_sampled,
|
|
733
789
|
per_thread_context *thread_context,
|
|
734
|
-
sampling_buffer* sampling_buffer,
|
|
735
790
|
long current_cpu_time_ns,
|
|
736
791
|
long current_monotonic_wall_time_ns,
|
|
737
|
-
bool
|
|
792
|
+
bool force_sample
|
|
738
793
|
) {
|
|
739
794
|
bool is_gvl_waiting_state =
|
|
740
|
-
handle_gvl_waiting(state, thread_being_sampled, thread_context,
|
|
795
|
+
handle_gvl_waiting(state, thread_being_sampled, thread_context, current_cpu_time_ns);
|
|
741
796
|
|
|
742
|
-
if (skip_sample(state, thread_context, is_gvl_waiting_state,
|
|
797
|
+
if (skip_sample(state, thread_context, is_gvl_waiting_state, force_sample)) return;
|
|
743
798
|
|
|
744
799
|
// Don't assign/update cpu during "Waiting for GVL"
|
|
745
|
-
long cpu_time_elapsed_ns = is_gvl_waiting_state ? 0 :
|
|
746
|
-
&thread_context->cpu_time_at_previous_sample_ns,
|
|
747
|
-
current_cpu_time_ns,
|
|
748
|
-
thread_context->gc_tracking.cpu_time_at_start_ns,
|
|
749
|
-
IS_CPU_TIME
|
|
750
|
-
);
|
|
800
|
+
long cpu_time_elapsed_ns = is_gvl_waiting_state ? 0 : update_cpu_time_since_previous_sample(thread_context, current_cpu_time_ns);
|
|
751
801
|
|
|
752
|
-
long wall_time_elapsed_ns =
|
|
753
|
-
&thread_context->wall_time_at_previous_sample_ns,
|
|
754
|
-
current_monotonic_wall_time_ns,
|
|
755
|
-
INVALID_TIME,
|
|
756
|
-
IS_WALL_TIME
|
|
757
|
-
);
|
|
802
|
+
long wall_time_elapsed_ns = update_wall_time_since_previous_sample(thread_context, current_monotonic_wall_time_ns);
|
|
758
803
|
|
|
759
804
|
// A thread enters "Waiting for GVL", well, as the name implies, without the GVL.
|
|
760
805
|
//
|
|
@@ -775,7 +820,6 @@ static void update_metrics_and_sample(
|
|
|
775
820
|
state,
|
|
776
821
|
thread_being_sampled,
|
|
777
822
|
thread_context,
|
|
778
|
-
sampling_buffer,
|
|
779
823
|
(sample_values) {.cpu_time_ns = cpu_time_elapsed_ns, .cpu_or_wall_samples = 1, .wall_time_ns = wall_time_elapsed_ns},
|
|
780
824
|
current_monotonic_wall_time_ns,
|
|
781
825
|
NULL,
|
|
@@ -785,7 +829,12 @@ static void update_metrics_and_sample(
|
|
|
785
829
|
);
|
|
786
830
|
}
|
|
787
831
|
|
|
788
|
-
static bool skip_sample(thread_context_collector_state *state, per_thread_context *thread_context, bool is_gvl_waiting_state, bool
|
|
832
|
+
static bool skip_sample(thread_context_collector_state *state, per_thread_context *thread_context, bool is_gvl_waiting_state, bool force_sample) {
|
|
833
|
+
if (!force_sample && thread_context->is_profiler_internal_thread) {
|
|
834
|
+
state->stats.profiler_thread_samples_skipped++;
|
|
835
|
+
return true;
|
|
836
|
+
}
|
|
837
|
+
|
|
789
838
|
// Racy read but harmless, can only cause an extra sample
|
|
790
839
|
uint64_t gvl_state_change_count = thread_context->gvl_state_change_count;
|
|
791
840
|
|
|
@@ -797,7 +846,7 @@ static bool skip_sample(thread_context_collector_state *state, per_thread_contex
|
|
|
797
846
|
// in handle_gvl_waiting (situation 1 extra sample, situation 2 regular sample) keeps running.
|
|
798
847
|
// TODO: we could probably also skip while "Waiting for GVL"
|
|
799
848
|
if (!is_gvl_waiting_state &&
|
|
800
|
-
!
|
|
849
|
+
!force_sample &&
|
|
801
850
|
(gvl_state_change_count & GVL_SUSPENDED) &&
|
|
802
851
|
gvl_state_change_count == thread_context->gvl_state_change_count_at_previous_sample) {
|
|
803
852
|
state->stats.inactive_thread_samples_skipped++;
|
|
@@ -829,10 +878,8 @@ void thread_context_collector_on_gc_start(VALUE self_instance) {
|
|
|
829
878
|
|
|
830
879
|
per_thread_context *thread_context = get_per_thread_context(rb_thread_current());
|
|
831
880
|
|
|
832
|
-
//
|
|
833
|
-
//
|
|
834
|
-
// GC" is a rare enough case that we can just ignore it.
|
|
835
|
-
// We can always improve this later if we find that this happens often (and we have the counter to help us figure that out)!
|
|
881
|
+
// Context is created eagerly via on_thread_begin_event, so this should not normally be NULL.
|
|
882
|
+
// We can't get_or_create_context_for() here since we can't allocate (GC context).
|
|
836
883
|
if (thread_context == NULL) {
|
|
837
884
|
state->stats.gc_samples_missed_due_to_missing_context++;
|
|
838
885
|
return;
|
|
@@ -862,8 +909,7 @@ bool thread_context_collector_on_gc_finish(VALUE self_instance) {
|
|
|
862
909
|
|
|
863
910
|
per_thread_context *thread_context = get_per_thread_context(rb_thread_current());
|
|
864
911
|
|
|
865
|
-
//
|
|
866
|
-
// how often this happens -- see on_gc_start.
|
|
912
|
+
// Context is created eagerly, so this should not normally be NULL (see on_gc_start).
|
|
867
913
|
if (thread_context == NULL) return false;
|
|
868
914
|
|
|
869
915
|
long cpu_time_at_start_ns = thread_context->gc_tracking.cpu_time_at_start_ns;
|
|
@@ -904,9 +950,9 @@ bool thread_context_collector_on_gc_finish(VALUE self_instance) {
|
|
|
904
950
|
state->gc_tracking.accumulated_wall_time_ns += gc_wall_time_elapsed_ns;
|
|
905
951
|
state->gc_tracking.wall_time_at_previous_gc_ns = wall_time_at_finish_ns;
|
|
906
952
|
|
|
907
|
-
// Update cpu-time accounting so it doesn't include the cpu-time spent in GC during the next sample
|
|
908
|
-
// We don't
|
|
909
|
-
//
|
|
953
|
+
// Update cpu-time accounting so it doesn't include the cpu-time spent in GC during the next sample.
|
|
954
|
+
// We don't do the same for wall-time, because GC is just like any other reason a thread didn't make
|
|
955
|
+
// progress -- time always goes forward regardless of the thread making progress on what it wanted.
|
|
910
956
|
if (thread_context->cpu_time_at_previous_sample_ns != INVALID_TIME) {
|
|
911
957
|
thread_context->cpu_time_at_previous_sample_ns += gc_cpu_time_elapsed_ns;
|
|
912
958
|
}
|
|
@@ -982,7 +1028,6 @@ static void trigger_sample_for_thread(
|
|
|
982
1028
|
thread_context_collector_state *state,
|
|
983
1029
|
VALUE thread_being_sampled,
|
|
984
1030
|
per_thread_context *thread_context,
|
|
985
|
-
sampling_buffer* sampling_buffer,
|
|
986
1031
|
sample_values values,
|
|
987
1032
|
long current_monotonic_wall_time_ns,
|
|
988
1033
|
// These two labels are only used for allocation profiling; @ivoanjo: may want to refactor this at some point?
|
|
@@ -1104,7 +1149,7 @@ static void trigger_sample_for_thread(
|
|
|
1104
1149
|
|
|
1105
1150
|
sample_thread(
|
|
1106
1151
|
thread_being_sampled,
|
|
1107
|
-
sampling_buffer,
|
|
1152
|
+
&thread_context->sampling_buffer,
|
|
1108
1153
|
state->locations,
|
|
1109
1154
|
state->recorder_instance,
|
|
1110
1155
|
values,
|
|
@@ -1115,7 +1160,8 @@ static void trigger_sample_for_thread(
|
|
|
1115
1160
|
.is_gvl_waiting_state = is_gvl_waiting_state,
|
|
1116
1161
|
},
|
|
1117
1162
|
state->native_filenames_enabled,
|
|
1118
|
-
state->native_filenames_cache
|
|
1163
|
+
state->native_filenames_cache,
|
|
1164
|
+
state->show_classes
|
|
1119
1165
|
);
|
|
1120
1166
|
}
|
|
1121
1167
|
|
|
@@ -1133,17 +1179,22 @@ static VALUE _native_thread_list(DDTRACE_UNUSED VALUE _self) {
|
|
|
1133
1179
|
return result;
|
|
1134
1180
|
}
|
|
1135
1181
|
|
|
1182
|
+
static void check_frozen_thread(VALUE thread) {
|
|
1183
|
+
if (RB_OBJ_FROZEN(thread)) {
|
|
1184
|
+
raise_error(rb_eFrozenError, "Cannot setup profiler state for Thread %"PRIsVALUE" because it is frozen. Please avoid freezing Thread instances and/or report the issue to dd-trace-rb", thread);
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
// See the docs on struct per_thread_context.
|
|
1136
1189
|
// This allocates a Ruby object and therefore needs the GVL and is not safe to call from RUBY_INTERNAL_EVENT_* hooks.
|
|
1137
|
-
static per_thread_context *get_or_create_context_for(VALUE thread
|
|
1190
|
+
static per_thread_context *get_or_create_context_for(VALUE thread) {
|
|
1138
1191
|
per_thread_context *thread_context = get_per_thread_context(thread);
|
|
1139
1192
|
if (thread_context != NULL) return thread_context;
|
|
1140
1193
|
|
|
1141
|
-
|
|
1142
|
-
raise_error(rb_eFrozenError, "Cannot setup profiler state for Thread %"PRIsVALUE" because it is frozen. Please avoid freezing Thread instances and/or report the issue to dd-trace-rb", thread);
|
|
1143
|
-
}
|
|
1194
|
+
check_frozen_thread(thread);
|
|
1144
1195
|
|
|
1145
1196
|
thread_context = calloc(1, sizeof(per_thread_context)); // See "note on calloc vs ruby_xcalloc use" in heap_recorder.c
|
|
1146
|
-
initialize_context(thread, thread_context
|
|
1197
|
+
initialize_context(thread, thread_context);
|
|
1147
1198
|
|
|
1148
1199
|
VALUE wrapper = TypedData_Wrap_Struct(rb_cObject, &per_thread_context_typed_data, thread_context);
|
|
1149
1200
|
rb_ivar_set(thread, dd_per_thread_context_id, wrapper);
|
|
@@ -1152,6 +1203,14 @@ static per_thread_context *get_or_create_context_for(VALUE thread, thread_contex
|
|
|
1152
1203
|
return thread_context;
|
|
1153
1204
|
}
|
|
1154
1205
|
|
|
1206
|
+
static void on_thread_begin_event(VALUE tracepoint_data, DDTRACE_UNUSED void *unused) {
|
|
1207
|
+
if (!ddtrace_rb_ractor_main_p()) return;
|
|
1208
|
+
|
|
1209
|
+
VALUE thread = rb_tracearg_self(rb_tracearg_from_tracepoint(tracepoint_data));
|
|
1210
|
+
ENFORCE_THREAD(thread);
|
|
1211
|
+
get_or_create_context_for(thread);
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1155
1214
|
#define LOGGING_GEM_PATH "/lib/logging/diagnostic_context.rb"
|
|
1156
1215
|
|
|
1157
1216
|
// The `logging` gem monkey patches thread creation, which makes the `invoke_location_for` useless, since every thread
|
|
@@ -1173,8 +1232,11 @@ static bool is_logging_gem_monkey_patch(VALUE invoke_file_location) {
|
|
|
1173
1232
|
return strncmp(invoke_file + invoke_file_len - logging_gem_path_len, LOGGING_GEM_PATH, logging_gem_path_len) == 0;
|
|
1174
1233
|
}
|
|
1175
1234
|
|
|
1176
|
-
static void initialize_context(VALUE thread, per_thread_context *thread_context
|
|
1177
|
-
|
|
1235
|
+
static void initialize_context(VALUE thread, per_thread_context *thread_context) {
|
|
1236
|
+
// We always create per_thread_context's with latest_max_frames; that value is kept in sync with the
|
|
1237
|
+
// active profiler's max_frames by the global reset that runs when profiling starts
|
|
1238
|
+
// so we expect to always see here the latest correct value to be used.
|
|
1239
|
+
sampling_buffer_initialize(&thread_context->sampling_buffer, latest_max_frames);
|
|
1178
1240
|
|
|
1179
1241
|
snprintf(thread_context->thread_id, THREAD_ID_LIMIT_CHARS, "%"PRIu64" (%lu)", native_thread_id_for(thread), (unsigned long) thread_id_for(thread));
|
|
1180
1242
|
thread_context->thread_id_char_slice = (ddog_CharSlice) {.ptr = thread_context->thread_id, .len = strlen(thread_context->thread_id)};
|
|
@@ -1193,7 +1255,7 @@ static void initialize_context(VALUE thread, per_thread_context *thread_context,
|
|
|
1193
1255
|
} else {
|
|
1194
1256
|
snprintf(thread_context->thread_invoke_location, THREAD_INVOKE_LOCATION_LIMIT_CHARS, "%s", "(Unnamed thread)");
|
|
1195
1257
|
}
|
|
1196
|
-
} else if (thread !=
|
|
1258
|
+
} else if (thread != rb_thread_main()) {
|
|
1197
1259
|
// If the first function of a thread is native code, there won't be an invoke location, so we use this fallback.
|
|
1198
1260
|
// NOTE: In the future, I wonder if we could take the pointer to the native function, and try to see if there's a native
|
|
1199
1261
|
// symbol attached to it.
|
|
@@ -1207,9 +1269,8 @@ static void initialize_context(VALUE thread, per_thread_context *thread_context,
|
|
|
1207
1269
|
|
|
1208
1270
|
thread_context->thread_cpu_time_id = thread_cpu_time_id_for(thread);
|
|
1209
1271
|
|
|
1210
|
-
|
|
1211
|
-
thread_context->cpu_time_at_previous_sample_ns =
|
|
1212
|
-
thread_context->wall_time_at_previous_sample_ns = INVALID_TIME;
|
|
1272
|
+
thread_context->wall_time_at_previous_sample_ns = monotonic_wall_time_now_ns(RAISE_ON_FAILURE);
|
|
1273
|
+
thread_context->cpu_time_at_previous_sample_ns = cpu_time_now_ns(thread_context);
|
|
1213
1274
|
|
|
1214
1275
|
// These will only be used during a GC operation
|
|
1215
1276
|
thread_context->gc_tracking.cpu_time_at_start_ns = INVALID_TIME;
|
|
@@ -1219,6 +1280,45 @@ static void initialize_context(VALUE thread, per_thread_context *thread_context,
|
|
|
1219
1280
|
thread_context->gvl_state_change_count = 0;
|
|
1220
1281
|
}
|
|
1221
1282
|
|
|
1283
|
+
// This MUST be called before profiling starts, so that a new profiler session starts from a fresh state and never
|
|
1284
|
+
// observes or includes any leftover stale state from a previous session.
|
|
1285
|
+
// Such a call MUST happen while the CpuAndWallTimeWorker is stopped (e.g. no tracepoints active, no signals
|
|
1286
|
+
// triggering samples, no gvl hooks, etc).
|
|
1287
|
+
//
|
|
1288
|
+
// It updates the global `latest_max_frames` from the given (latest) ThreadContext and (re)creates every per-thread
|
|
1289
|
+
// context's sampling buffer sized accordingly, so the buffers always match the collector that's about to start
|
|
1290
|
+
// sampling -- even if a previous session used a different max_frames.
|
|
1291
|
+
void thread_context_collector_reset_all_per_thread_contexts(VALUE self_instance) {
|
|
1292
|
+
thread_context_collector_state *state;
|
|
1293
|
+
TypedData_Get_Struct(self_instance, thread_context_collector_state, &thread_context_collector_typed_data, state);
|
|
1294
|
+
|
|
1295
|
+
// Update global max frames to be used when allocating sampling buffers
|
|
1296
|
+
if (state->locations.len == 0) {
|
|
1297
|
+
raise_error(rb_eRuntimeError, "BUG: Unexpected locations.len == 0. Is this ThreadContext not initialized?");
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
latest_max_frames = state->locations.len;
|
|
1301
|
+
|
|
1302
|
+
VALUE threads = thread_list(state);
|
|
1303
|
+
const long thread_count = RARRAY_LEN(threads);
|
|
1304
|
+
for (long i = 0; i < thread_count; i++) {
|
|
1305
|
+
VALUE thread = rb_ary_entry(threads, i);
|
|
1306
|
+
per_thread_context *thread_context = get_per_thread_context(thread);
|
|
1307
|
+
if (thread_context != NULL) {
|
|
1308
|
+
bool is_profiler_internal_thread = thread_context->is_profiler_internal_thread;
|
|
1309
|
+
|
|
1310
|
+
sampling_buffer_free(&thread_context->sampling_buffer);
|
|
1311
|
+
memset(thread_context, 0, sizeof(per_thread_context));
|
|
1312
|
+
initialize_context(thread, thread_context);
|
|
1313
|
+
|
|
1314
|
+
thread_context->is_profiler_internal_thread = is_profiler_internal_thread;
|
|
1315
|
+
} else {
|
|
1316
|
+
// If thread didn't have a context, let's trigger its creation
|
|
1317
|
+
get_or_create_context_for(thread);
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1222
1322
|
static VALUE _native_inspect(DDTRACE_UNUSED VALUE _self, VALUE collector_instance) {
|
|
1223
1323
|
thread_context_collector_state *state;
|
|
1224
1324
|
TypedData_Get_Struct(collector_instance, thread_context_collector_state, &thread_context_collector_typed_data, state);
|
|
@@ -1233,6 +1333,7 @@ static VALUE _native_inspect(DDTRACE_UNUSED VALUE _self, VALUE collector_instanc
|
|
|
1233
1333
|
rb_str_concat(result, rb_sprintf(" stats=%"PRIsVALUE, stats_to_ruby_hash(state, rb_hash_new())));
|
|
1234
1334
|
rb_str_concat(result, rb_sprintf(" endpoint_collection_enabled=%"PRIsVALUE, state->endpoint_collection_enabled ? Qtrue : Qfalse));
|
|
1235
1335
|
rb_str_concat(result, rb_sprintf(" native_filenames_enabled=%"PRIsVALUE, state->native_filenames_enabled ? Qtrue : Qfalse));
|
|
1336
|
+
rb_str_concat(result, rb_sprintf(" show_classes=%"PRIsVALUE, state->show_classes ? Qtrue : Qfalse));
|
|
1236
1337
|
// Note: `st_table_size()` is available from Ruby 3.2+ but not before
|
|
1237
1338
|
rb_str_concat(result, rb_sprintf(" native_filenames_cache_size=%zu", state->native_filenames_cache->num_entries));
|
|
1238
1339
|
rb_str_concat(result, rb_sprintf(" otel_context_enabled=%d", state->otel_context_enabled));
|
|
@@ -1271,6 +1372,7 @@ static VALUE per_thread_context_to_ruby_hash(per_thread_context *thread_context)
|
|
|
1271
1372
|
ID2SYM(rb_intern("gvl_state_change_count")), /* => */ ULL2NUM(thread_context->gvl_state_change_count),
|
|
1272
1373
|
ID2SYM(rb_intern("gvl_state_change_count_at_previous_sample")), /* => */ ULL2NUM(thread_context->gvl_state_change_count_at_previous_sample),
|
|
1273
1374
|
ID2SYM(rb_intern("was_skipped_at_last_sample")), /* => */ thread_context->was_skipped_at_last_sample ? Qtrue : Qfalse,
|
|
1375
|
+
ID2SYM(rb_intern("is_profiler_internal_thread")), /* => */ thread_context->is_profiler_internal_thread ? Qtrue : Qfalse,
|
|
1274
1376
|
};
|
|
1275
1377
|
for (long unsigned int i = 0; i < VALUE_COUNT(arguments); i += 2) rb_hash_aset(context_as_hash, arguments[i], arguments[i+1]);
|
|
1276
1378
|
|
|
@@ -1284,6 +1386,7 @@ static VALUE stats_to_ruby_hash(thread_context_collector_state *state, VALUE has
|
|
|
1284
1386
|
ID2SYM(rb_intern("gc_samples")), /* => */ UINT2NUM(state->stats.gc_samples),
|
|
1285
1387
|
ID2SYM(rb_intern("gc_samples_missed_due_to_missing_context")), /* => */ UINT2NUM(state->stats.gc_samples_missed_due_to_missing_context),
|
|
1286
1388
|
ID2SYM(rb_intern("inactive_thread_samples_skipped")), /* => */ UINT2NUM(state->stats.inactive_thread_samples_skipped),
|
|
1389
|
+
ID2SYM(rb_intern("profiler_thread_samples_skipped")), /* => */ UINT2NUM(state->stats.profiler_thread_samples_skipped),
|
|
1287
1390
|
};
|
|
1288
1391
|
for (long unsigned int i = 0; i < VALUE_COUNT(arguments); i += 2) rb_hash_aset(hash, arguments[i], arguments[i+1]);
|
|
1289
1392
|
return hash;
|
|
@@ -1323,48 +1426,59 @@ static VALUE _native_per_thread_context(DDTRACE_UNUSED VALUE _self, VALUE collec
|
|
|
1323
1426
|
return result;
|
|
1324
1427
|
}
|
|
1325
1428
|
|
|
1326
|
-
|
|
1327
|
-
static long update_time_since_previous_sample(long *time_at_previous_sample_ns, long current_time_ns, long gc_start_time_ns, bool is_wall_time) {
|
|
1429
|
+
static long update_time_since_previous_sample(long *time_at_previous_sample_ns, long current_time_ns, per_thread_context *thread_context) {
|
|
1328
1430
|
// If we didn't have a time for the previous sample, we use the current one
|
|
1329
1431
|
if (*time_at_previous_sample_ns == INVALID_TIME) *time_at_previous_sample_ns = current_time_ns;
|
|
1330
1432
|
|
|
1331
|
-
// We don't
|
|
1332
|
-
//
|
|
1333
|
-
|
|
1334
|
-
|
|
1433
|
+
// We don't expect to be sampling a thread (and thus updating these counters) while Ruby is doing GC (between
|
|
1434
|
+
// `thread_context_collector_on_gc_start` and `thread_context_collector_on_gc_finish`)
|
|
1435
|
+
if (thread_context->gc_tracking.cpu_time_at_start_ns != INVALID_TIME) {
|
|
1436
|
+
raise_error(
|
|
1437
|
+
rb_eRuntimeError,
|
|
1438
|
+
"BUG: Unexpected sample during GC (thread_id=%s, gc_tracking.cpu_time_at_start_ns=%ld, "
|
|
1439
|
+
"gc_tracking.wall_time_at_start_ns=%ld, monotonic_wall_time_now_ns=%ld)",
|
|
1440
|
+
thread_context->thread_id,
|
|
1441
|
+
thread_context->gc_tracking.cpu_time_at_start_ns,
|
|
1442
|
+
thread_context->gc_tracking.wall_time_at_start_ns,
|
|
1443
|
+
monotonic_wall_time_now_ns(RAISE_ON_FAILURE)
|
|
1444
|
+
);
|
|
1445
|
+
}
|
|
1335
1446
|
|
|
1336
|
-
|
|
1337
|
-
|
|
1447
|
+
long elapsed_time_ns = current_time_ns - *time_at_previous_sample_ns; // Capture all time since previous sample
|
|
1448
|
+
*time_at_previous_sample_ns = current_time_ns;
|
|
1338
1449
|
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
} else {
|
|
1342
|
-
elapsed_time_ns = gc_start_time_ns - *time_at_previous_sample_ns; // Capture time between previous sample and start of GC only
|
|
1343
|
-
}
|
|
1450
|
+
return elapsed_time_ns;
|
|
1451
|
+
}
|
|
1344
1452
|
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1453
|
+
static long update_cpu_time_since_previous_sample(per_thread_context *thread_context, long current_cpu_time_ns) {
|
|
1454
|
+
long elapsed_time_ns = update_time_since_previous_sample(
|
|
1455
|
+
&thread_context->cpu_time_at_previous_sample_ns,
|
|
1456
|
+
current_cpu_time_ns,
|
|
1457
|
+
thread_context
|
|
1458
|
+
);
|
|
1351
1459
|
|
|
1460
|
+
// We don't expect cpu-time to go backwards, so let's flag this as a bug
|
|
1352
1461
|
if (elapsed_time_ns < 0) {
|
|
1353
|
-
|
|
1354
|
-
// Wall-time can actually go backwards (e.g. when the system clock gets set) so we can't assume time going backwards
|
|
1355
|
-
// was a bug.
|
|
1356
|
-
// @ivoanjo: I've also observed time going backwards spuriously on macOS, see discussion on
|
|
1357
|
-
// https://github.com/DataDog/dd-trace-rb/pull/2336.
|
|
1358
|
-
elapsed_time_ns = 0;
|
|
1359
|
-
} else {
|
|
1360
|
-
// We don't expect non-wall time to go backwards, so let's flag this as a bug
|
|
1361
|
-
raise_error(rb_eRuntimeError, "BUG: Unexpected negative elapsed_time_ns between samples");
|
|
1362
|
-
}
|
|
1462
|
+
raise_error(rb_eRuntimeError, "BUG: Unexpected CPU time going backwards between samples");
|
|
1363
1463
|
}
|
|
1364
1464
|
|
|
1365
1465
|
return elapsed_time_ns;
|
|
1366
1466
|
}
|
|
1367
1467
|
|
|
1468
|
+
static long update_wall_time_since_previous_sample(per_thread_context *thread_context, long current_wall_time_ns) {
|
|
1469
|
+
long elapsed_time_ns = update_time_since_previous_sample(
|
|
1470
|
+
&thread_context->wall_time_at_previous_sample_ns,
|
|
1471
|
+
current_wall_time_ns,
|
|
1472
|
+
thread_context
|
|
1473
|
+
);
|
|
1474
|
+
|
|
1475
|
+
// Wall-time can actually go backwards (e.g. when the system clock gets set) so we can't assume time going backwards
|
|
1476
|
+
// was a bug.
|
|
1477
|
+
// @ivoanjo: I've also observed time going backwards spuriously on macOS, see discussion on
|
|
1478
|
+
// https://github.com/DataDog/dd-trace-rb/pull/2336.
|
|
1479
|
+
return long_max_of(elapsed_time_ns, 0);
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1368
1482
|
// Safety: This function is assumed never to raise exceptions by callers
|
|
1369
1483
|
static long cpu_time_now_ns(per_thread_context *thread_context) {
|
|
1370
1484
|
thread_cpu_time cpu_time = thread_cpu_time_for(thread_context->thread_cpu_time_id);
|
|
@@ -1521,8 +1635,8 @@ static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE collector
|
|
|
1521
1635
|
|
|
1522
1636
|
state->stats = (struct stats) {}; // Resets all stats back to zero
|
|
1523
1637
|
|
|
1524
|
-
//
|
|
1525
|
-
|
|
1638
|
+
// No need to clean-up the per-thread context because the CpuAndWallTimeWorker always cleans
|
|
1639
|
+
// it up unconditionally on every start/restart and that includes after a fork.
|
|
1526
1640
|
|
|
1527
1641
|
rb_funcall(state->recorder_instance, rb_intern("reset_after_fork"), 0);
|
|
1528
1642
|
|
|
@@ -1634,11 +1748,10 @@ bool thread_context_collector_sample_allocation(VALUE self_instance, per_thread_
|
|
|
1634
1748
|
state,
|
|
1635
1749
|
current_thread,
|
|
1636
1750
|
thread_context,
|
|
1637
|
-
&thread_context->sampling_buffer,
|
|
1638
1751
|
(sample_values) {.alloc_samples = sample_weight, .alloc_samples_unscaled = 1, .heap_sample = true},
|
|
1639
1752
|
INVALID_TIME, // For now we're not collecting timestamps for allocation events, as per profiling team internal discussions
|
|
1640
1753
|
&ruby_vm_type,
|
|
1641
|
-
|
|
1754
|
+
&class_name,
|
|
1642
1755
|
/* is_gvl_waiting_state: */ false,
|
|
1643
1756
|
/* is_safe_to_allocate_objects: */ false // Not safe to allocate further inside the NEWOBJ tracepoint
|
|
1644
1757
|
);
|
|
@@ -1649,9 +1762,10 @@ bool thread_context_collector_sample_allocation(VALUE self_instance, per_thread_
|
|
|
1649
1762
|
// This method exists only to enable testing Datadog::Profiling::Collectors::ThreadContext behavior using RSpec.
|
|
1650
1763
|
// It SHOULD NOT be used for other purposes.
|
|
1651
1764
|
static VALUE _native_sample_allocation(DDTRACE_UNUSED VALUE self, VALUE collector_instance, VALUE sample_weight, VALUE new_object) {
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1765
|
+
per_thread_context *thread_context = get_per_thread_context(rb_thread_current());
|
|
1766
|
+
if (thread_context == NULL) {
|
|
1767
|
+
rb_raise(rb_eRuntimeError, "Missing per_thread_context for current thread in _native_sample_allocation");
|
|
1768
|
+
}
|
|
1655
1769
|
|
|
1656
1770
|
debug_enter_unsafe_context();
|
|
1657
1771
|
|
|
@@ -1972,49 +2086,115 @@ void thread_context_collector_stats_reset_not_thread_safe(VALUE self_instance) {
|
|
|
1972
2086
|
state->stats = (struct stats) {};
|
|
1973
2087
|
}
|
|
1974
2088
|
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
2089
|
+
static void mark_thread_as_profiler_internal(per_thread_context *ctx) {
|
|
2090
|
+
ctx->is_profiler_internal_thread = true;
|
|
2091
|
+
}
|
|
2092
|
+
|
|
2093
|
+
void thread_context_collector_profiler_internal_thread_started(void) {
|
|
2094
|
+
per_thread_context *ctx = get_or_create_context_for(rb_thread_current());
|
|
2095
|
+
mark_thread_as_profiler_internal(ctx);
|
|
2096
|
+
}
|
|
2097
|
+
|
|
2098
|
+
static VALUE _native_mark_thread_as_profiler_internal(DDTRACE_UNUSED VALUE self, VALUE thread) {
|
|
2099
|
+
per_thread_context *ctx = get_or_create_context_for(thread);
|
|
2100
|
+
mark_thread_as_profiler_internal(ctx);
|
|
2101
|
+
return Qnil;
|
|
2102
|
+
}
|
|
2103
|
+
|
|
2104
|
+
// Called via rb_ensure when a profiler-internal thread (worker or idle helper) is about to exit.
|
|
2105
|
+
// Records a final sample so the thread's accumulated cpu/wall time since the last on_serialize
|
|
2106
|
+
// flush is not lost. on_serialize (below) also flushes profiler-internal threads during periodic
|
|
2107
|
+
// serialization, but it can't help at shutdown: by the time the final serialize runs, these
|
|
2108
|
+
// threads are already dead and absent from thread_list.
|
|
2109
|
+
void thread_context_collector_profiler_internal_thread_done(VALUE self_instance) {
|
|
2110
|
+
thread_context_collector_state *state;
|
|
2111
|
+
TypedData_Get_Struct(self_instance, thread_context_collector_state, &thread_context_collector_typed_data, state);
|
|
2112
|
+
|
|
2113
|
+
VALUE current_thread = rb_thread_current();
|
|
2114
|
+
per_thread_context *thread_context = get_or_create_context_for(current_thread);
|
|
2115
|
+
if (!thread_context->is_profiler_internal_thread) {
|
|
2116
|
+
rb_raise(rb_eRuntimeError, "current thread %"PRIsVALUE" is not profiler-internal thread", current_thread);
|
|
1978
2117
|
}
|
|
1979
2118
|
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
// time recorded in this reporting period. Without this, a thread that sleeps across the whole
|
|
1983
|
-
// period would not be reported at all.
|
|
1984
|
-
void thread_context_collector_on_serialize(VALUE self_instance) {
|
|
1985
|
-
thread_context_collector_state *state;
|
|
1986
|
-
TypedData_Get_Struct(self_instance, thread_context_collector_state, &thread_context_collector_typed_data, state);
|
|
2119
|
+
long current_cpu_time_ns = cpu_time_now_ns(thread_context);
|
|
2120
|
+
long current_monotonic_wall_time_ns = monotonic_wall_time_now_ns(RAISE_ON_FAILURE);
|
|
1987
2121
|
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2122
|
+
update_metrics_and_sample(
|
|
2123
|
+
state,
|
|
2124
|
+
current_thread,
|
|
2125
|
+
thread_context,
|
|
2126
|
+
current_cpu_time_ns,
|
|
2127
|
+
current_monotonic_wall_time_ns,
|
|
2128
|
+
true);
|
|
2129
|
+
}
|
|
2130
|
+
|
|
2131
|
+
// Flushes threads whose last per-tick sample was skipped (either by the SUSPENDED-skip
|
|
2132
|
+
// optimization, or by is_profiler_internal_thread) so their accumulated time is recorded.
|
|
2133
|
+
// Called by the stack recorder at the start of _native_serialize (regular periodic flush).
|
|
2134
|
+
void thread_context_collector_on_serialize(VALUE self_instance) {
|
|
2135
|
+
thread_context_collector_state *state;
|
|
2136
|
+
TypedData_Get_Struct(self_instance, thread_context_collector_state, &thread_context_collector_typed_data, state);
|
|
2137
|
+
|
|
2138
|
+
long current_monotonic_wall_time_ns = monotonic_wall_time_now_ns(RAISE_ON_FAILURE);
|
|
2139
|
+
VALUE threads = thread_list(state);
|
|
2140
|
+
const long thread_count = RARRAY_LEN(threads);
|
|
2141
|
+
|
|
2142
|
+
for (long i = 0; i < thread_count; i++) {
|
|
2143
|
+
VALUE thread = RARRAY_AREF(threads, i);
|
|
2144
|
+
per_thread_context *thread_context = get_per_thread_context(thread);
|
|
2145
|
+
|
|
2146
|
+
if (thread_context != NULL && (thread_context->was_skipped_at_last_sample || thread_context->is_profiler_internal_thread)) {
|
|
2147
|
+
long current_cpu_time_ns = cpu_time_now_ns(thread_context);
|
|
2148
|
+
// We need to force_sample=true otherwise this sample would be skipped too
|
|
2149
|
+
update_metrics_and_sample(
|
|
2150
|
+
state,
|
|
2151
|
+
thread,
|
|
2152
|
+
thread_context,
|
|
2153
|
+
current_cpu_time_ns,
|
|
2154
|
+
current_monotonic_wall_time_ns,
|
|
2155
|
+
true);
|
|
2008
2156
|
}
|
|
2009
2157
|
}
|
|
2158
|
+
}
|
|
2010
2159
|
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2160
|
+
void thread_context_collector_on_gvl_released(per_thread_context *thread_context) {
|
|
2161
|
+
thread_context->gvl_state_change_count |= GVL_SUSPENDED;
|
|
2162
|
+
}
|
|
2014
2163
|
|
|
2015
|
-
|
|
2016
|
-
|
|
2164
|
+
void thread_context_collector_on_gvl_waiting(per_thread_context *thread_context) {
|
|
2165
|
+
long current_monotonic_wall_time_ns = monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE);
|
|
2166
|
+
if (current_monotonic_wall_time_ns <= 0) return;
|
|
2167
|
+
|
|
2168
|
+
thread_context->gvl_waiting_at = current_monotonic_wall_time_ns;
|
|
2169
|
+
}
|
|
2170
|
+
|
|
2171
|
+
static VALUE _native_on_gvl_waiting(DDTRACE_UNUSED VALUE self, VALUE thread) {
|
|
2172
|
+
ENFORCE_THREAD(thread);
|
|
2173
|
+
|
|
2174
|
+
debug_enter_unsafe_context();
|
|
2175
|
+
|
|
2176
|
+
per_thread_context *thread_context = get_per_thread_context(thread);
|
|
2177
|
+
if (thread_context) thread_context_collector_on_gvl_waiting(thread_context);
|
|
2178
|
+
|
|
2179
|
+
debug_leave_unsafe_context();
|
|
2180
|
+
|
|
2181
|
+
return Qnil;
|
|
2182
|
+
}
|
|
2183
|
+
|
|
2184
|
+
static VALUE _native_on_gvl_released(DDTRACE_UNUSED VALUE self, VALUE thread) {
|
|
2185
|
+
ENFORCE_THREAD(thread);
|
|
2186
|
+
|
|
2187
|
+
debug_enter_unsafe_context();
|
|
2188
|
+
|
|
2189
|
+
per_thread_context *thread_context = get_per_thread_context(thread);
|
|
2190
|
+
if (thread_context) thread_context_collector_on_gvl_released(thread_context);
|
|
2017
2191
|
|
|
2192
|
+
debug_leave_unsafe_context();
|
|
2193
|
+
|
|
2194
|
+
return Qnil;
|
|
2195
|
+
}
|
|
2196
|
+
|
|
2197
|
+
#ifndef NO_GVL_INSTRUMENTATION
|
|
2018
2198
|
// This function runs on the passed thread and has the GVL because it gets called just after the Ruby thread acquired the GVL
|
|
2019
2199
|
__attribute__((warn_unused_result))
|
|
2020
2200
|
on_gvl_running_result thread_context_collector_on_gvl_running(VALUE self_instance, VALUE thread, per_thread_context *thread_context) {
|
|
@@ -2103,7 +2283,7 @@ void thread_context_collector_stats_reset_not_thread_safe(VALUE self_instance) {
|
|
|
2103
2283
|
thread_context_collector_state *state;
|
|
2104
2284
|
TypedData_Get_Struct(self_instance, thread_context_collector_state, &thread_context_collector_typed_data, state);
|
|
2105
2285
|
|
|
2106
|
-
per_thread_context *thread_context = get_or_create_context_for(current_thread
|
|
2286
|
+
per_thread_context *thread_context = get_or_create_context_for(current_thread);
|
|
2107
2287
|
|
|
2108
2288
|
long gvl_waiting_at = thread_context->gvl_waiting_at;
|
|
2109
2289
|
|
|
@@ -2126,7 +2306,6 @@ void thread_context_collector_stats_reset_not_thread_safe(VALUE self_instance) {
|
|
|
2126
2306
|
state,
|
|
2127
2307
|
current_thread,
|
|
2128
2308
|
thread_context,
|
|
2129
|
-
&thread_context->sampling_buffer,
|
|
2130
2309
|
cpu_time_for_thread,
|
|
2131
2310
|
current_monotonic_wall_time_ns,
|
|
2132
2311
|
false);
|
|
@@ -2141,7 +2320,6 @@ void thread_context_collector_stats_reset_not_thread_safe(VALUE self_instance) {
|
|
|
2141
2320
|
thread_context_collector_state *state,
|
|
2142
2321
|
VALUE thread_being_sampled,
|
|
2143
2322
|
per_thread_context *thread_context,
|
|
2144
|
-
sampling_buffer* sampling_buffer,
|
|
2145
2323
|
long current_cpu_time_ns
|
|
2146
2324
|
) {
|
|
2147
2325
|
long gvl_waiting_at = thread_context->gvl_waiting_at;
|
|
@@ -2200,26 +2378,16 @@ void thread_context_collector_stats_reset_not_thread_safe(VALUE self_instance) {
|
|
|
2200
2378
|
long gvl_waiting_started_wall_time_ns = labs(gvl_waiting_at);
|
|
2201
2379
|
|
|
2202
2380
|
if (thread_context->wall_time_at_previous_sample_ns < gvl_waiting_started_wall_time_ns) { // situation 1 above
|
|
2203
|
-
long cpu_time_elapsed_ns =
|
|
2204
|
-
&thread_context->cpu_time_at_previous_sample_ns,
|
|
2205
|
-
current_cpu_time_ns,
|
|
2206
|
-
thread_context->gc_tracking.cpu_time_at_start_ns,
|
|
2207
|
-
IS_CPU_TIME
|
|
2208
|
-
);
|
|
2381
|
+
long cpu_time_elapsed_ns = update_cpu_time_since_previous_sample(thread_context, current_cpu_time_ns);
|
|
2209
2382
|
|
|
2210
|
-
long duration_until_start_of_gvl_waiting_ns =
|
|
2211
|
-
|
|
2212
|
-
gvl_waiting_started_wall_time_ns,
|
|
2213
|
-
INVALID_TIME,
|
|
2214
|
-
IS_WALL_TIME
|
|
2215
|
-
);
|
|
2383
|
+
long duration_until_start_of_gvl_waiting_ns =
|
|
2384
|
+
update_wall_time_since_previous_sample(thread_context, gvl_waiting_started_wall_time_ns);
|
|
2216
2385
|
|
|
2217
2386
|
// Push extra sample
|
|
2218
2387
|
trigger_sample_for_thread(
|
|
2219
2388
|
state,
|
|
2220
2389
|
thread_being_sampled,
|
|
2221
2390
|
thread_context,
|
|
2222
|
-
sampling_buffer,
|
|
2223
2391
|
(sample_values) {.cpu_time_ns = cpu_time_elapsed_ns, .cpu_or_wall_samples = 1, .wall_time_ns = duration_until_start_of_gvl_waiting_ns},
|
|
2224
2392
|
gvl_waiting_started_wall_time_ns,
|
|
2225
2393
|
NULL,
|
|
@@ -2232,19 +2400,6 @@ void thread_context_collector_stats_reset_not_thread_safe(VALUE self_instance) {
|
|
|
2232
2400
|
return true;
|
|
2233
2401
|
}
|
|
2234
2402
|
|
|
2235
|
-
static VALUE _native_on_gvl_waiting(DDTRACE_UNUSED VALUE self, VALUE thread) {
|
|
2236
|
-
ENFORCE_THREAD(thread);
|
|
2237
|
-
|
|
2238
|
-
debug_enter_unsafe_context();
|
|
2239
|
-
|
|
2240
|
-
per_thread_context *thread_context = get_per_thread_context(thread);
|
|
2241
|
-
if (thread_context) thread_context_collector_on_gvl_waiting(thread_context);
|
|
2242
|
-
|
|
2243
|
-
debug_leave_unsafe_context();
|
|
2244
|
-
|
|
2245
|
-
return Qnil;
|
|
2246
|
-
}
|
|
2247
|
-
|
|
2248
2403
|
static VALUE _native_gvl_waiting_at_for(DDTRACE_UNUSED VALUE self, VALUE thread) {
|
|
2249
2404
|
ENFORCE_THREAD(thread);
|
|
2250
2405
|
|
|
@@ -2276,19 +2431,6 @@ void thread_context_collector_stats_reset_not_thread_safe(VALUE self_instance) {
|
|
|
2276
2431
|
return result;
|
|
2277
2432
|
}
|
|
2278
2433
|
|
|
2279
|
-
static VALUE _native_on_gvl_released(DDTRACE_UNUSED VALUE self, VALUE thread) {
|
|
2280
|
-
ENFORCE_THREAD(thread);
|
|
2281
|
-
|
|
2282
|
-
debug_enter_unsafe_context();
|
|
2283
|
-
|
|
2284
|
-
per_thread_context *thread_context = get_per_thread_context(thread);
|
|
2285
|
-
if (thread_context) thread_context_collector_on_gvl_released(thread_context);
|
|
2286
|
-
|
|
2287
|
-
debug_leave_unsafe_context();
|
|
2288
|
-
|
|
2289
|
-
return Qnil;
|
|
2290
|
-
}
|
|
2291
|
-
|
|
2292
2434
|
static VALUE _native_sample_after_gvl_running(DDTRACE_UNUSED VALUE self, VALUE collector_instance, VALUE thread, VALUE allow_exception) {
|
|
2293
2435
|
ENFORCE_THREAD(thread);
|
|
2294
2436
|
ENFORCE_BOOLEAN(allow_exception);
|
|
@@ -2306,29 +2448,27 @@ void thread_context_collector_stats_reset_not_thread_safe(VALUE self_instance) {
|
|
|
2306
2448
|
return result;
|
|
2307
2449
|
}
|
|
2308
2450
|
|
|
2309
|
-
static VALUE _native_apply_delta_to_cpu_time_at_previous_sample_ns(DDTRACE_UNUSED VALUE self, VALUE thread, VALUE delta_ns) {
|
|
2310
|
-
ENFORCE_THREAD(thread);
|
|
2311
|
-
|
|
2312
|
-
per_thread_context *thread_context = get_per_thread_context(thread);
|
|
2313
|
-
if (thread_context == NULL) raise_error(rb_eArgError, "Unexpected: This method cannot be used unless the per-thread context for the thread already exists");
|
|
2314
|
-
|
|
2315
|
-
thread_context->cpu_time_at_previous_sample_ns += NUM2LONG(delta_ns);
|
|
2316
|
-
|
|
2317
|
-
return Qtrue;
|
|
2318
|
-
}
|
|
2319
|
-
|
|
2320
2451
|
#else
|
|
2321
2452
|
static bool handle_gvl_waiting(
|
|
2322
2453
|
DDTRACE_UNUSED thread_context_collector_state *state,
|
|
2323
2454
|
DDTRACE_UNUSED VALUE thread_being_sampled,
|
|
2324
2455
|
DDTRACE_UNUSED per_thread_context *thread_context,
|
|
2325
|
-
DDTRACE_UNUSED sampling_buffer* sampling_buffer,
|
|
2326
2456
|
DDTRACE_UNUSED long current_cpu_time_ns
|
|
2327
2457
|
) { return false; }
|
|
2328
2458
|
|
|
2329
|
-
void thread_context_collector_on_serialize(DDTRACE_UNUSED VALUE self_instance) { }
|
|
2330
2459
|
#endif // NO_GVL_INSTRUMENTATION
|
|
2331
2460
|
|
|
2461
|
+
static VALUE _native_apply_delta_to_cpu_time_at_previous_sample_ns(DDTRACE_UNUSED VALUE self, VALUE thread, VALUE delta_ns) {
|
|
2462
|
+
ENFORCE_THREAD(thread);
|
|
2463
|
+
|
|
2464
|
+
per_thread_context *thread_context = get_per_thread_context(thread);
|
|
2465
|
+
if (thread_context == NULL) raise_error(rb_eArgError, "Unexpected: This method cannot be used unless the per-thread context for the thread already exists");
|
|
2466
|
+
|
|
2467
|
+
thread_context->cpu_time_at_previous_sample_ns += NUM2LONG(delta_ns);
|
|
2468
|
+
|
|
2469
|
+
return Qtrue;
|
|
2470
|
+
}
|
|
2471
|
+
|
|
2332
2472
|
#define MAX_SAFE_LOOKUP_SIZE 16
|
|
2333
2473
|
|
|
2334
2474
|
typedef struct { VALUE lookup_key; VALUE result; } safe_lookup_hash_state;
|