datadog 2.8.0 → 2.39.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 +1009 -1
- data/README.md +0 -1
- data/bin/ddprofrb +4 -4
- data/ext/LIBDATADOG_DEVELOPMENT.md +3 -0
- data/ext/datadog_profiling_native_extension/clock_id.h +11 -3
- data/ext/datadog_profiling_native_extension/clock_id_from_mach.c +66 -0
- data/ext/datadog_profiling_native_extension/clock_id_from_pthread.c +3 -2
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +500 -188
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +5 -5
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h +1 -1
- data/ext/datadog_profiling_native_extension/collectors_gc_profiling_helper.c +3 -2
- data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +34 -20
- data/ext/datadog_profiling_native_extension/collectors_stack.c +319 -101
- data/ext/datadog_profiling_native_extension/collectors_stack.h +27 -5
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +985 -504
- data/ext/datadog_profiling_native_extension/collectors_thread_context.h +19 -5
- data/ext/datadog_profiling_native_extension/crashtracking_runtime_stacks.c +239 -0
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +66 -5
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +50 -1
- data/ext/datadog_profiling_native_extension/encoded_profile.c +80 -0
- data/ext/datadog_profiling_native_extension/encoded_profile.h +8 -0
- data/ext/datadog_profiling_native_extension/extconf.rb +53 -35
- data/ext/datadog_profiling_native_extension/gvl_profiling_helper.c +6 -43
- data/ext/datadog_profiling_native_extension/gvl_profiling_helper.h +15 -55
- data/ext/datadog_profiling_native_extension/heap_recorder.c +487 -497
- data/ext/datadog_profiling_native_extension/heap_recorder.h +17 -8
- data/ext/datadog_profiling_native_extension/http_transport.c +108 -144
- data/ext/datadog_profiling_native_extension/libdatadog_helpers.c +18 -15
- data/ext/datadog_profiling_native_extension/libdatadog_helpers.h +8 -10
- data/ext/datadog_profiling_native_extension/macos_sampler_thread.h +55 -0
- data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +0 -13
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +136 -60
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +22 -5
- data/ext/datadog_profiling_native_extension/profiling.c +84 -27
- data/ext/datadog_profiling_native_extension/ruby_helpers.c +67 -62
- data/ext/datadog_profiling_native_extension/ruby_helpers.h +20 -16
- data/ext/datadog_profiling_native_extension/setup_signal_handler.c +34 -10
- data/ext/datadog_profiling_native_extension/setup_signal_handler.h +2 -1
- data/ext/datadog_profiling_native_extension/stack_recorder.c +326 -217
- data/ext/datadog_profiling_native_extension/stack_recorder.h +4 -2
- data/ext/datadog_profiling_native_extension/time_helpers.h +14 -8
- data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.c +48 -0
- data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.h +36 -0
- data/ext/libdatadog_api/crashtracker.c +27 -24
- data/ext/libdatadog_api/crashtracker.h +5 -0
- data/ext/libdatadog_api/crashtracker_report_exception.c +126 -0
- data/ext/libdatadog_api/datadog_ruby_common.c +66 -5
- data/ext/libdatadog_api/datadog_ruby_common.h +50 -1
- data/ext/libdatadog_api/ddsketch.c +102 -0
- data/ext/libdatadog_api/di.c +203 -0
- data/ext/libdatadog_api/extconf.rb +41 -45
- data/ext/libdatadog_api/feature_flags.c +580 -0
- data/ext/libdatadog_api/feature_flags.h +5 -0
- data/ext/libdatadog_api/helpers.h +27 -0
- data/ext/libdatadog_api/init.c +27 -0
- data/ext/libdatadog_api/library_config.c +173 -0
- data/ext/libdatadog_api/library_config.h +25 -0
- data/ext/libdatadog_api/process_discovery.c +118 -0
- data/ext/libdatadog_api/process_discovery.h +5 -0
- data/ext/libdatadog_extconf_helpers.rb +111 -18
- data/lib/datadog/ai_guard/api_client.rb +84 -0
- data/lib/datadog/ai_guard/autoload.rb +10 -0
- data/lib/datadog/ai_guard/component.rb +44 -0
- data/lib/datadog/ai_guard/configuration/ext.rb +17 -0
- data/lib/datadog/ai_guard/configuration.rb +115 -0
- data/lib/datadog/ai_guard/contrib/auto_instrument.rb +24 -0
- data/lib/datadog/ai_guard/contrib/integration.rb +37 -0
- data/lib/datadog/ai_guard/contrib/rack/integration.rb +42 -0
- data/lib/datadog/ai_guard/contrib/rack/patcher.rb +26 -0
- data/lib/datadog/ai_guard/contrib/rack/request_middleware.rb +97 -0
- data/lib/datadog/ai_guard/contrib/rails/integration.rb +41 -0
- data/lib/datadog/ai_guard/contrib/rails/patcher.rb +97 -0
- data/lib/datadog/ai_guard/contrib/ruby_llm/chat_instrumentation.rb +80 -0
- data/lib/datadog/ai_guard/contrib/ruby_llm/integration.rb +41 -0
- data/lib/datadog/ai_guard/contrib/ruby_llm/patcher.rb +30 -0
- data/lib/datadog/ai_guard/evaluation/content_builder.rb +31 -0
- data/lib/datadog/ai_guard/evaluation/content_part.rb +36 -0
- data/lib/datadog/ai_guard/evaluation/message.rb +25 -0
- data/lib/datadog/ai_guard/evaluation/no_op_result.rb +36 -0
- data/lib/datadog/ai_guard/evaluation/request.rb +86 -0
- data/lib/datadog/ai_guard/evaluation/result.rb +45 -0
- data/lib/datadog/ai_guard/evaluation/tool_call.rb +18 -0
- data/lib/datadog/ai_guard/evaluation.rb +108 -0
- data/lib/datadog/ai_guard/ext.rb +29 -0
- data/lib/datadog/ai_guard.rb +181 -0
- data/lib/datadog/appsec/actions_handler/serializable_backtrace.rb +89 -0
- data/lib/datadog/appsec/actions_handler.rb +49 -0
- data/lib/datadog/appsec/anonymizer.rb +16 -0
- data/lib/datadog/appsec/api_security/endpoint_collection/grape_route_serializer.rb +26 -0
- data/lib/datadog/appsec/api_security/endpoint_collection/rails_collector.rb +66 -0
- data/lib/datadog/appsec/api_security/endpoint_collection/rails_route_serializer.rb +36 -0
- data/lib/datadog/appsec/api_security/endpoint_collection/sinatra_route_serializer.rb +26 -0
- data/lib/datadog/appsec/api_security/endpoint_collection.rb +10 -0
- data/lib/datadog/appsec/api_security/route_extractor.rb +104 -0
- data/lib/datadog/appsec/api_security/sampler.rb +62 -0
- data/lib/datadog/appsec/api_security.rb +23 -0
- data/lib/datadog/appsec/assets/blocked.html +10 -1
- data/lib/datadog/appsec/assets/blocked.json +1 -1
- data/lib/datadog/appsec/assets/blocked.text +3 -1
- data/lib/datadog/appsec/assets/waf_rules/README.md +44 -5
- data/lib/datadog/appsec/assets/waf_rules/recommended.json +954 -229
- data/lib/datadog/appsec/assets/waf_rules/strict.json +109 -106
- data/lib/datadog/appsec/assets.rb +8 -8
- data/lib/datadog/appsec/autoload.rb +5 -5
- data/lib/datadog/appsec/component.rb +56 -68
- data/lib/datadog/appsec/compressed_json.rb +40 -0
- data/lib/datadog/appsec/configuration.rb +427 -1
- data/lib/datadog/appsec/context.rb +135 -0
- data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +45 -24
- data/lib/datadog/appsec/contrib/active_record/integration.rb +6 -6
- data/lib/datadog/appsec/contrib/active_record/patcher.rb +67 -16
- data/lib/datadog/appsec/contrib/auto_instrument.rb +1 -1
- data/lib/datadog/appsec/contrib/aws_lambda/gateway/watcher.rb +75 -0
- data/lib/datadog/appsec/contrib/aws_lambda/integration.rb +39 -0
- data/lib/datadog/appsec/contrib/aws_lambda/patcher.rb +30 -0
- data/lib/datadog/appsec/contrib/aws_lambda/waf_addresses.rb +146 -0
- data/lib/datadog/appsec/contrib/devise/configuration.rb +52 -0
- data/lib/datadog/appsec/contrib/devise/data_extractor.rb +78 -0
- data/lib/datadog/appsec/contrib/devise/ext.rb +22 -0
- data/lib/datadog/appsec/contrib/devise/integration.rb +5 -6
- data/lib/datadog/appsec/contrib/devise/patcher.rb +33 -25
- data/lib/datadog/appsec/contrib/devise/patches/signin_tracking_patch.rb +104 -0
- data/lib/datadog/appsec/contrib/devise/patches/signup_tracking_patch.rb +70 -0
- data/lib/datadog/appsec/contrib/devise/{patcher/rememberable_patch.rb → patches/skip_signin_tracking_patch.rb} +3 -3
- data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +121 -0
- data/lib/datadog/appsec/contrib/excon/integration.rb +41 -0
- data/lib/datadog/appsec/contrib/excon/patcher.rb +30 -0
- data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +181 -0
- data/lib/datadog/appsec/contrib/faraday/connection_patch.rb +22 -0
- data/lib/datadog/appsec/contrib/faraday/integration.rb +42 -0
- data/lib/datadog/appsec/contrib/faraday/patcher.rb +53 -0
- data/lib/datadog/appsec/contrib/faraday/rack_builder_patch.rb +22 -0
- data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +166 -0
- data/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +4 -10
- data/lib/datadog/appsec/contrib/graphql/gateway/multiplex.rb +76 -26
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +22 -33
- data/lib/datadog/appsec/contrib/graphql/integration.rb +10 -9
- data/lib/datadog/appsec/contrib/graphql/patcher.rb +3 -6
- data/lib/datadog/appsec/contrib/rack/buffered_input.rb +83 -0
- data/lib/datadog/appsec/contrib/rack/ext.rb +34 -0
- data/lib/datadog/appsec/contrib/rack/gateway/request.rb +56 -21
- data/lib/datadog/appsec/contrib/rack/gateway/response.rb +4 -4
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +101 -100
- data/lib/datadog/appsec/contrib/rack/input_peeker.rb +79 -0
- data/lib/datadog/appsec/contrib/rack/integration.rb +7 -7
- data/lib/datadog/appsec/contrib/rack/patcher.rb +2 -5
- data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +13 -14
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +117 -115
- data/lib/datadog/appsec/contrib/rack/response_body.rb +36 -0
- data/lib/datadog/appsec/contrib/rails/gateway/request.rb +43 -4
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +58 -33
- data/lib/datadog/appsec/contrib/rails/integration.rb +6 -6
- data/lib/datadog/appsec/contrib/rails/patcher.rb +82 -69
- data/lib/datadog/appsec/contrib/rails/patches/process_action_patch.rb +29 -0
- data/lib/datadog/appsec/contrib/rails/patches/render_to_body_patch.rb +33 -0
- data/lib/datadog/appsec/contrib/rails/request.rb +3 -3
- data/lib/datadog/appsec/contrib/rest_client/integration.rb +45 -0
- data/lib/datadog/appsec/contrib/rest_client/patcher.rb +30 -0
- data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +193 -0
- 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 +83 -67
- data/lib/datadog/appsec/contrib/sinatra/integration.rb +6 -6
- data/lib/datadog/appsec/contrib/sinatra/patcher.rb +25 -61
- data/lib/datadog/appsec/contrib/sinatra/patches/json_patch.rb +31 -0
- data/lib/datadog/appsec/counter_sampler.rb +25 -0
- data/lib/datadog/appsec/default_header_tags.rb +52 -0
- data/lib/datadog/appsec/event.rb +80 -152
- data/lib/datadog/appsec/ext.rb +16 -4
- data/lib/datadog/appsec/extensions.rb +2 -2
- data/lib/datadog/appsec/instrumentation/gateway/argument.rb +23 -2
- data/lib/datadog/appsec/instrumentation/gateway/middleware.rb +23 -0
- data/lib/datadog/appsec/instrumentation/gateway.rb +6 -24
- data/lib/datadog/appsec/metrics/collector.rb +80 -0
- data/lib/datadog/appsec/metrics/exporter.rb +48 -0
- data/lib/datadog/appsec/metrics/telemetry.rb +40 -0
- data/lib/datadog/appsec/metrics/telemetry_exporter.rb +47 -0
- data/lib/datadog/appsec/metrics.rb +14 -0
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +60 -34
- data/lib/datadog/appsec/monitor.rb +1 -1
- data/lib/datadog/appsec/processor/rule_loader.rb +48 -54
- data/lib/datadog/appsec/rate_limiter.rb +1 -1
- data/lib/datadog/appsec/remote.rb +59 -68
- data/lib/datadog/appsec/response.rb +42 -90
- 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 +197 -0
- data/lib/datadog/appsec/security_engine/result.rb +103 -0
- data/lib/datadog/appsec/security_engine/runner.rb +111 -0
- data/lib/datadog/appsec/security_engine.rb +9 -0
- data/lib/datadog/appsec/security_event.rb +37 -0
- data/lib/datadog/appsec/thread_safe_ref.rb +61 -0
- data/lib/datadog/appsec/trace_keeper.rb +36 -0
- data/lib/datadog/appsec/utils/hash_coercion.rb +23 -0
- data/lib/datadog/appsec/utils/http/body.rb +41 -0
- data/lib/datadog/appsec/utils/http/body_reader.rb +61 -0
- data/lib/datadog/appsec/utils/http/media_range.rb +17 -16
- data/lib/datadog/appsec/utils/http/media_type.rb +33 -27
- data/lib/datadog/appsec/utils/http/url_encoded.rb +107 -0
- data/lib/datadog/appsec/utils.rb +0 -2
- data/lib/datadog/appsec.rb +35 -30
- data/lib/datadog/auto_instrument.rb +5 -2
- data/lib/datadog/auto_instrument_base.rb +2 -1
- data/lib/datadog/core/buffer/cruby.rb +1 -1
- data/lib/datadog/core/buffer/random.rb +18 -2
- data/lib/datadog/core/buffer/thread_safe.rb +1 -1
- data/lib/datadog/core/configuration/agent_settings.rb +52 -0
- data/lib/datadog/core/configuration/agent_settings_resolver.rb +22 -36
- data/lib/datadog/core/configuration/agentless_settings_resolver.rb +176 -0
- data/lib/datadog/core/configuration/base.rb +19 -7
- data/lib/datadog/core/configuration/components.rb +261 -57
- data/lib/datadog/core/configuration/components_state.rb +28 -0
- data/lib/datadog/core/configuration/config_helper.rb +109 -0
- data/lib/datadog/core/configuration/deprecations.rb +36 -0
- data/lib/datadog/core/configuration/ext.rb +15 -12
- data/lib/datadog/core/configuration/option.rb +150 -84
- data/lib/datadog/core/configuration/option_definition.rb +50 -29
- data/lib/datadog/core/configuration/options.rb +58 -19
- data/lib/datadog/core/configuration/settings.rb +287 -103
- data/lib/datadog/core/configuration/stable_config.rb +32 -0
- data/lib/datadog/core/configuration/supported_configurations.rb +415 -0
- data/lib/datadog/core/configuration.rb +47 -23
- data/lib/datadog/core/contrib/rails/railtie.rb +32 -0
- data/lib/datadog/core/contrib/rails/utils.rb +28 -0
- data/lib/datadog/core/crashtracking/component.rb +81 -38
- data/lib/datadog/core/crashtracking/tag_builder.rb +11 -23
- data/lib/datadog/core/ddsketch.rb +19 -0
- data/lib/datadog/core/deprecations.rb +3 -3
- data/lib/datadog/core/diagnostics/environment_logger.rb +10 -8
- data/lib/datadog/core/diagnostics/health.rb +2 -2
- data/lib/datadog/core/encoding.rb +21 -5
- data/lib/datadog/core/environment/agent_info.rb +142 -0
- data/lib/datadog/core/environment/cgroup.rb +53 -28
- data/lib/datadog/core/environment/container.rb +143 -51
- data/lib/datadog/core/environment/execution.rb +3 -3
- data/lib/datadog/core/environment/ext.rb +32 -21
- data/lib/datadog/core/environment/git.rb +5 -4
- data/lib/datadog/core/environment/identity.rb +50 -14
- data/lib/datadog/core/environment/platform.rb +8 -8
- data/lib/datadog/core/environment/process.rb +122 -0
- data/lib/datadog/core/environment/socket.rb +15 -2
- data/lib/datadog/core/environment/variable_helpers.rb +4 -4
- data/lib/datadog/core/environment/yjit.rb +2 -1
- data/lib/datadog/core/error.rb +15 -13
- data/lib/datadog/core/evp.rb +11 -0
- data/lib/datadog/core/extensions.rb +1 -1
- data/lib/datadog/core/feature_flags.rb +61 -0
- data/lib/datadog/core/git/ext.rb +4 -4
- data/lib/datadog/core/knuth_sampler.rb +59 -0
- data/lib/datadog/core/logger.rb +5 -5
- data/lib/datadog/core/logging/ext.rb +1 -1
- data/lib/datadog/core/metrics/client.rb +49 -49
- data/lib/datadog/core/metrics/ext.rb +5 -5
- data/lib/datadog/core/metrics/logging.rb +8 -8
- data/lib/datadog/core/metrics/options.rb +3 -3
- data/lib/datadog/core/pin.rb +9 -9
- data/lib/datadog/core/process_discovery/tracer_memfd.rb +13 -0
- data/lib/datadog/core/process_discovery.rb +62 -0
- data/lib/datadog/core/rate_limiter.rb +16 -4
- data/lib/datadog/core/remote/client/capabilities.rb +72 -13
- data/lib/datadog/core/remote/client.rb +68 -51
- data/lib/datadog/core/remote/component.rb +90 -55
- data/lib/datadog/core/remote/configuration/content.rb +17 -4
- data/lib/datadog/core/remote/configuration/digest.rb +22 -15
- data/lib/datadog/core/remote/configuration/path.rb +9 -9
- data/lib/datadog/core/remote/configuration/repository.rb +17 -4
- data/lib/datadog/core/remote/configuration/target.rb +15 -8
- 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 +10 -10
- data/lib/datadog/core/remote/tie/tracing.rb +7 -7
- data/lib/datadog/core/remote/transport/config.rb +11 -37
- data/lib/datadog/core/remote/transport/http/config.rb +39 -107
- data/lib/datadog/core/remote/transport/http/negotiation.rb +19 -92
- data/lib/datadog/core/remote/transport/http.rb +33 -111
- data/lib/datadog/core/remote/transport/negotiation.rb +9 -21
- data/lib/datadog/core/remote/worker.rb +33 -42
- data/lib/datadog/core/runtime/ext.rb +22 -23
- data/lib/datadog/core/runtime/metrics.rb +30 -14
- data/lib/datadog/core/semaphore.rb +1 -4
- data/lib/datadog/core/tag_builder.rb +52 -0
- data/lib/datadog/core/tag_normalizer.rb +84 -0
- data/lib/datadog/core/telemetry/component.rb +142 -65
- data/lib/datadog/core/telemetry/emitter.rb +26 -14
- data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +65 -0
- data/lib/datadog/core/telemetry/event/app_closing.rb +18 -0
- data/lib/datadog/core/telemetry/event/app_dependencies_loaded.rb +33 -0
- data/lib/datadog/core/telemetry/event/app_endpoints_loaded.rb +30 -0
- data/lib/datadog/core/telemetry/event/app_extended_heartbeat.rb +32 -0
- data/lib/datadog/core/telemetry/event/app_heartbeat.rb +18 -0
- data/lib/datadog/core/telemetry/event/app_integrations_change.rb +58 -0
- data/lib/datadog/core/telemetry/event/app_started.rb +293 -0
- data/lib/datadog/core/telemetry/event/base.rb +40 -0
- data/lib/datadog/core/telemetry/event/distributions.rb +18 -0
- data/lib/datadog/core/telemetry/event/generate_metrics.rb +43 -0
- data/lib/datadog/core/telemetry/event/log.rb +76 -0
- data/lib/datadog/core/telemetry/event/message_batch.rb +42 -0
- data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +66 -0
- data/lib/datadog/core/telemetry/event.rb +21 -392
- data/lib/datadog/core/telemetry/ext.rb +11 -10
- data/lib/datadog/core/telemetry/http/adapters/net.rb +12 -97
- data/lib/datadog/core/telemetry/logger.rb +6 -3
- data/lib/datadog/core/telemetry/logging.rb +27 -9
- data/lib/datadog/core/telemetry/metric.rb +35 -13
- data/lib/datadog/core/telemetry/metrics_collection.rb +2 -2
- data/lib/datadog/core/telemetry/metrics_manager.rb +10 -1
- data/lib/datadog/core/telemetry/request.rb +21 -9
- data/lib/datadog/core/telemetry/transport/http/telemetry.rb +66 -0
- data/lib/datadog/core/telemetry/transport/http.rb +68 -0
- data/lib/datadog/core/telemetry/transport/telemetry.rb +42 -0
- data/lib/datadog/core/telemetry/worker.rb +214 -35
- data/lib/datadog/core/transport/ext.rb +14 -11
- data/lib/datadog/core/transport/http/adapters/net.rb +19 -4
- data/lib/datadog/core/transport/http/adapters/test.rb +3 -2
- data/lib/datadog/core/transport/http/adapters/unix_socket.rb +5 -5
- data/lib/datadog/core/transport/http/api/endpoint.rb +10 -5
- data/lib/datadog/{tracing → core}/transport/http/api/instance.rb +5 -5
- data/lib/datadog/core/transport/http/api/map.rb +1 -1
- data/lib/datadog/{tracing → core}/transport/http/builder.rb +62 -36
- data/lib/datadog/core/transport/http/client.rb +80 -0
- data/lib/datadog/core/transport/http/env.rb +8 -0
- data/lib/datadog/core/transport/http/response.rb +5 -1
- data/lib/datadog/core/transport/http.rb +80 -0
- data/lib/datadog/core/transport/parcel.rb +61 -9
- data/lib/datadog/core/transport/response.rb +19 -1
- data/lib/datadog/core/transport/transport.rb +90 -0
- data/lib/datadog/core/utils/at_fork_monkey_patch.rb +9 -9
- data/lib/datadog/core/utils/base64_codec.rb +23 -0
- data/lib/datadog/core/utils/duration.rb +33 -33
- data/lib/datadog/core/utils/enumerable_compat.rb +29 -0
- data/lib/datadog/core/utils/fnv.rb +26 -0
- data/lib/datadog/core/utils/forking.rb +5 -3
- data/lib/datadog/core/utils/hash.rb +0 -23
- data/lib/datadog/core/utils/lru_cache.rb +45 -0
- data/lib/datadog/core/utils/network.rb +34 -13
- data/lib/datadog/core/utils/only_once.rb +1 -1
- data/lib/datadog/core/utils/only_once_successful.rb +25 -8
- data/lib/datadog/core/utils/safe_dup.rb +4 -3
- data/lib/datadog/core/utils/sequence.rb +2 -0
- data/lib/datadog/core/utils/spawn_monkey_patch.rb +68 -0
- data/lib/datadog/core/utils/time.rb +26 -2
- data/lib/datadog/core/utils/truncation.rb +21 -0
- data/lib/datadog/core/utils/url.rb +1 -1
- data/lib/datadog/core/utils.rb +14 -5
- data/lib/datadog/core/vendor/multipart-post/multipart/post/composite_read_io.rb +1 -1
- data/lib/datadog/core/vendor/multipart-post/multipart/post/multipartable.rb +8 -8
- data/lib/datadog/core/vendor/multipart-post/multipart/post/parts.rb +7 -7
- data/lib/datadog/core/worker.rb +1 -1
- data/lib/datadog/core/workers/async.rb +40 -14
- data/lib/datadog/core/workers/interval_loop.rb +63 -4
- data/lib/datadog/core/workers/polling.rb +4 -2
- data/lib/datadog/core/workers/queue.rb +96 -1
- data/lib/datadog/core/workers/runtime_metrics.rb +14 -6
- data/lib/datadog/core.rb +20 -3
- data/lib/datadog/data_streams/configuration.rb +50 -0
- data/lib/datadog/data_streams/ext.rb +11 -0
- data/lib/datadog/data_streams/extensions.rb +16 -0
- data/lib/datadog/data_streams/pathway_context.rb +169 -0
- data/lib/datadog/data_streams/processor.rb +511 -0
- data/lib/datadog/data_streams/transport/http/stats.rb +58 -0
- data/lib/datadog/data_streams/transport/http.rb +36 -0
- data/lib/datadog/data_streams/transport/stats.rb +39 -0
- data/lib/datadog/data_streams.rb +100 -0
- data/lib/datadog/di/base.rb +123 -0
- data/lib/datadog/di/boot.rb +47 -0
- 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 +224 -12
- data/lib/datadog/di/component.rb +157 -49
- data/lib/datadog/di/configuration.rb +241 -2
- data/lib/datadog/di/context.rb +82 -0
- data/lib/datadog/di/contrib/active_record.rb +34 -5
- data/lib/datadog/di/contrib/railtie.rb +15 -0
- data/lib/datadog/di/contrib.rb +28 -0
- data/lib/datadog/di/el/compiler.rb +168 -0
- data/lib/datadog/di/el/evaluator.rb +159 -0
- data/lib/datadog/di/el/expression.rb +42 -0
- data/lib/datadog/di/el.rb +5 -0
- data/lib/datadog/di/error.rb +49 -0
- data/lib/datadog/di/fatal_exceptions.rb +26 -0
- data/lib/datadog/di/instrumenter.rb +672 -122
- data/lib/datadog/di/logger.rb +30 -0
- data/lib/datadog/di/{init.rb → preload.rb} +2 -4
- data/lib/datadog/di/probe.rb +125 -20
- data/lib/datadog/di/probe_builder.rb +126 -5
- data/lib/datadog/di/probe_file_loader/railtie.rb +15 -0
- data/lib/datadog/di/probe_file_loader.rb +87 -0
- data/lib/datadog/di/probe_manager.rb +198 -100
- data/lib/datadog/di/probe_notification_builder.rb +349 -103
- data/lib/datadog/di/probe_notifier_worker.rb +161 -51
- data/lib/datadog/di/probe_repository.rb +198 -0
- data/lib/datadog/di/proc_responder.rb +36 -0
- data/lib/datadog/di/redactor.rb +24 -3
- data/lib/datadog/di/remote.rb +259 -73
- data/lib/datadog/di/serializer.rb +319 -30
- data/lib/datadog/di/transport/diagnostics.rb +32 -0
- data/lib/datadog/di/transport/http/diagnostics.rb +35 -0
- data/lib/datadog/di/transport/http/input.rb +45 -0
- data/lib/datadog/di/transport/http.rb +81 -0
- data/lib/datadog/di/transport/input.rb +144 -0
- data/lib/datadog/di/utils.rb +133 -9
- data/lib/datadog/di.rb +188 -121
- data/lib/datadog/error_tracking/collector.rb +88 -0
- data/lib/datadog/error_tracking/component.rb +167 -0
- data/lib/datadog/error_tracking/configuration.rb +64 -0
- data/lib/datadog/error_tracking/ext.rb +18 -0
- data/lib/datadog/error_tracking/extensions.rb +16 -0
- data/lib/datadog/error_tracking/filters.rb +77 -0
- data/lib/datadog/error_tracking.rb +18 -0
- data/lib/datadog/kit/appsec/events/v2.rb +253 -0
- data/lib/datadog/kit/appsec/events.rb +39 -26
- data/lib/datadog/kit/enable_core_dumps.rb +3 -3
- data/lib/datadog/kit/identity.rb +34 -24
- data/lib/datadog/kit/tracing/method_tracer.rb +135 -0
- data/lib/datadog/kit.rb +1 -1
- data/lib/datadog/open_feature/component.rb +109 -0
- data/lib/datadog/open_feature/configuration.rb +50 -0
- data/lib/datadog/open_feature/evaluation_engine.rb +70 -0
- data/lib/datadog/open_feature/exposures/batch_builder.rb +32 -0
- data/lib/datadog/open_feature/exposures/buffer.rb +43 -0
- data/lib/datadog/open_feature/exposures/deduplicator.rb +30 -0
- data/lib/datadog/open_feature/exposures/event.rb +60 -0
- data/lib/datadog/open_feature/exposures/reporter.rb +40 -0
- data/lib/datadog/open_feature/exposures/worker.rb +116 -0
- data/lib/datadog/open_feature/ext.rb +21 -0
- 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_metrics_hook.rb +51 -0
- data/lib/datadog/open_feature/hooks/span_enrichment_hook/codec.rb +58 -0
- data/lib/datadog/open_feature/hooks/span_enrichment_hook/span_enrichment_state.rb +96 -0
- data/lib/datadog/open_feature/hooks/span_enrichment_hook/span_enrichment_state_store.rb +49 -0
- data/lib/datadog/open_feature/hooks/span_enrichment_hook.rb +184 -0
- data/lib/datadog/open_feature/metrics/flag_eval_metrics.rb +149 -0
- data/lib/datadog/open_feature/native_evaluator.rb +60 -0
- data/lib/datadog/open_feature/noop_evaluator.rb +26 -0
- data/lib/datadog/open_feature/provider.rb +226 -0
- data/lib/datadog/open_feature/remote.rb +67 -0
- data/lib/datadog/open_feature/resolution_details.rb +37 -0
- data/lib/datadog/open_feature/transport.rb +121 -0
- data/lib/datadog/open_feature.rb +19 -0
- data/lib/datadog/opentelemetry/api/baggage.rb +90 -0
- data/lib/datadog/opentelemetry/api/context.rb +25 -10
- data/lib/datadog/opentelemetry/configuration/settings.rb +226 -0
- data/lib/datadog/opentelemetry/ext.rb +9 -0
- data/lib/datadog/opentelemetry/logs.rb +98 -0
- data/lib/datadog/opentelemetry/metrics.rb +90 -0
- data/lib/datadog/opentelemetry/sdk/configurator.rb +69 -5
- data/lib/datadog/opentelemetry/sdk/id_generator.rb +16 -10
- data/lib/datadog/opentelemetry/sdk/logs_exporter.rb +30 -0
- data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +28 -0
- data/lib/datadog/opentelemetry/sdk/propagator.rb +20 -14
- data/lib/datadog/opentelemetry/sdk/span_processor.rb +24 -21
- data/lib/datadog/opentelemetry/sdk/trace/span.rb +43 -39
- data/lib/datadog/opentelemetry/sdk.rb +19 -0
- data/lib/datadog/opentelemetry/signal_configuration.rb +53 -0
- data/lib/datadog/opentelemetry/trace.rb +5 -5
- data/lib/datadog/opentelemetry.rb +11 -6
- data/lib/datadog/profiling/collectors/code_provenance.rb +84 -16
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +57 -3
- data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +13 -4
- data/lib/datadog/profiling/collectors/info.rb +62 -4
- data/lib/datadog/profiling/collectors/thread_context.rb +27 -7
- data/lib/datadog/profiling/component.rb +125 -88
- data/lib/datadog/profiling/encoded_profile.rb +11 -0
- data/lib/datadog/profiling/exporter.rb +51 -17
- data/lib/datadog/profiling/ext/dir_monkey_patches.rb +24 -5
- data/lib/datadog/profiling/ext/exec_monkey_patch.rb +32 -0
- data/lib/datadog/profiling/ext.rb +2 -17
- data/lib/datadog/profiling/flush.rb +26 -17
- data/lib/datadog/profiling/http_transport.rb +30 -96
- data/lib/datadog/profiling/load_native_extension.rb +3 -35
- data/lib/datadog/profiling/profiler.rb +31 -12
- data/lib/datadog/profiling/scheduler.rb +19 -10
- data/lib/datadog/profiling/sequence_tracker.rb +44 -0
- data/lib/datadog/profiling/stack_recorder.rb +9 -17
- data/lib/datadog/profiling/tag_builder.rb +41 -41
- data/lib/datadog/profiling/tasks/exec.rb +10 -5
- data/lib/datadog/profiling/tasks/help.rb +1 -0
- data/lib/datadog/profiling/tasks/setup.rb +4 -2
- data/lib/datadog/profiling.rb +38 -37
- data/lib/datadog/ruby_version.rb +25 -0
- data/lib/datadog/single_step_instrument.rb +11 -2
- data/lib/datadog/symbol_database/component.rb +734 -0
- data/lib/datadog/symbol_database/configuration.rb +73 -0
- data/lib/datadog/symbol_database/extensions.rb +19 -0
- data/lib/datadog/symbol_database/extractor.rb +1110 -0
- data/lib/datadog/symbol_database/file_hash.rb +48 -0
- data/lib/datadog/symbol_database/logger.rb +43 -0
- data/lib/datadog/symbol_database/remote.rb +195 -0
- data/lib/datadog/symbol_database/scope.rb +102 -0
- data/lib/datadog/symbol_database/scope_batcher.rb +292 -0
- data/lib/datadog/symbol_database/service_version.rb +66 -0
- data/lib/datadog/symbol_database/symbol.rb +69 -0
- data/lib/datadog/symbol_database/transport/http/endpoint.rb +28 -0
- data/lib/datadog/symbol_database/transport/http.rb +45 -0
- data/lib/datadog/symbol_database/transport.rb +54 -0
- data/lib/datadog/symbol_database/uploader.rb +230 -0
- data/lib/datadog/symbol_database.rb +71 -0
- data/lib/datadog/tracing/analytics.rb +2 -2
- data/lib/datadog/tracing/buffer.rb +15 -15
- data/lib/datadog/tracing/client_ip.rb +4 -4
- data/lib/datadog/tracing/component.rb +39 -35
- data/lib/datadog/tracing/configuration/dynamic.rb +14 -16
- data/lib/datadog/tracing/configuration/ext.rb +60 -33
- data/lib/datadog/tracing/configuration/http.rb +2 -2
- data/lib/datadog/tracing/configuration/settings.rb +156 -26
- data/lib/datadog/tracing/context.rb +3 -3
- data/lib/datadog/tracing/context_provider.rb +3 -3
- data/lib/datadog/tracing/contrib/action_cable/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/action_cable/event.rb +5 -5
- data/lib/datadog/tracing/contrib/action_cable/events/broadcast.rb +9 -6
- data/lib/datadog/tracing/contrib/action_cable/events/perform_action.rb +8 -5
- data/lib/datadog/tracing/contrib/action_cable/events/transmit.rb +9 -6
- data/lib/datadog/tracing/contrib/action_cable/events.rb +4 -4
- data/lib/datadog/tracing/contrib/action_cable/ext.rb +18 -18
- data/lib/datadog/tracing/contrib/action_cable/instrumentation.rb +8 -5
- data/lib/datadog/tracing/contrib/action_cable/integration.rb +10 -7
- data/lib/datadog/tracing/contrib/action_cable/patcher.rb +4 -4
- data/lib/datadog/tracing/contrib/action_mailer/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/action_mailer/event.rb +7 -4
- data/lib/datadog/tracing/contrib/action_mailer/events/deliver.rb +8 -8
- data/lib/datadog/tracing/contrib/action_mailer/events/process.rb +4 -4
- data/lib/datadog/tracing/contrib/action_mailer/events.rb +2 -2
- data/lib/datadog/tracing/contrib/action_mailer/ext.rb +18 -18
- data/lib/datadog/tracing/contrib/action_mailer/integration.rb +11 -7
- data/lib/datadog/tracing/contrib/action_mailer/patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +37 -19
- data/lib/datadog/tracing/contrib/action_pack/action_controller/patcher.rb +2 -2
- data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +48 -13
- data/lib/datadog/tracing/contrib/action_pack/action_dispatch/patcher.rb +5 -3
- data/lib/datadog/tracing/contrib/action_pack/configuration/settings.rb +3 -3
- data/lib/datadog/tracing/contrib/action_pack/ext.rb +10 -8
- data/lib/datadog/tracing/contrib/action_pack/integration.rb +10 -7
- data/lib/datadog/tracing/contrib/action_pack/patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/action_pack/utils.rb +2 -3
- data/lib/datadog/tracing/contrib/action_view/configuration/settings.rb +3 -3
- data/lib/datadog/tracing/contrib/action_view/event.rb +1 -1
- data/lib/datadog/tracing/contrib/action_view/events/render_partial.rb +10 -7
- data/lib/datadog/tracing/contrib/action_view/events/render_template.rb +12 -9
- 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 +14 -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 +11 -11
- data/lib/datadog/tracing/contrib/active_job/events/discard.rb +11 -8
- data/lib/datadog/tracing/contrib/active_job/events/enqueue.rb +11 -8
- data/lib/datadog/tracing/contrib/active_job/events/enqueue_at.rb +11 -8
- data/lib/datadog/tracing/contrib/active_job/events/enqueue_retry.rb +11 -8
- data/lib/datadog/tracing/contrib/active_job/events/perform.rb +11 -8
- data/lib/datadog/tracing/contrib/active_job/events/retry_stopped.rb +11 -8
- 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 +10 -7
- data/lib/datadog/tracing/contrib/active_job/log_injection.rb +21 -7
- data/lib/datadog/tracing/contrib/active_job/patcher.rb +21 -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 +8 -8
- data/lib/datadog/tracing/contrib/active_model_serializers/events/serialize.rb +9 -10
- 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 -6
- 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 +8 -8
- 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 +10 -10
- data/lib/datadog/tracing/contrib/active_record/events/sql.rb +16 -19
- 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 +16 -12
- data/lib/datadog/tracing/contrib/active_record/patcher.rb +2 -2
- data/lib/datadog/tracing/contrib/active_record/utils.rb +19 -19
- data/lib/datadog/tracing/contrib/active_support/cache/event.rb +1 -1
- data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +28 -20
- data/lib/datadog/tracing/contrib/active_support/cache/events.rb +1 -1
- data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +40 -8
- data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +8 -4
- data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +5 -7
- data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +26 -3
- data/lib/datadog/tracing/contrib/active_support/ext.rb +16 -16
- data/lib/datadog/tracing/contrib/active_support/integration.rb +11 -8
- data/lib/datadog/tracing/contrib/active_support/notifications/event.rb +3 -2
- data/lib/datadog/tracing/contrib/active_support/notifications/subscriber.rb +2 -2
- data/lib/datadog/tracing/contrib/active_support/notifications/subscription.rb +9 -11
- 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 +5 -5
- data/lib/datadog/tracing/contrib/aws/configuration/settings.rb +3 -3
- data/lib/datadog/tracing/contrib/aws/ext.rb +26 -26
- data/lib/datadog/tracing/contrib/aws/instrumentation.rb +21 -13
- data/lib/datadog/tracing/contrib/aws/integration.rb +11 -8
- data/lib/datadog/tracing/contrib/aws/parsed_context.rb +9 -3
- data/lib/datadog/tracing/contrib/aws/patcher.rb +10 -6
- data/lib/datadog/tracing/contrib/aws/service/base.rb +2 -1
- data/lib/datadog/tracing/contrib/aws/service/dynamodb.rb +2 -2
- data/lib/datadog/tracing/contrib/aws/service/eventbridge.rb +2 -2
- data/lib/datadog/tracing/contrib/aws/service/kinesis.rb +4 -4
- data/lib/datadog/tracing/contrib/aws/service/s3.rb +2 -2
- data/lib/datadog/tracing/contrib/aws/service/sns.rb +3 -3
- data/lib/datadog/tracing/contrib/aws/service/sqs.rb +3 -3
- data/lib/datadog/tracing/contrib/aws/service/states.rb +5 -5
- data/lib/datadog/tracing/contrib/aws/services.rb +14 -14
- data/lib/datadog/tracing/contrib/component.rb +3 -3
- data/lib/datadog/tracing/contrib/concurrent_ruby/async_patch.rb +2 -2
- data/lib/datadog/tracing/contrib/concurrent_ruby/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/concurrent_ruby/context_composite_executor_service.rb +2 -2
- data/lib/datadog/tracing/contrib/concurrent_ruby/ext.rb +2 -2
- data/lib/datadog/tracing/contrib/concurrent_ruby/future_patch.rb +2 -2
- data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +8 -5
- data/lib/datadog/tracing/contrib/concurrent_ruby/patcher.rb +4 -4
- data/lib/datadog/tracing/contrib/concurrent_ruby/promises_future_patch.rb +2 -2
- data/lib/datadog/tracing/contrib/configurable.rb +24 -9
- data/lib/datadog/tracing/contrib/configuration/resolver.rb +14 -4
- data/lib/datadog/tracing/contrib/configuration/resolvers/pattern_resolver.rb +5 -5
- data/lib/datadog/tracing/contrib/configuration/settings.rb +3 -3
- data/lib/datadog/tracing/contrib/dalli/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/dalli/ext.rb +16 -15
- data/lib/datadog/tracing/contrib/dalli/instrumentation.rb +6 -10
- data/lib/datadog/tracing/contrib/dalli/integration.rb +10 -7
- data/lib/datadog/tracing/contrib/dalli/patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/dalli/quantize.rb +3 -3
- data/lib/datadog/tracing/contrib/delayed_job/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/delayed_job/ext.rb +14 -14
- data/lib/datadog/tracing/contrib/delayed_job/integration.rb +5 -5
- data/lib/datadog/tracing/contrib/delayed_job/patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/delayed_job/plugin.rb +7 -5
- data/lib/datadog/tracing/contrib/delayed_job/server_internal_tracer/worker.rb +1 -0
- data/lib/datadog/tracing/contrib/elasticsearch/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/elasticsearch/ext.rb +18 -17
- data/lib/datadog/tracing/contrib/elasticsearch/integration.rb +8 -8
- data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +57 -63
- data/lib/datadog/tracing/contrib/elasticsearch/quantize.rb +8 -8
- data/lib/datadog/tracing/contrib/ethon/configuration/settings.rb +7 -3
- data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +19 -21
- data/lib/datadog/tracing/contrib/ethon/ext.rb +16 -14
- data/lib/datadog/tracing/contrib/ethon/integration.rb +6 -6
- data/lib/datadog/tracing/contrib/ethon/multi_patch.rb +4 -11
- data/lib/datadog/tracing/contrib/ethon/patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/excon/configuration/settings.rb +21 -10
- data/lib/datadog/tracing/contrib/excon/ext.rb +14 -12
- data/lib/datadog/tracing/contrib/excon/integration.rb +6 -6
- data/lib/datadog/tracing/contrib/excon/middleware.rb +17 -19
- data/lib/datadog/tracing/contrib/excon/patcher.rb +2 -2
- data/lib/datadog/tracing/contrib/ext.rb +20 -17
- data/lib/datadog/tracing/contrib/extensions.rb +57 -14
- data/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +20 -13
- data/lib/datadog/tracing/contrib/faraday/ext.rb +14 -12
- data/lib/datadog/tracing/contrib/faraday/integration.rb +6 -6
- data/lib/datadog/tracing/contrib/faraday/middleware.rb +19 -19
- data/lib/datadog/tracing/contrib/faraday/patcher.rb +6 -6
- data/lib/datadog/tracing/contrib/grape/configuration/settings.rb +11 -7
- data/lib/datadog/tracing/contrib/grape/endpoint.rb +37 -34
- data/lib/datadog/tracing/contrib/grape/ext.rb +15 -15
- data/lib/datadog/tracing/contrib/grape/instrumentation.rb +15 -10
- data/lib/datadog/tracing/contrib/grape/integration.rb +5 -5
- data/lib/datadog/tracing/contrib/grape/patcher.rb +10 -5
- data/lib/datadog/tracing/contrib/graphql/configuration/error_extension_env_parser.rb +21 -0
- data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +20 -2
- data/lib/datadog/tracing/contrib/graphql/ext.rb +11 -5
- data/lib/datadog/tracing/contrib/graphql/integration.rb +9 -9
- data/lib/datadog/tracing/contrib/graphql/patcher.rb +8 -8
- data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +174 -41
- data/lib/datadog/tracing/contrib/graphql/unified_trace_patcher.rb +2 -2
- data/lib/datadog/tracing/contrib/grpc/configuration/settings.rb +7 -4
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +25 -23
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +13 -17
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor.rb +6 -6
- data/lib/datadog/tracing/contrib/grpc/distributed/fetcher.rb +2 -2
- data/lib/datadog/tracing/contrib/grpc/distributed/propagation.rb +12 -7
- data/lib/datadog/tracing/contrib/grpc/ext.rb +14 -13
- data/lib/datadog/tracing/contrib/grpc/formatting.rb +7 -7
- data/lib/datadog/tracing/contrib/grpc/integration.rb +5 -5
- data/lib/datadog/tracing/contrib/grpc/intercept_with_datadog.rb +1 -1
- data/lib/datadog/tracing/contrib/grpc/patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/grpc.rb +7 -6
- data/lib/datadog/tracing/contrib/hanami/action_tracer.rb +4 -3
- data/lib/datadog/tracing/contrib/hanami/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/hanami/ext.rb +8 -8
- data/lib/datadog/tracing/contrib/hanami/integration.rb +6 -6
- data/lib/datadog/tracing/contrib/hanami/patcher.rb +5 -5
- data/lib/datadog/tracing/contrib/hanami/renderer_policy_tracing.rb +5 -4
- data/lib/datadog/tracing/contrib/hanami/router_tracing.rb +12 -13
- data/lib/datadog/tracing/contrib/http/circuit_breaker.rb +1 -16
- data/lib/datadog/tracing/contrib/http/configuration/settings.rb +20 -9
- data/lib/datadog/tracing/contrib/http/distributed/fetcher.rb +6 -6
- data/lib/datadog/tracing/contrib/http/distributed/propagation.rb +13 -8
- data/lib/datadog/tracing/contrib/http/ext.rb +14 -12
- data/lib/datadog/tracing/contrib/http/instrumentation.rb +20 -28
- data/lib/datadog/tracing/contrib/http/integration.rb +9 -8
- data/lib/datadog/tracing/contrib/http/patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/http.rb +7 -6
- data/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb +20 -9
- data/lib/datadog/tracing/contrib/httpclient/ext.rb +14 -12
- data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +21 -31
- 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 +20 -9
- data/lib/datadog/tracing/contrib/httprb/ext.rb +14 -12
- data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +20 -32
- data/lib/datadog/tracing/contrib/httprb/integration.rb +9 -6
- 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 +5 -4
- data/lib/datadog/tracing/contrib/kafka/events/connection/request.rb +4 -4
- data/lib/datadog/tracing/contrib/kafka/events/consumer/process_batch.rb +5 -5
- data/lib/datadog/tracing/contrib/kafka/events/consumer/process_message.rb +5 -5
- data/lib/datadog/tracing/contrib/kafka/events/consumer_group/heartbeat.rb +6 -6
- data/lib/datadog/tracing/contrib/kafka/events/consumer_group/join_group.rb +6 -6
- data/lib/datadog/tracing/contrib/kafka/events/consumer_group/leave_group.rb +6 -6
- data/lib/datadog/tracing/contrib/kafka/events/consumer_group/sync_group.rb +6 -6
- data/lib/datadog/tracing/contrib/kafka/events/produce_operation/send_messages.rb +4 -4
- data/lib/datadog/tracing/contrib/kafka/events/producer/deliver_messages.rb +4 -4
- 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 +66 -0
- data/lib/datadog/tracing/contrib/kafka/instrumentation/producer.rb +66 -0
- data/lib/datadog/tracing/contrib/kafka/integration.rb +8 -5
- data/lib/datadog/tracing/contrib/kafka/patcher.rb +17 -3
- data/lib/datadog/tracing/contrib/karafka/configuration/settings.rb +31 -0
- data/lib/datadog/tracing/contrib/karafka/distributed/propagation.rb +50 -0
- data/lib/datadog/tracing/contrib/karafka/ext.rb +28 -0
- data/lib/datadog/tracing/contrib/karafka/framework.rb +30 -0
- data/lib/datadog/tracing/contrib/karafka/integration.rb +45 -0
- data/lib/datadog/tracing/contrib/karafka/monitor.rb +77 -0
- data/lib/datadog/tracing/contrib/karafka/patcher.rb +102 -0
- data/lib/datadog/tracing/contrib/karafka.rb +38 -0
- 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/instrumentation.rb +1 -1
- data/lib/datadog/tracing/contrib/lograge/integration.rb +5 -5
- data/lib/datadog/tracing/contrib/lograge/patcher.rb +13 -11
- data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +11 -3
- data/lib/datadog/tracing/contrib/mongodb/ext.rb +19 -18
- data/lib/datadog/tracing/contrib/mongodb/instrumentation.rb +3 -3
- data/lib/datadog/tracing/contrib/mongodb/integration.rb +9 -6
- data/lib/datadog/tracing/contrib/mongodb/parsers.rb +10 -10
- data/lib/datadog/tracing/contrib/mongodb/patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +38 -24
- data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +9 -3
- data/lib/datadog/tracing/contrib/mysql2/ext.rb +12 -12
- data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +25 -18
- 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 +19 -2
- data/lib/datadog/tracing/contrib/opensearch/ext.rb +31 -21
- data/lib/datadog/tracing/contrib/opensearch/integration.rb +8 -6
- data/lib/datadog/tracing/contrib/opensearch/patcher.rb +75 -77
- data/lib/datadog/tracing/contrib/opensearch/quantize.rb +9 -9
- data/lib/datadog/tracing/contrib/patcher.rb +14 -13
- data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +9 -3
- data/lib/datadog/tracing/contrib/pg/ext.rb +19 -19
- data/lib/datadog/tracing/contrib/pg/instrumentation.rb +21 -24
- 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 +22 -22
- data/lib/datadog/tracing/contrib/presto/instrumentation.rb +11 -13
- data/lib/datadog/tracing/contrib/presto/integration.rb +8 -5
- 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 +26 -13
- data/lib/datadog/tracing/contrib/propagation/sql_comment/mode.rb +7 -3
- data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +29 -5
- data/lib/datadog/tracing/contrib/que/configuration/settings.rb +7 -4
- data/lib/datadog/tracing/contrib/que/ext.rb +19 -18
- data/lib/datadog/tracing/contrib/que/integration.rb +6 -6
- data/lib/datadog/tracing/contrib/que/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/que/tracer.rb +2 -1
- data/lib/datadog/tracing/contrib/racecar/configuration/settings.rb +3 -3
- data/lib/datadog/tracing/contrib/racecar/event.rb +6 -10
- data/lib/datadog/tracing/contrib/racecar/events/batch.rb +5 -5
- data/lib/datadog/tracing/contrib/racecar/events/consume.rb +4 -4
- data/lib/datadog/tracing/contrib/racecar/events/message.rb +5 -5
- 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 +13 -3
- data/lib/datadog/tracing/contrib/rack/ext.rb +43 -15
- data/lib/datadog/tracing/contrib/rack/header_collection.rb +13 -3
- data/lib/datadog/tracing/contrib/rack/header_tagging.rb +55 -32
- data/lib/datadog/tracing/contrib/rack/integration.rb +7 -7
- data/lib/datadog/tracing/contrib/rack/middlewares.rb +102 -63
- data/lib/datadog/tracing/contrib/rack/patcher.rb +5 -5
- data/lib/datadog/tracing/contrib/rack/request_queue.rb +8 -7
- data/lib/datadog/tracing/contrib/rack/route_inference.rb +67 -0
- data/lib/datadog/tracing/contrib/rack/trace_proxy_middleware.rb +130 -6
- data/lib/datadog/tracing/contrib/rails/auto_instrument_railtie.rb +1 -1
- data/lib/datadog/tracing/contrib/rails/configuration/settings.rb +9 -6
- data/lib/datadog/tracing/contrib/rails/ext.rb +16 -14
- data/lib/datadog/tracing/contrib/rails/framework.rb +12 -12
- data/lib/datadog/tracing/contrib/rails/integration.rb +6 -6
- data/lib/datadog/tracing/contrib/rails/log_injection.rb +2 -2
- data/lib/datadog/tracing/contrib/rails/middlewares.rb +4 -4
- data/lib/datadog/tracing/contrib/rails/patcher.rb +11 -9
- data/lib/datadog/tracing/contrib/rails/railtie.rb +4 -4
- data/lib/datadog/tracing/contrib/rails/runner.rb +64 -40
- 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 +13 -11
- 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 +4 -4
- data/lib/datadog/tracing/contrib/redis/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/redis/ext.rb +19 -18
- 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 +12 -12
- data/lib/datadog/tracing/contrib/redis/quantize.rb +6 -6
- data/lib/datadog/tracing/contrib/redis/tags.rb +7 -12
- data/lib/datadog/tracing/contrib/redis/trace_middleware.rb +11 -9
- data/lib/datadog/tracing/contrib/registerable.rb +11 -0
- data/lib/datadog/tracing/contrib/registry.rb +1 -1
- 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 +7 -6
- data/lib/datadog/tracing/contrib/rest_client/configuration/settings.rb +7 -4
- data/lib/datadog/tracing/contrib/rest_client/ext.rb +13 -11
- data/lib/datadog/tracing/contrib/rest_client/integration.rb +8 -5
- data/lib/datadog/tracing/contrib/rest_client/patcher.rb +2 -2
- data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +18 -17
- data/lib/datadog/tracing/contrib/roda/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/roda/ext.rb +6 -5
- data/lib/datadog/tracing/contrib/roda/instrumentation.rb +12 -7
- 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/instrumentation.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 +12 -11
- data/lib/datadog/tracing/contrib/sequel/dataset.rb +7 -6
- 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 -15
- data/lib/datadog/tracing/contrib/shoryuken/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/shoryuken/ext.rb +12 -12
- data/lib/datadog/tracing/contrib/shoryuken/integration.rb +6 -6
- data/lib/datadog/tracing/contrib/shoryuken/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/shoryuken/tracer.rb +3 -2
- data/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +15 -9
- data/lib/datadog/tracing/contrib/sidekiq/configuration/settings.rb +7 -3
- data/lib/datadog/tracing/contrib/sidekiq/distributed/propagation.rb +13 -8
- data/lib/datadog/tracing/contrib/sidekiq/ext.rb +31 -29
- data/lib/datadog/tracing/contrib/sidekiq/integration.rb +7 -7
- data/lib/datadog/tracing/contrib/sidekiq/patcher.rb +8 -8
- data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/heartbeat.rb +2 -0
- data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/job_fetch.rb +1 -0
- data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/redis_info.rb +1 -0
- data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/scheduled_poller.rb +2 -0
- data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/stop.rb +1 -0
- data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +19 -15
- data/lib/datadog/tracing/contrib/sidekiq/utils.rb +10 -10
- data/lib/datadog/tracing/contrib/sidekiq.rb +7 -6
- data/lib/datadog/tracing/contrib/sinatra/configuration/settings.rb +7 -3
- data/lib/datadog/tracing/contrib/sinatra/env.rb +6 -6
- data/lib/datadog/tracing/contrib/sinatra/ext.rb +17 -16
- data/lib/datadog/tracing/contrib/sinatra/framework.rb +2 -2
- data/lib/datadog/tracing/contrib/sinatra/integration.rb +5 -5
- data/lib/datadog/tracing/contrib/sinatra/patcher.rb +5 -5
- data/lib/datadog/tracing/contrib/sinatra/tracer.rb +11 -10
- data/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb +46 -45
- 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 +19 -8
- data/lib/datadog/tracing/contrib/sneakers/patcher.rb +2 -2
- data/lib/datadog/tracing/contrib/sneakers/tracer.rb +4 -3
- data/lib/datadog/tracing/contrib/span_attribute_schema.rb +9 -4
- data/lib/datadog/tracing/contrib/status_range_env_parser.rb +2 -2
- data/lib/datadog/tracing/contrib/status_range_matcher.rb +13 -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 +5 -5
- data/lib/datadog/tracing/contrib/sucker_punch/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/sucker_punch/exception_handler.rb +1 -1
- data/lib/datadog/tracing/contrib/sucker_punch/ext.rb +13 -13
- data/lib/datadog/tracing/contrib/sucker_punch/instrumentation.rb +5 -4
- data/lib/datadog/tracing/contrib/sucker_punch/integration.rb +5 -5
- data/lib/datadog/tracing/contrib/sucker_punch/patcher.rb +4 -4
- data/lib/datadog/tracing/contrib/support.rb +28 -0
- data/lib/datadog/tracing/contrib/trilogy/configuration/settings.rb +9 -3
- data/lib/datadog/tracing/contrib/trilogy/ext.rb +12 -12
- data/lib/datadog/tracing/contrib/trilogy/instrumentation.rb +10 -12
- data/lib/datadog/tracing/contrib/trilogy/integration.rb +5 -5
- data/lib/datadog/tracing/contrib/trilogy/patcher.rb +2 -2
- data/lib/datadog/tracing/contrib/utils/database.rb +5 -5
- data/lib/datadog/tracing/contrib/utils/quantization/{hash.rb → hash_formatter.rb} +16 -14
- data/lib/datadog/tracing/contrib/utils/quantization/http.rb +16 -16
- data/lib/datadog/tracing/contrib/waterdrop/configuration/settings.rb +31 -0
- data/lib/datadog/tracing/contrib/waterdrop/distributed/propagation.rb +50 -0
- data/lib/datadog/tracing/contrib/waterdrop/ext.rb +18 -0
- data/lib/datadog/tracing/contrib/waterdrop/integration.rb +43 -0
- data/lib/datadog/tracing/contrib/waterdrop/middleware.rb +46 -0
- data/lib/datadog/tracing/contrib/waterdrop/patcher.rb +49 -0
- data/lib/datadog/tracing/contrib/waterdrop/producer.rb +50 -0
- data/lib/datadog/tracing/contrib/waterdrop.rb +42 -0
- data/lib/datadog/tracing/contrib.rb +62 -52
- data/lib/datadog/tracing/correlation.rb +19 -12
- data/lib/datadog/tracing/diagnostics/environment_logger.rb +21 -13
- 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 +9 -9
- data/lib/datadog/tracing/distributed/b3_single.rb +6 -6
- data/lib/datadog/tracing/distributed/baggage.rb +252 -0
- data/lib/datadog/tracing/distributed/datadog.rb +39 -36
- data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +12 -27
- data/lib/datadog/tracing/distributed/fetcher.rb +1 -1
- data/lib/datadog/tracing/distributed/helpers.rb +4 -4
- data/lib/datadog/tracing/distributed/none.rb +4 -2
- data/lib/datadog/tracing/distributed/propagation.rb +70 -14
- data/lib/datadog/tracing/distributed/propagation_policy.rb +42 -0
- data/lib/datadog/tracing/distributed/trace_context.rb +126 -97
- data/lib/datadog/tracing/event.rb +6 -8
- data/lib/datadog/tracing/ext.rb +9 -0
- data/lib/datadog/tracing/flush.rb +1 -1
- data/lib/datadog/tracing/metadata/analytics.rb +3 -3
- data/lib/datadog/tracing/metadata/errors.rb +8 -8
- data/lib/datadog/tracing/metadata/ext.rb +86 -59
- data/lib/datadog/tracing/metadata/metastruct.rb +36 -0
- data/lib/datadog/tracing/metadata/metastruct_tagging.rb +42 -0
- data/lib/datadog/tracing/metadata/tagging.rb +8 -8
- data/lib/datadog/tracing/metadata.rb +5 -3
- data/lib/datadog/tracing/pipeline/span_filter.rb +5 -3
- data/lib/datadog/tracing/pipeline/span_processor.rb +3 -1
- data/lib/datadog/tracing/pipeline.rb +4 -4
- data/lib/datadog/tracing/remote.rb +47 -17
- data/lib/datadog/tracing/sampling/all_sampler.rb +1 -1
- data/lib/datadog/tracing/sampling/ext.rb +9 -9
- data/lib/datadog/tracing/sampling/matcher.rb +4 -4
- data/lib/datadog/tracing/sampling/priority_sampler.rb +20 -5
- 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 +9 -19
- data/lib/datadog/tracing/sampling/rule.rb +5 -5
- data/lib/datadog/tracing/sampling/rule_sampler.rb +88 -59
- 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 -2
- data/lib/datadog/tracing/sampling/span/rule_parser.rb +11 -11
- data/lib/datadog/tracing/sampling/span/sampler.rb +0 -7
- data/lib/datadog/tracing/span.rb +28 -11
- data/lib/datadog/tracing/span_event.rb +125 -5
- data/lib/datadog/tracing/span_link.rb +12 -12
- data/lib/datadog/tracing/span_operation.rb +119 -39
- data/lib/datadog/tracing/sync_writer.rb +14 -11
- data/lib/datadog/tracing/trace_digest.rb +36 -24
- data/lib/datadog/tracing/trace_operation.rb +243 -112
- data/lib/datadog/tracing/trace_segment.rb +18 -16
- data/lib/datadog/tracing/tracer.rb +181 -72
- data/lib/datadog/tracing/transport/http/client.rb +17 -30
- data/lib/datadog/tracing/transport/http/statistics.rb +2 -2
- data/lib/datadog/tracing/transport/http/traces.rb +11 -90
- data/lib/datadog/tracing/transport/http.rb +26 -77
- data/lib/datadog/tracing/transport/io/client.rb +13 -16
- data/lib/datadog/tracing/transport/io/response.rb +1 -1
- data/lib/datadog/tracing/transport/io/traces.rb +32 -38
- data/lib/datadog/tracing/transport/io.rb +3 -3
- data/lib/datadog/tracing/transport/serializable_trace.rb +47 -23
- data/lib/datadog/tracing/transport/statistics.rb +3 -3
- data/lib/datadog/tracing/transport/trace_formatter.rb +36 -7
- data/lib/datadog/tracing/transport/traces.rb +56 -90
- data/lib/datadog/tracing/utils.rb +3 -3
- data/lib/datadog/tracing/workers.rb +11 -9
- data/lib/datadog/tracing/writer.rb +15 -11
- data/lib/datadog/tracing.rb +19 -6
- data/lib/datadog/version.rb +4 -4
- data/lib/datadog.rb +20 -7
- metadata +327 -69
- data/ext/datadog_profiling_loader/datadog_profiling_loader.c +0 -142
- data/ext/datadog_profiling_loader/extconf.rb +0 -60
- data/ext/datadog_profiling_native_extension/clock_id_noop.c +0 -21
- data/ext/libdatadog_api/macos_development.md +0 -26
- data/lib/datadog/appsec/assets/waf_rules/processors.json +0 -92
- data/lib/datadog/appsec/assets/waf_rules/scanners.json +0 -114
- data/lib/datadog/appsec/configuration/settings.rb +0 -215
- data/lib/datadog/appsec/contrib/devise/event.rb +0 -57
- data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +0 -77
- data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +0 -54
- data/lib/datadog/appsec/contrib/devise/resource.rb +0 -35
- data/lib/datadog/appsec/contrib/devise/tracking.rb +0 -57
- data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +0 -46
- data/lib/datadog/appsec/contrib/patcher.rb +0 -12
- data/lib/datadog/appsec/contrib/rack/reactive/request.rb +0 -69
- data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +0 -47
- data/lib/datadog/appsec/contrib/rack/reactive/response.rb +0 -53
- data/lib/datadog/appsec/contrib/rails/ext.rb +0 -13
- data/lib/datadog/appsec/contrib/rails/reactive/action.rb +0 -53
- data/lib/datadog/appsec/contrib/sinatra/ext.rb +0 -14
- data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +0 -48
- data/lib/datadog/appsec/monitor/reactive/set_user.rb +0 -45
- data/lib/datadog/appsec/processor/context.rb +0 -107
- data/lib/datadog/appsec/processor/rule_merger.rb +0 -170
- data/lib/datadog/appsec/processor.rb +0 -106
- data/lib/datadog/appsec/reactive/address_hash.rb +0 -22
- data/lib/datadog/appsec/reactive/engine.rb +0 -47
- data/lib/datadog/appsec/reactive/operation.rb +0 -68
- data/lib/datadog/appsec/reactive/subscriber.rb +0 -19
- data/lib/datadog/appsec/scope.rb +0 -58
- data/lib/datadog/appsec/utils/trace_operation.rb +0 -15
- data/lib/datadog/core/crashtracking/agent_base_url.rb +0 -21
- data/lib/datadog/core/remote/transport/http/api/instance.rb +0 -39
- data/lib/datadog/core/remote/transport/http/api/spec.rb +0 -21
- data/lib/datadog/core/remote/transport/http/api.rb +0 -58
- data/lib/datadog/core/remote/transport/http/builder.rb +0 -219
- data/lib/datadog/core/remote/transport/http/client.rb +0 -48
- data/lib/datadog/core/telemetry/http/env.rb +0 -20
- data/lib/datadog/core/telemetry/http/ext.rb +0 -28
- data/lib/datadog/core/telemetry/http/response.rb +0 -70
- data/lib/datadog/core/telemetry/http/transport.rb +0 -90
- data/lib/datadog/core/utils/base64.rb +0 -22
- data/lib/datadog/di/configuration/settings.rb +0 -188
- data/lib/datadog/di/transport.rb +0 -81
- data/lib/datadog/tracing/contrib/rails/utils.rb +0 -26
- data/lib/datadog/tracing/transport/http/api/spec.rb +0 -19
- data/lib/datadog/tracing/transport/http/api.rb +0 -43
- data/lib/datadog/tracing/workers/trace_writer.rb +0 -196
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
#include "heap_recorder.h"
|
|
2
|
-
#include <pthread.h>
|
|
3
2
|
#include "ruby/st.h"
|
|
4
3
|
#include "ruby_helpers.h"
|
|
5
|
-
#include <errno.h>
|
|
6
4
|
#include "collectors_stack.h"
|
|
7
5
|
#include "libdatadog_helpers.h"
|
|
8
6
|
#include "time_helpers.h"
|
|
9
7
|
|
|
8
|
+
// note on calloc vs ruby_xcalloc use:
|
|
9
|
+
// * Whenever we're allocating memory after being called by the Ruby VM in a "regular" situation (e.g. initializer)
|
|
10
|
+
// we should use `ruby_xcalloc` to give the VM visibility into what we're doing + give it a chance to manage GC
|
|
11
|
+
// * BUT, when we're being called during a sample, being in the middle of an object allocation is a very special
|
|
12
|
+
// situation for the VM to be in, and we've found the hard way (e.g. https://bugs.ruby-lang.org/issues/20629 and
|
|
13
|
+
// https://github.com/DataDog/dd-trace-rb/pull/4240 ) that it can be easy to do things the VM didn't expect.
|
|
14
|
+
// * Thus, out of caution and to avoid future potential issues such as the ones above, whenever we allocate memory
|
|
15
|
+
// during **sampling** we use `calloc` instead of `ruby_xcalloc`. Note that we've never seen issues from using
|
|
16
|
+
// `ruby_xcalloc` at any time, so this is a **precaution** not a "we've seen it break". But it seems a harmless
|
|
17
|
+
// one to use.
|
|
18
|
+
// This applies to both heap_recorder.c and collectors_thread_context.c
|
|
19
|
+
|
|
10
20
|
// Minimum age (in GC generations) of heap objects we want to include in heap
|
|
11
21
|
// recorder iterations. Object with age 0 represent objects that have yet to undergo
|
|
12
22
|
// a GC and, thus, may just be noise/trash at instant of iteration and are usually not
|
|
@@ -26,81 +36,37 @@
|
|
|
26
36
|
|
|
27
37
|
// A compact representation of a stacktrace frame for a heap allocation.
|
|
28
38
|
typedef struct {
|
|
29
|
-
|
|
30
|
-
|
|
39
|
+
ddog_prof_ManagedStringId name;
|
|
40
|
+
ddog_prof_ManagedStringId filename;
|
|
31
41
|
int32_t line;
|
|
32
42
|
} heap_frame;
|
|
33
|
-
|
|
43
|
+
|
|
44
|
+
// We use memcmp/st_hash below to compare/hash an entire array of heap_frames, so want to make sure no padding is added
|
|
45
|
+
// We could define the structure to be packed, but that seems even weirder across compilers, and this seems more portable?
|
|
46
|
+
_Static_assert(
|
|
47
|
+
sizeof(heap_frame) == sizeof(ddog_prof_ManagedStringId) * 2 + sizeof(int32_t),
|
|
48
|
+
"Size of heap_frame does not match the sum of its members. Padding detected."
|
|
49
|
+
);
|
|
34
50
|
|
|
35
51
|
// A compact representation of a stacktrace for a heap allocation.
|
|
36
|
-
//
|
|
37
|
-
// We could use a ddog_prof_Slice_Location instead but it has a lot of
|
|
38
|
-
// unused fields. Because we have to keep these stacks around for at
|
|
39
|
-
// least the lifetime of the objects allocated therein, we would be
|
|
40
|
-
// incurring a non-negligible memory overhead for little purpose.
|
|
52
|
+
// Used to dedup heap allocation stacktraces across multiple objects sharing the same allocation location.
|
|
41
53
|
typedef struct {
|
|
54
|
+
// How many objects are currently tracked in object_records recorder for this heap record.
|
|
55
|
+
uint32_t num_tracked_objects;
|
|
56
|
+
|
|
42
57
|
uint16_t frames_len;
|
|
43
58
|
heap_frame frames[];
|
|
44
|
-
}
|
|
45
|
-
static
|
|
46
|
-
static void
|
|
47
|
-
static st_index_t heap_stack_hash(heap_stack*, st_index_t);
|
|
59
|
+
} heap_record;
|
|
60
|
+
static heap_record* heap_record_new(heap_recorder*, ddog_prof_Slice_Location);
|
|
61
|
+
static void heap_record_free(heap_recorder*, heap_record*, bool should_unintern);
|
|
48
62
|
|
|
49
63
|
#if MAX_FRAMES_LIMIT > UINT16_MAX
|
|
50
64
|
#error Frames len type not compatible with MAX_FRAMES_LIMIT
|
|
51
65
|
#endif
|
|
52
66
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
};
|
|
57
|
-
// This struct allows us to use two different types of stacks when
|
|
58
|
-
// interacting with a heap_record hash.
|
|
59
|
-
//
|
|
60
|
-
// The idea is that we'll always want to use heap_stack-keys when
|
|
61
|
-
// adding new entries to the hash since that's the compact stack
|
|
62
|
-
// representation we rely on internally.
|
|
63
|
-
//
|
|
64
|
-
// However, when querying for an existing heap record, we'd save a
|
|
65
|
-
// lot of allocations if we could query with the
|
|
66
|
-
// ddog_prof_Slice_Location we receive in our external API.
|
|
67
|
-
//
|
|
68
|
-
// To allow this interchange, we need a union and need to ensure
|
|
69
|
-
// that whatever shape of the union, the heap_record_key_cmp_st
|
|
70
|
-
// and heap_record_hash_st functions return the same results for
|
|
71
|
-
// equivalent stacktraces.
|
|
72
|
-
typedef struct {
|
|
73
|
-
enum heap_record_key_type type;
|
|
74
|
-
union {
|
|
75
|
-
// key never owns this if set
|
|
76
|
-
heap_stack *heap_stack;
|
|
77
|
-
// key never owns this if set
|
|
78
|
-
ddog_prof_Slice_Location *location_slice;
|
|
79
|
-
};
|
|
80
|
-
} heap_record_key;
|
|
81
|
-
static heap_record_key* heap_record_key_new(heap_stack*);
|
|
82
|
-
static void heap_record_key_free(heap_record_key*);
|
|
83
|
-
static int heap_record_key_cmp_st(st_data_t, st_data_t);
|
|
84
|
-
static st_index_t heap_record_key_hash_st(st_data_t);
|
|
85
|
-
static const struct st_hash_type st_hash_type_heap_record_key = {
|
|
86
|
-
heap_record_key_cmp_st,
|
|
87
|
-
heap_record_key_hash_st,
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
// Need to implement these functions to support the location-slice based keys
|
|
91
|
-
static st_index_t ddog_location_hash(ddog_prof_Location, st_index_t seed);
|
|
92
|
-
static st_index_t ddog_location_slice_hash(ddog_prof_Slice_Location, st_index_t seed);
|
|
93
|
-
|
|
94
|
-
// A heap record is used for deduping heap allocation stacktraces across multiple
|
|
95
|
-
// objects sharing the same allocation location.
|
|
96
|
-
typedef struct {
|
|
97
|
-
// How many objects are currently tracked by the heap recorder for this heap record.
|
|
98
|
-
uint32_t num_tracked_objects;
|
|
99
|
-
// stack is owned by the associated record and gets cleaned up alongside it
|
|
100
|
-
heap_stack *stack;
|
|
101
|
-
} heap_record;
|
|
102
|
-
static heap_record* heap_record_new(heap_stack*);
|
|
103
|
-
static void heap_record_free(heap_record*);
|
|
67
|
+
static int heap_record_cmp_st(st_data_t, st_data_t);
|
|
68
|
+
static st_index_t heap_record_hash_st(st_data_t);
|
|
69
|
+
static const struct st_hash_type st_hash_type_heap_record = { .compare = heap_record_cmp_st, .hash = heap_record_hash_st };
|
|
104
70
|
|
|
105
71
|
// An object record is used for storing data about currently tracked live objects
|
|
106
72
|
typedef struct {
|
|
@@ -109,17 +75,19 @@ typedef struct {
|
|
|
109
75
|
live_object_data object_data;
|
|
110
76
|
} object_record;
|
|
111
77
|
static object_record* object_record_new(long, heap_record*, live_object_data);
|
|
112
|
-
static void object_record_free(object_record
|
|
113
|
-
static VALUE object_record_inspect(object_record*);
|
|
78
|
+
static void object_record_free(heap_recorder*, object_record*, bool should_unintern);
|
|
79
|
+
static VALUE object_record_inspect(heap_recorder*, object_record*);
|
|
114
80
|
static object_record SKIPPED_RECORD = {0};
|
|
115
81
|
|
|
116
|
-
// A
|
|
117
|
-
//
|
|
82
|
+
// A pending recording is used to defer the object_id call on Ruby 4+
|
|
83
|
+
// where calling rb_obj_id during on_newobj_event is unsafe.
|
|
118
84
|
typedef struct {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}
|
|
85
|
+
VALUE object_ref;
|
|
86
|
+
heap_record *heap_record;
|
|
87
|
+
live_object_data object_data;
|
|
88
|
+
} pending_recording;
|
|
89
|
+
|
|
90
|
+
#define MAX_PENDING_RECORDINGS 256
|
|
123
91
|
|
|
124
92
|
struct heap_recorder {
|
|
125
93
|
// Config
|
|
@@ -127,12 +95,15 @@ struct heap_recorder {
|
|
|
127
95
|
bool size_enabled;
|
|
128
96
|
uint sample_rate;
|
|
129
97
|
|
|
130
|
-
// Map[key:
|
|
131
|
-
// NOTE: We always use heap_record_key.type == HEAP_STACK for storage but support lookups
|
|
132
|
-
// via heap_record_key.type == LOCATION_SLICE to allow for allocation-free fast-paths.
|
|
98
|
+
// Map[key: heap_record*, record: nothing] (This is a set, basically)
|
|
133
99
|
// NOTE: This table is currently only protected by the GVL since we never interact with it
|
|
134
100
|
// outside the GVL.
|
|
135
|
-
// NOTE: This table has ownership of
|
|
101
|
+
// NOTE: This table has ownership of its heap_records.
|
|
102
|
+
//
|
|
103
|
+
// This is a cpu/memory trade-off: Maintaining the "heap_records" map means we spend extra CPU when sampling as we need
|
|
104
|
+
// to do de-duplication, but we reduce the memory footprint of the heap profiler.
|
|
105
|
+
// In the future, it may be worth revisiting if we can move this inside libdatadog: if libdatadog was able to track
|
|
106
|
+
// entire stacks for us, then we wouldn't need to do it on the Ruby side.
|
|
136
107
|
st_table *heap_records;
|
|
137
108
|
|
|
138
109
|
// Map[obj_id: long, record: object_record*]
|
|
@@ -140,6 +111,11 @@ struct heap_recorder {
|
|
|
140
111
|
// outside the GVL.
|
|
141
112
|
// NOTE: This table has ownership of its object_records. The keys are longs and so are
|
|
142
113
|
// passed as values.
|
|
114
|
+
//
|
|
115
|
+
// TODO: @ivoanjo We've evolved to actually never need to look up on object_records (we only insert and iterate),
|
|
116
|
+
// so right now this seems to be just a really really fancy self-resizing list/set.
|
|
117
|
+
// If we replace this with a list, we could record the latest id and compare it when inserting to make sure our
|
|
118
|
+
// assumption of ids never reused + always increasing always holds. (This as an alternative to checking for duplicates)
|
|
143
119
|
st_table *object_records;
|
|
144
120
|
|
|
145
121
|
// Map[obj_id: long, record: object_record*]
|
|
@@ -162,14 +138,30 @@ struct heap_recorder {
|
|
|
162
138
|
long last_update_ns;
|
|
163
139
|
|
|
164
140
|
// Data for a heap recording that was started but not yet ended
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
//
|
|
141
|
+
object_record *active_recording;
|
|
142
|
+
|
|
143
|
+
// Pending recordings that need to be finalized after on_newobj_event completes.
|
|
144
|
+
// On Ruby 4+, we can't call rb_obj_id during the newobj event, so we store the
|
|
145
|
+
// VALUE reference here and finalize it via a postponed job.
|
|
146
|
+
pending_recording pending_recordings[MAX_PENDING_RECORDINGS];
|
|
147
|
+
// Temporary storage for the recording in progress, used between start and end
|
|
148
|
+
VALUE active_deferred_object;
|
|
149
|
+
live_object_data active_deferred_object_data;
|
|
150
|
+
uint16_t pending_recordings_count;
|
|
151
|
+
|
|
152
|
+
// Reusable arrays, implementing a flyweight pattern for things like iteration
|
|
153
|
+
#define REUSABLE_LOCATIONS_SIZE MAX_FRAMES_LIMIT
|
|
168
154
|
ddog_prof_Location *reusable_locations;
|
|
169
155
|
|
|
156
|
+
#define REUSABLE_FRAME_DETAILS_SIZE (2 * MAX_FRAMES_LIMIT) // because it'll be used for both function names AND file names)
|
|
157
|
+
ddog_prof_ManagedStringId *reusable_ids;
|
|
158
|
+
ddog_CharSlice *reusable_char_slices;
|
|
159
|
+
|
|
170
160
|
// Sampling state
|
|
171
161
|
uint num_recordings_skipped;
|
|
172
162
|
|
|
163
|
+
ddog_prof_ManagedStringStorage string_storage;
|
|
164
|
+
|
|
173
165
|
struct stats_last_update {
|
|
174
166
|
size_t objects_alive;
|
|
175
167
|
size_t objects_dead;
|
|
@@ -190,27 +182,35 @@ struct heap_recorder {
|
|
|
190
182
|
double ewma_objects_alive;
|
|
191
183
|
double ewma_objects_dead;
|
|
192
184
|
double ewma_objects_skipped;
|
|
185
|
+
|
|
186
|
+
unsigned long deferred_recordings_skipped_buffer_full;
|
|
187
|
+
unsigned long deferred_recordings_finalized;
|
|
193
188
|
} stats_lifetime;
|
|
194
189
|
};
|
|
195
190
|
|
|
196
|
-
struct
|
|
197
|
-
|
|
191
|
+
typedef struct {
|
|
192
|
+
heap_recorder *heap_recorder;
|
|
198
193
|
ddog_prof_Slice_Location locations;
|
|
199
|
-
};
|
|
194
|
+
} end_heap_allocation_args;
|
|
200
195
|
|
|
201
196
|
static heap_record* get_or_create_heap_record(heap_recorder*, ddog_prof_Slice_Location);
|
|
202
197
|
static void cleanup_heap_record_if_unused(heap_recorder*, heap_record*);
|
|
203
198
|
static void on_committed_object_record_cleanup(heap_recorder *heap_recorder, object_record *record);
|
|
204
|
-
static int
|
|
205
|
-
static int
|
|
199
|
+
static int st_heap_record_entry_free_no_unintern(st_data_t, st_data_t, st_data_t);
|
|
200
|
+
static int st_object_record_entry_free_no_unintern(st_data_t, st_data_t, st_data_t);
|
|
206
201
|
static int st_object_record_update(st_data_t, st_data_t, st_data_t);
|
|
207
202
|
static int st_object_records_iterate(st_data_t, st_data_t, st_data_t);
|
|
208
203
|
static int st_object_records_debug(st_data_t key, st_data_t value, st_data_t extra);
|
|
209
204
|
static int update_object_record_entry(st_data_t*, st_data_t*, st_data_t, int);
|
|
210
|
-
static void
|
|
205
|
+
static void inc_tracked_objects_or_fail(heap_record *heap_record);
|
|
206
|
+
static void commit_recording(heap_recorder *, heap_record *, object_record *active_recording);
|
|
211
207
|
static VALUE end_heap_allocation_recording(VALUE end_heap_allocation_args);
|
|
212
208
|
static void heap_recorder_update(heap_recorder *heap_recorder, bool full_update);
|
|
213
209
|
static inline double ewma_stat(double previous, double current);
|
|
210
|
+
static void unintern_or_raise(heap_recorder *, ddog_prof_ManagedStringId);
|
|
211
|
+
static void unintern_all_or_raise(heap_recorder *recorder, ddog_prof_Slice_ManagedStringId ids);
|
|
212
|
+
static VALUE get_ruby_string_or_raise(heap_recorder*, ddog_prof_ManagedStringId);
|
|
213
|
+
static long obj_id_or_fail(VALUE obj);
|
|
214
214
|
|
|
215
215
|
// ==========================
|
|
216
216
|
// Heap Recorder External API
|
|
@@ -221,16 +221,20 @@ static inline double ewma_stat(double previous, double current);
|
|
|
221
221
|
// happens under the GVL.
|
|
222
222
|
//
|
|
223
223
|
// ==========================
|
|
224
|
-
heap_recorder* heap_recorder_new(
|
|
224
|
+
heap_recorder* heap_recorder_new(ddog_prof_ManagedStringStorage string_storage) {
|
|
225
225
|
heap_recorder *recorder = ruby_xcalloc(1, sizeof(heap_recorder));
|
|
226
226
|
|
|
227
|
-
recorder->heap_records = st_init_table(&
|
|
227
|
+
recorder->heap_records = st_init_table(&st_hash_type_heap_record);
|
|
228
228
|
recorder->object_records = st_init_numtable();
|
|
229
229
|
recorder->object_records_snapshot = NULL;
|
|
230
|
-
recorder->reusable_locations = ruby_xcalloc(
|
|
231
|
-
recorder->
|
|
230
|
+
recorder->reusable_locations = ruby_xcalloc(REUSABLE_LOCATIONS_SIZE, sizeof(ddog_prof_Location));
|
|
231
|
+
recorder->reusable_ids = ruby_xcalloc(REUSABLE_FRAME_DETAILS_SIZE, sizeof(ddog_prof_ManagedStringId));
|
|
232
|
+
recorder->reusable_char_slices = ruby_xcalloc(REUSABLE_FRAME_DETAILS_SIZE, sizeof(ddog_CharSlice));
|
|
233
|
+
recorder->active_recording = NULL;
|
|
232
234
|
recorder->size_enabled = true;
|
|
233
235
|
recorder->sample_rate = 1; // By default do no sampling on top of what allocation profiling already does
|
|
236
|
+
recorder->string_storage = string_storage;
|
|
237
|
+
recorder->active_deferred_object = Qnil;
|
|
234
238
|
|
|
235
239
|
return recorder;
|
|
236
240
|
}
|
|
@@ -246,20 +250,29 @@ void heap_recorder_free(heap_recorder *heap_recorder) {
|
|
|
246
250
|
heap_recorder_finish_iteration(heap_recorder);
|
|
247
251
|
}
|
|
248
252
|
|
|
253
|
+
// NOTE: We don't unintern the strings referenced by the records we're about to free, thus we use
|
|
254
|
+
// `..._no_unintern` and `should_unintern: false`. This is intentional: `heap_recorder_free` is only ever called as part of
|
|
255
|
+
// tearing down the entire stack recorder, and the caller drops the whole managed string storage right after
|
|
256
|
+
// (see `stack_recorder_typed_data_free`), so there's no need to spend effort updating the managed string table.
|
|
257
|
+
// Crucially, this also keeps us from crashing: this code runs from the stack recorder's GC free callback, and
|
|
258
|
+
// because uninterning can fail, we can't raise exceptions in the middle of a dfree.
|
|
259
|
+
|
|
249
260
|
// Clean-up all object records
|
|
250
|
-
st_foreach(heap_recorder->object_records,
|
|
261
|
+
st_foreach(heap_recorder->object_records, st_object_record_entry_free_no_unintern, (st_data_t) heap_recorder);
|
|
251
262
|
st_free_table(heap_recorder->object_records);
|
|
252
263
|
|
|
253
264
|
// Clean-up all heap records (this includes those only referred to by queued_samples)
|
|
254
|
-
st_foreach(heap_recorder->heap_records,
|
|
265
|
+
st_foreach(heap_recorder->heap_records, st_heap_record_entry_free_no_unintern, (st_data_t) heap_recorder);
|
|
255
266
|
st_free_table(heap_recorder->heap_records);
|
|
256
267
|
|
|
257
|
-
if (heap_recorder->active_recording
|
|
268
|
+
if (heap_recorder->active_recording != NULL && heap_recorder->active_recording != &SKIPPED_RECORD) {
|
|
258
269
|
// If there's a partial object record, clean it up as well
|
|
259
|
-
object_record_free(heap_recorder->active_recording
|
|
270
|
+
object_record_free(heap_recorder, heap_recorder->active_recording, false);
|
|
260
271
|
}
|
|
261
272
|
|
|
262
273
|
ruby_xfree(heap_recorder->reusable_locations);
|
|
274
|
+
ruby_xfree(heap_recorder->reusable_ids);
|
|
275
|
+
ruby_xfree(heap_recorder->reusable_char_slices);
|
|
263
276
|
|
|
264
277
|
ruby_xfree(heap_recorder);
|
|
265
278
|
}
|
|
@@ -278,7 +291,7 @@ void heap_recorder_set_sample_rate(heap_recorder *heap_recorder, int sample_rate
|
|
|
278
291
|
}
|
|
279
292
|
|
|
280
293
|
if (sample_rate <= 0) {
|
|
281
|
-
|
|
294
|
+
raise_error(rb_eArgError, "Heap sample rate must be a positive integer value but was %d", sample_rate);
|
|
282
295
|
}
|
|
283
296
|
|
|
284
297
|
heap_recorder->sample_rate = sample_rate;
|
|
@@ -300,8 +313,8 @@ void heap_recorder_after_fork(heap_recorder *heap_recorder) {
|
|
|
300
313
|
// simply be noticed on next heap_recorder_prepare_iteration.
|
|
301
314
|
//
|
|
302
315
|
// There is one small caveat though: fork only preserves one thread and in a Ruby app, that
|
|
303
|
-
// will be the thread holding
|
|
304
|
-
// outside of the GVL, any state specific to that interaction may be
|
|
316
|
+
// will be the thread holding the GVL. Since we support iteration on the heap recorder
|
|
317
|
+
// outside of the GVL, any state specific to that interaction may be inconsistent after fork
|
|
305
318
|
// (e.g. an acquired lock for thread safety). Iteration operates on object_records_snapshot
|
|
306
319
|
// though and that one will be updated on next heap_recorder_prepare_iteration so we really
|
|
307
320
|
// only need to finish any iteration that might have been left unfinished.
|
|
@@ -313,101 +326,220 @@ void heap_recorder_after_fork(heap_recorder *heap_recorder) {
|
|
|
313
326
|
heap_recorder->stats_lifetime = (struct stats_lifetime) {0};
|
|
314
327
|
}
|
|
315
328
|
|
|
316
|
-
|
|
329
|
+
bool start_heap_allocation_recording(heap_recorder *heap_recorder, VALUE new_obj, unsigned int weight, ddog_CharSlice alloc_class) {
|
|
317
330
|
if (heap_recorder == NULL) {
|
|
318
|
-
return;
|
|
331
|
+
return false;
|
|
319
332
|
}
|
|
320
333
|
|
|
321
|
-
if (heap_recorder->active_recording
|
|
322
|
-
|
|
334
|
+
if (heap_recorder->active_recording != NULL) {
|
|
335
|
+
raise_error(rb_eRuntimeError, "Detected consecutive heap allocation recording starts without end.");
|
|
323
336
|
}
|
|
324
337
|
|
|
325
|
-
if (heap_recorder->num_recordings_skipped
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
338
|
+
if (++heap_recorder->num_recordings_skipped < heap_recorder->sample_rate ||
|
|
339
|
+
#ifdef NO_IMEMO_OBJECT_ID
|
|
340
|
+
// On Ruby 4, we can't ask the object_id from IMEMOs (https://github.com/ruby/ruby/pull/13347)
|
|
341
|
+
RB_BUILTIN_TYPE(new_obj) == RUBY_T_IMEMO
|
|
342
|
+
#else
|
|
343
|
+
false
|
|
344
|
+
#endif
|
|
345
|
+
// If we got really unlucky and an allocation showed up during an update (because it triggered an allocation
|
|
346
|
+
// directly OR because the GVL got released in the middle of an update), let's skip this sample as well.
|
|
347
|
+
// See notes on `heap_recorder_update` for details.
|
|
348
|
+
|| heap_recorder->updating
|
|
349
|
+
) {
|
|
350
|
+
heap_recorder->active_recording = &SKIPPED_RECORD;
|
|
351
|
+
return false;
|
|
329
352
|
}
|
|
330
353
|
|
|
331
|
-
|
|
354
|
+
bool needs_after_allocation = false;
|
|
332
355
|
|
|
333
|
-
|
|
334
|
-
if
|
|
335
|
-
|
|
356
|
+
#ifdef USE_DEFERRED_HEAP_ALLOCATION_RECORDING
|
|
357
|
+
// Skip if we've hit the pending recordings limit or if there's already a deferred object being recorded
|
|
358
|
+
if (heap_recorder->pending_recordings_count >= MAX_PENDING_RECORDINGS) {
|
|
359
|
+
heap_recorder->stats_lifetime.deferred_recordings_skipped_buffer_full++;
|
|
360
|
+
heap_recorder->active_recording = &SKIPPED_RECORD;
|
|
361
|
+
return true; // If the buffer is full, we keep asking for a callback (see `needs_after_allocation` below)
|
|
362
|
+
} else {
|
|
363
|
+
// The intuition here is: We start by asking for an `after_allocation` callback when the buffer is about to go
|
|
364
|
+
// from empty -> non-empty, because this is going to be mapped onto a postponed job, so after it gets queued once
|
|
365
|
+
// it doesn't seem worth it to keep spamming requests.
|
|
366
|
+
//
|
|
367
|
+
// Yet, if for some reason the postponed job doesn't flush the pending list (or if e.g. it ran with `during_sample == true` and thus
|
|
368
|
+
// was skipped) we need to have some mechanism to recover -- and so if the buffer starts accumulating too much we
|
|
369
|
+
// start always requesting the callback to happen so that we eventually flush the buffer.
|
|
370
|
+
needs_after_allocation =
|
|
371
|
+
heap_recorder->pending_recordings_count == 0 || heap_recorder->pending_recordings_count >= (MAX_PENDING_RECORDINGS / 2);
|
|
336
372
|
}
|
|
373
|
+
#endif
|
|
374
|
+
|
|
375
|
+
heap_recorder->num_recordings_skipped = 0;
|
|
337
376
|
|
|
338
|
-
|
|
339
|
-
.
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
.alloc_gen = rb_gc_count(),
|
|
343
|
-
}),
|
|
377
|
+
live_object_data object_data = (live_object_data) {
|
|
378
|
+
.weight = weight * heap_recorder->sample_rate,
|
|
379
|
+
.class = intern_or_raise(heap_recorder->string_storage, alloc_class),
|
|
380
|
+
.alloc_gen = rb_gc_count(),
|
|
344
381
|
};
|
|
382
|
+
|
|
383
|
+
#ifdef USE_DEFERRED_HEAP_ALLOCATION_RECORDING
|
|
384
|
+
// On Ruby 4+, we can't call rb_obj_id during on_newobj_event as it mutates the object.
|
|
385
|
+
// Instead, we store the VALUE reference and will get the object_id later via a postponed job.
|
|
386
|
+
// active_deferred_object != Qnil indicates we're in deferred mode.
|
|
387
|
+
heap_recorder->active_deferred_object = new_obj;
|
|
388
|
+
heap_recorder->active_deferred_object_data = object_data;
|
|
389
|
+
#else
|
|
390
|
+
heap_recorder->active_recording = object_record_new(obj_id_or_fail(new_obj), NULL, object_data);
|
|
391
|
+
#endif
|
|
392
|
+
|
|
393
|
+
return needs_after_allocation;
|
|
345
394
|
}
|
|
346
395
|
|
|
347
396
|
// end_heap_allocation_recording_with_rb_protect gets called while the stack_recorder is holding one of the profile
|
|
348
397
|
// locks. To enable us to correctly unlock the profile on exception, we wrap the call to end_heap_allocation_recording
|
|
349
398
|
// with an rb_protect.
|
|
350
399
|
__attribute__((warn_unused_result))
|
|
351
|
-
int end_heap_allocation_recording_with_rb_protect(
|
|
400
|
+
int end_heap_allocation_recording_with_rb_protect(heap_recorder *heap_recorder, ddog_prof_Slice_Location locations) {
|
|
401
|
+
if (heap_recorder == NULL) {
|
|
402
|
+
return 0;
|
|
403
|
+
}
|
|
404
|
+
if (heap_recorder->active_recording == &SKIPPED_RECORD) {
|
|
405
|
+
// Short circuit, in this case there's nothing to be done
|
|
406
|
+
heap_recorder->active_recording = NULL;
|
|
407
|
+
return 0;
|
|
408
|
+
}
|
|
409
|
+
|
|
352
410
|
int exception_state;
|
|
353
|
-
|
|
411
|
+
end_heap_allocation_args args = {
|
|
354
412
|
.heap_recorder = heap_recorder,
|
|
355
413
|
.locations = locations,
|
|
356
414
|
};
|
|
357
|
-
rb_protect(end_heap_allocation_recording, (VALUE) &
|
|
415
|
+
rb_protect(end_heap_allocation_recording, (VALUE) &args, &exception_state);
|
|
358
416
|
return exception_state;
|
|
359
417
|
}
|
|
360
418
|
|
|
361
|
-
static VALUE end_heap_allocation_recording(VALUE
|
|
362
|
-
|
|
419
|
+
static VALUE end_heap_allocation_recording(VALUE protect_args) {
|
|
420
|
+
end_heap_allocation_args *args = (end_heap_allocation_args *) protect_args;
|
|
363
421
|
|
|
364
|
-
|
|
422
|
+
heap_recorder *heap_recorder = args->heap_recorder;
|
|
365
423
|
ddog_prof_Slice_Location locations = args->locations;
|
|
366
424
|
|
|
425
|
+
#ifdef USE_DEFERRED_HEAP_ALLOCATION_RECORDING
|
|
426
|
+
if (heap_recorder->active_deferred_object == Qnil) {
|
|
427
|
+
// Recording ended without having been started?
|
|
428
|
+
raise_error(rb_eRuntimeError, "Ended a heap recording that was not started");
|
|
429
|
+
}
|
|
430
|
+
#else
|
|
431
|
+
object_record *active_recording = heap_recorder->active_recording;
|
|
432
|
+
|
|
433
|
+
if (active_recording == NULL) {
|
|
434
|
+
// Recording ended without having been started?
|
|
435
|
+
raise_error(rb_eRuntimeError, "Ended a heap recording that was not started");
|
|
436
|
+
}
|
|
437
|
+
// From now on, mark the global active recording as invalid so we can short-circuit at any point
|
|
438
|
+
// and not end up with a still active recording. the local active_recording still holds the
|
|
439
|
+
// data required for committing though.
|
|
440
|
+
heap_recorder->active_recording = NULL;
|
|
441
|
+
|
|
442
|
+
if (active_recording == &SKIPPED_RECORD) {
|
|
443
|
+
raise_error(
|
|
444
|
+
rb_eRuntimeError,
|
|
445
|
+
"BUG: end_heap_allocation_recording should never observe SKIPPED_RECORDING because " \
|
|
446
|
+
"end_heap_allocation_recording_with_rb_protect is supposed to test for it directly"
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
#endif
|
|
450
|
+
|
|
451
|
+
heap_record *heap_record = get_or_create_heap_record(heap_recorder, locations);
|
|
452
|
+
inc_tracked_objects_or_fail(heap_record);
|
|
453
|
+
|
|
454
|
+
#ifdef USE_DEFERRED_HEAP_ALLOCATION_RECORDING
|
|
455
|
+
// Commit is delayed, so we need to record all we'll need for it
|
|
456
|
+
pending_recording *pending = &heap_recorder->pending_recordings[heap_recorder->pending_recordings_count++];
|
|
457
|
+
pending->object_ref = heap_recorder->active_deferred_object;
|
|
458
|
+
pending->heap_record = heap_record;
|
|
459
|
+
pending->object_data = heap_recorder->active_deferred_object_data;
|
|
460
|
+
|
|
461
|
+
heap_recorder->active_deferred_object = Qnil;
|
|
462
|
+
heap_recorder->active_deferred_object_data = (live_object_data) {0};
|
|
463
|
+
#else
|
|
464
|
+
// And then commit the new allocation
|
|
465
|
+
commit_recording(heap_recorder, heap_record, active_recording);
|
|
466
|
+
#endif
|
|
467
|
+
|
|
468
|
+
return Qnil;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
void heap_recorder_update_young_objects(heap_recorder *heap_recorder) {
|
|
367
472
|
if (heap_recorder == NULL) {
|
|
368
|
-
return
|
|
473
|
+
return;
|
|
369
474
|
}
|
|
370
475
|
|
|
371
|
-
|
|
476
|
+
heap_recorder_update(heap_recorder, /* full_update: */ false);
|
|
477
|
+
}
|
|
372
478
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
479
|
+
void heap_recorder_finalize_pending_recordings(heap_recorder *heap_recorder) {
|
|
480
|
+
if (heap_recorder == NULL) {
|
|
481
|
+
return; // Nothing to do
|
|
376
482
|
}
|
|
377
|
-
// From now on, mark the global active recording as invalid so we can short-circuit at any point
|
|
378
|
-
// and not end up with a still active recording. the local active_recording still holds the
|
|
379
|
-
// data required for committing though.
|
|
380
|
-
heap_recorder->active_recording = (recording) {0};
|
|
381
483
|
|
|
382
|
-
|
|
383
|
-
|
|
484
|
+
uint count = heap_recorder->pending_recordings_count;
|
|
485
|
+
if (count == 0) {
|
|
486
|
+
return; // Nothing to do
|
|
384
487
|
}
|
|
385
488
|
|
|
386
|
-
|
|
489
|
+
heap_recorder->stats_lifetime.deferred_recordings_finalized += count;
|
|
387
490
|
|
|
388
|
-
|
|
389
|
-
|
|
491
|
+
for (uint i = 0; i < count; i++) {
|
|
492
|
+
pending_recording *pending = &heap_recorder->pending_recordings[i];
|
|
390
493
|
|
|
391
|
-
|
|
494
|
+
// This is the step we couldn't do during the original sample call -- we're now expected to be called in a context
|
|
495
|
+
// where it's finally safe to call this
|
|
496
|
+
long obj_id = obj_id_or_fail(pending->object_ref);
|
|
497
|
+
|
|
498
|
+
// Create the object record now that we have the object_id
|
|
499
|
+
object_record *record = object_record_new(obj_id, pending->heap_record, pending->object_data);
|
|
500
|
+
|
|
501
|
+
commit_recording(heap_recorder, pending->heap_record, record);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
heap_recorder->pending_recordings_count = 0;
|
|
392
505
|
}
|
|
393
506
|
|
|
394
|
-
|
|
507
|
+
// Mark pending recordings to prevent GC from collecting the objects
|
|
508
|
+
// while they're waiting to be finalized
|
|
509
|
+
void heap_recorder_mark_pending_recordings(heap_recorder *heap_recorder) {
|
|
395
510
|
if (heap_recorder == NULL) {
|
|
396
511
|
return;
|
|
397
512
|
}
|
|
398
513
|
|
|
399
|
-
|
|
514
|
+
for (uint i = 0; i < heap_recorder->pending_recordings_count; i++) {
|
|
515
|
+
rb_gc_mark(heap_recorder->pending_recordings[i].object_ref);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
rb_gc_mark(heap_recorder->active_deferred_object);
|
|
400
519
|
}
|
|
401
520
|
|
|
521
|
+
// NOTE: This function needs and assumes it gets called with the GVL being held.
|
|
522
|
+
// But importantly **some of the operations inside `st_object_record_update` may cause a thread switch**,
|
|
523
|
+
// so we can't assume a single update happens in a single "atomic" step -- other threads may get some running time
|
|
524
|
+
// in the meanwhile.
|
|
402
525
|
static void heap_recorder_update(heap_recorder *heap_recorder, bool full_update) {
|
|
403
526
|
if (heap_recorder->updating) {
|
|
404
|
-
if (full_update)
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
527
|
+
if (full_update) {
|
|
528
|
+
// There's another thread that's already doing an update :(
|
|
529
|
+
//
|
|
530
|
+
// Because there's a lock on the `StackRecorder` (see @no_concurrent_serialize_mutex) then it's not possible that
|
|
531
|
+
// the other update is a full update.
|
|
532
|
+
// Thus we expect is happening is that the GVL got released by the other thread in the middle of a non-full update
|
|
533
|
+
// and the scheduler thread decided now was a great time to serialize the profile.
|
|
534
|
+
//
|
|
535
|
+
// So, let's yield the time on the current thread until Ruby goes back to the other thread doing the update and
|
|
536
|
+
// it finishes cleanly.
|
|
537
|
+
while (heap_recorder->updating) { rb_thread_schedule(); }
|
|
538
|
+
} else {
|
|
539
|
+
// Non-full updates are optional, so let's walk away
|
|
540
|
+
heap_recorder->stats_lifetime.updates_skipped_concurrent++;
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
411
543
|
}
|
|
412
544
|
|
|
413
545
|
if (heap_recorder->object_records_snapshot != NULL) {
|
|
@@ -474,14 +606,14 @@ void heap_recorder_prepare_iteration(heap_recorder *heap_recorder) {
|
|
|
474
606
|
|
|
475
607
|
if (heap_recorder->object_records_snapshot != NULL) {
|
|
476
608
|
// we could trivially handle this but we raise to highlight and catch unexpected usages.
|
|
477
|
-
|
|
609
|
+
raise_error(rb_eRuntimeError, "New heap recorder iteration prepared without the previous one having been finished.");
|
|
478
610
|
}
|
|
479
611
|
|
|
480
612
|
heap_recorder_update(heap_recorder, /* full_update: */ true);
|
|
481
613
|
|
|
482
614
|
heap_recorder->object_records_snapshot = st_copy(heap_recorder->object_records);
|
|
483
615
|
if (heap_recorder->object_records_snapshot == NULL) {
|
|
484
|
-
|
|
616
|
+
raise_error(rb_eRuntimeError, "Failed to create heap snapshot.");
|
|
485
617
|
}
|
|
486
618
|
}
|
|
487
619
|
|
|
@@ -492,7 +624,7 @@ void heap_recorder_finish_iteration(heap_recorder *heap_recorder) {
|
|
|
492
624
|
|
|
493
625
|
if (heap_recorder->object_records_snapshot == NULL) {
|
|
494
626
|
// we could trivially handle this but we raise to highlight and catch unexpected usages.
|
|
495
|
-
|
|
627
|
+
raise_error(rb_eRuntimeError, "Heap recorder iteration finished without having been prepared.");
|
|
496
628
|
}
|
|
497
629
|
|
|
498
630
|
st_free_table(heap_recorder->object_records_snapshot);
|
|
@@ -534,20 +666,21 @@ bool heap_recorder_for_each_live_object(
|
|
|
534
666
|
|
|
535
667
|
VALUE heap_recorder_state_snapshot(heap_recorder *heap_recorder) {
|
|
536
668
|
VALUE arguments[] = {
|
|
537
|
-
ID2SYM(rb_intern("num_object_records")), /* => */
|
|
538
|
-
ID2SYM(rb_intern("num_heap_records")), /* => */
|
|
669
|
+
ID2SYM(rb_intern("num_object_records")), /* => */ ULONG2NUM(heap_recorder->object_records->num_entries),
|
|
670
|
+
ID2SYM(rb_intern("num_heap_records")), /* => */ ULONG2NUM(heap_recorder->heap_records->num_entries),
|
|
671
|
+
ID2SYM(rb_intern("pending_recordings_count")), /* => */ ULONG2NUM(heap_recorder->pending_recordings_count),
|
|
539
672
|
|
|
540
673
|
// Stats as of last update
|
|
541
|
-
ID2SYM(rb_intern("last_update_objects_alive")), /* => */
|
|
542
|
-
ID2SYM(rb_intern("last_update_objects_dead")), /* => */
|
|
543
|
-
ID2SYM(rb_intern("last_update_objects_skipped")), /* => */
|
|
544
|
-
ID2SYM(rb_intern("last_update_objects_frozen")), /* => */
|
|
674
|
+
ID2SYM(rb_intern("last_update_objects_alive")), /* => */ ULONG2NUM(heap_recorder->stats_last_update.objects_alive),
|
|
675
|
+
ID2SYM(rb_intern("last_update_objects_dead")), /* => */ ULONG2NUM(heap_recorder->stats_last_update.objects_dead),
|
|
676
|
+
ID2SYM(rb_intern("last_update_objects_skipped")), /* => */ ULONG2NUM(heap_recorder->stats_last_update.objects_skipped),
|
|
677
|
+
ID2SYM(rb_intern("last_update_objects_frozen")), /* => */ ULONG2NUM(heap_recorder->stats_last_update.objects_frozen),
|
|
545
678
|
|
|
546
679
|
// Lifetime stats
|
|
547
|
-
ID2SYM(rb_intern("lifetime_updates_successful")), /* => */
|
|
548
|
-
ID2SYM(rb_intern("lifetime_updates_skipped_concurrent")), /* => */
|
|
549
|
-
ID2SYM(rb_intern("lifetime_updates_skipped_gcgen")), /* => */
|
|
550
|
-
ID2SYM(rb_intern("lifetime_updates_skipped_time")), /* => */
|
|
680
|
+
ID2SYM(rb_intern("lifetime_updates_successful")), /* => */ ULONG2NUM(heap_recorder->stats_lifetime.updates_successful),
|
|
681
|
+
ID2SYM(rb_intern("lifetime_updates_skipped_concurrent")), /* => */ ULONG2NUM(heap_recorder->stats_lifetime.updates_skipped_concurrent),
|
|
682
|
+
ID2SYM(rb_intern("lifetime_updates_skipped_gcgen")), /* => */ ULONG2NUM(heap_recorder->stats_lifetime.updates_skipped_gcgen),
|
|
683
|
+
ID2SYM(rb_intern("lifetime_updates_skipped_time")), /* => */ ULONG2NUM(heap_recorder->stats_lifetime.updates_skipped_time),
|
|
551
684
|
ID2SYM(rb_intern("lifetime_ewma_young_objects_alive")), /* => */ DBL2NUM(heap_recorder->stats_lifetime.ewma_young_objects_alive),
|
|
552
685
|
ID2SYM(rb_intern("lifetime_ewma_young_objects_dead")), /* => */ DBL2NUM(heap_recorder->stats_lifetime.ewma_young_objects_dead),
|
|
553
686
|
// Note: Here "young" refers to the young update; objects skipped includes non-young objects
|
|
@@ -555,61 +688,54 @@ VALUE heap_recorder_state_snapshot(heap_recorder *heap_recorder) {
|
|
|
555
688
|
ID2SYM(rb_intern("lifetime_ewma_objects_alive")), /* => */ DBL2NUM(heap_recorder->stats_lifetime.ewma_objects_alive),
|
|
556
689
|
ID2SYM(rb_intern("lifetime_ewma_objects_dead")), /* => */ DBL2NUM(heap_recorder->stats_lifetime.ewma_objects_dead),
|
|
557
690
|
ID2SYM(rb_intern("lifetime_ewma_objects_skipped")), /* => */ DBL2NUM(heap_recorder->stats_lifetime.ewma_objects_skipped),
|
|
691
|
+
|
|
692
|
+
ID2SYM(rb_intern("lifetime_deferred_recordings_skipped_buffer_full")), /* => */ ULONG2NUM(heap_recorder->stats_lifetime.deferred_recordings_skipped_buffer_full),
|
|
693
|
+
ID2SYM(rb_intern("lifetime_deferred_recordings_finalized")), /* => */ ULONG2NUM(heap_recorder->stats_lifetime.deferred_recordings_finalized),
|
|
558
694
|
};
|
|
559
695
|
VALUE hash = rb_hash_new();
|
|
560
696
|
for (long unsigned int i = 0; i < VALUE_COUNT(arguments); i += 2) rb_hash_aset(hash, arguments[i], arguments[i+1]);
|
|
697
|
+
|
|
561
698
|
return hash;
|
|
562
699
|
}
|
|
563
700
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
.heap_stack = stack,
|
|
569
|
-
};
|
|
570
|
-
heap_record_key location_based_key = (heap_record_key) {
|
|
571
|
-
.type = LOCATION_SLICE,
|
|
572
|
-
.location_slice = &locations,
|
|
573
|
-
};
|
|
574
|
-
|
|
575
|
-
st_index_t stack_hash = heap_record_key_hash_st((st_data_t) &stack_based_key);
|
|
576
|
-
st_index_t location_hash = heap_record_key_hash_st((st_data_t) &location_based_key);
|
|
577
|
-
|
|
578
|
-
heap_stack_free(stack);
|
|
579
|
-
|
|
580
|
-
if (stack_hash != location_hash) {
|
|
581
|
-
rb_raise(rb_eRuntimeError, "Heap record key hashes built from the same locations differ. stack_based_hash=%"PRI_VALUE_PREFIX"u location_based_hash=%"PRI_VALUE_PREFIX"u", stack_hash, location_hash);
|
|
582
|
-
}
|
|
583
|
-
}
|
|
701
|
+
typedef struct {
|
|
702
|
+
heap_recorder *recorder;
|
|
703
|
+
VALUE debug_ary;
|
|
704
|
+
} debug_context;
|
|
584
705
|
|
|
585
706
|
VALUE heap_recorder_testonly_debug(heap_recorder *heap_recorder) {
|
|
586
707
|
if (heap_recorder == NULL) {
|
|
587
|
-
|
|
708
|
+
raise_error(rb_eArgError, "heap_recorder is NULL");
|
|
588
709
|
}
|
|
589
710
|
|
|
590
|
-
VALUE
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
rb_str_catf(debug_str, "state snapshot: %"PRIsVALUE"\n------\n", heap_recorder_state_snapshot(heap_recorder));
|
|
711
|
+
VALUE debug_ary = rb_ary_new();
|
|
712
|
+
debug_context context = (debug_context) {.recorder = heap_recorder, .debug_ary = debug_ary};
|
|
713
|
+
st_foreach(heap_recorder->object_records, st_object_records_debug, (st_data_t) &context);
|
|
594
714
|
|
|
595
|
-
return
|
|
715
|
+
return rb_ary_new_from_args(2,
|
|
716
|
+
rb_ary_new_from_args(2, ID2SYM(rb_intern("records")), debug_ary),
|
|
717
|
+
rb_ary_new_from_args(2, ID2SYM(rb_intern("state")), heap_recorder_state_snapshot(heap_recorder))
|
|
718
|
+
);
|
|
596
719
|
}
|
|
597
720
|
|
|
598
721
|
// ==========================
|
|
599
722
|
// Heap Recorder Internal API
|
|
600
723
|
// ==========================
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
heap_record_free((heap_record *)
|
|
724
|
+
// NOTE: Only expected to be used from heap_recorder_free, which will separately destroy the string table
|
|
725
|
+
static int st_heap_record_entry_free_no_unintern(st_data_t key, DDTRACE_UNUSED st_data_t value, st_data_t extra_arg) {
|
|
726
|
+
heap_recorder *recorder = (heap_recorder *) extra_arg;
|
|
727
|
+
heap_record_free(recorder, (heap_record *) key, false);
|
|
605
728
|
return ST_DELETE;
|
|
606
729
|
}
|
|
607
730
|
|
|
608
|
-
|
|
609
|
-
|
|
731
|
+
// NOTE: Only expected to be used from heap_recorder_free, which will separately destroy the string table
|
|
732
|
+
static int st_object_record_entry_free_no_unintern(DDTRACE_UNUSED st_data_t key, st_data_t value, st_data_t extra_arg) {
|
|
733
|
+
heap_recorder *recorder = (heap_recorder *) extra_arg;
|
|
734
|
+
object_record_free(recorder, (object_record *) value, false);
|
|
610
735
|
return ST_DELETE;
|
|
611
736
|
}
|
|
612
737
|
|
|
738
|
+
// NOTE: Some operations inside this function can cause the GVL to be released! Plan accordingly.
|
|
613
739
|
static int st_object_record_update(st_data_t key, st_data_t value, st_data_t extra_arg) {
|
|
614
740
|
long obj_id = (long) key;
|
|
615
741
|
object_record *record = (object_record*) value;
|
|
@@ -635,7 +761,7 @@ static int st_object_record_update(st_data_t key, st_data_t value, st_data_t ext
|
|
|
635
761
|
return ST_CONTINUE;
|
|
636
762
|
}
|
|
637
763
|
|
|
638
|
-
if (!ruby_ref_from_id(LONG2NUM(obj_id), &ref)) {
|
|
764
|
+
if (!ruby_ref_from_id(LONG2NUM(obj_id), &ref)) { // Note: This function call can cause the GVL to be released
|
|
639
765
|
// Id no longer associated with a valid ref. Need to delete this object record!
|
|
640
766
|
on_committed_object_record_cleanup(recorder, record);
|
|
641
767
|
recorder->stats_last_update.objects_dead++;
|
|
@@ -651,7 +777,8 @@ static int st_object_record_update(st_data_t key, st_data_t value, st_data_t ext
|
|
|
651
777
|
) {
|
|
652
778
|
// if we were asked to update sizes and this object was not already seen as being frozen,
|
|
653
779
|
// update size again.
|
|
654
|
-
record->object_data.size = ruby_obj_memsize_of(ref);
|
|
780
|
+
record->object_data.size = ruby_obj_memsize_of(ref); // Note: This function call can cause the GVL to be released... maybe?
|
|
781
|
+
// (With T_DATA for instance, since it can be a custom method supplied by extensions)
|
|
655
782
|
// Check if it's now frozen so we skip a size update next time
|
|
656
783
|
record->object_data.is_frozen = RB_OBJ_FROZEN(ref);
|
|
657
784
|
}
|
|
@@ -671,7 +798,7 @@ static int st_object_record_update(st_data_t key, st_data_t value, st_data_t ext
|
|
|
671
798
|
// WARN: This can get called outside the GVL. NO HEAP ALLOCATIONS OR EXCEPTIONS ARE ALLOWED.
|
|
672
799
|
static int st_object_records_iterate(DDTRACE_UNUSED st_data_t key, st_data_t value, st_data_t extra) {
|
|
673
800
|
object_record *record = (object_record*) value;
|
|
674
|
-
const
|
|
801
|
+
const heap_record *stack = record->heap_record;
|
|
675
802
|
iteration_context *context = (iteration_context*) extra;
|
|
676
803
|
|
|
677
804
|
const heap_recorder *recorder = context->heap_recorder;
|
|
@@ -685,10 +812,12 @@ static int st_object_records_iterate(DDTRACE_UNUSED st_data_t key, st_data_t val
|
|
|
685
812
|
for (uint16_t i = 0; i < stack->frames_len; i++) {
|
|
686
813
|
const heap_frame *frame = &stack->frames[i];
|
|
687
814
|
locations[i] = (ddog_prof_Location) {
|
|
688
|
-
.mapping = {.filename = DDOG_CHARSLICE_C(""), .build_id = DDOG_CHARSLICE_C("")},
|
|
815
|
+
.mapping = {.filename = DDOG_CHARSLICE_C(""), .build_id = DDOG_CHARSLICE_C(""), .build_id_id = {}},
|
|
689
816
|
.function = {
|
|
690
|
-
.name =
|
|
691
|
-
.
|
|
817
|
+
.name = DDOG_CHARSLICE_C(""),
|
|
818
|
+
.name_id = frame->name,
|
|
819
|
+
.filename = DDOG_CHARSLICE_C(""),
|
|
820
|
+
.filename_id = frame->filename,
|
|
692
821
|
},
|
|
693
822
|
.line = frame->line,
|
|
694
823
|
};
|
|
@@ -698,6 +827,7 @@ static int st_object_records_iterate(DDTRACE_UNUSED st_data_t key, st_data_t val
|
|
|
698
827
|
iteration_data.object_data = record->object_data;
|
|
699
828
|
iteration_data.locations = (ddog_prof_Slice_Location) {.ptr = locations, .len = stack->frames_len};
|
|
700
829
|
|
|
830
|
+
// This is expected to be StackRecorder's add_heap_sample_to_active_profile_without_gvl
|
|
701
831
|
if (!context->for_each_callback(iteration_data, context->for_each_callback_extra_arg)) {
|
|
702
832
|
return ST_STOP;
|
|
703
833
|
}
|
|
@@ -706,107 +836,71 @@ static int st_object_records_iterate(DDTRACE_UNUSED st_data_t key, st_data_t val
|
|
|
706
836
|
}
|
|
707
837
|
|
|
708
838
|
static int st_object_records_debug(DDTRACE_UNUSED st_data_t key, st_data_t value, st_data_t extra) {
|
|
709
|
-
|
|
839
|
+
debug_context *context = (debug_context*) extra;
|
|
710
840
|
|
|
711
841
|
object_record *record = (object_record*) value;
|
|
712
842
|
|
|
713
|
-
|
|
843
|
+
rb_ary_push(context->debug_ary, object_record_inspect(context->recorder, record));
|
|
714
844
|
|
|
715
845
|
return ST_CONTINUE;
|
|
716
846
|
}
|
|
717
847
|
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
// [in] The heap recorder where the update is happening.
|
|
725
|
-
heap_recorder *heap_recorder;
|
|
726
|
-
} object_record_update_data;
|
|
727
|
-
|
|
728
|
-
static int update_object_record_entry(DDTRACE_UNUSED st_data_t *key, st_data_t *value, st_data_t data, int existing) {
|
|
729
|
-
object_record_update_data *update_data = (object_record_update_data*) data;
|
|
730
|
-
recording recording = update_data->recording;
|
|
731
|
-
object_record *new_object_record = recording.object_record;
|
|
732
|
-
if (existing) {
|
|
733
|
-
object_record *existing_record = (object_record*) (*value);
|
|
734
|
-
|
|
735
|
-
// This is not supposed to happen, raising...
|
|
736
|
-
VALUE existing_inspect = object_record_inspect(existing_record);
|
|
737
|
-
VALUE new_inspect = object_record_inspect(new_object_record);
|
|
738
|
-
rb_raise(rb_eRuntimeError, "Object ids are supposed to be unique. We got 2 allocation recordings with "
|
|
739
|
-
"the same id. previous=%"PRIsVALUE" new=%"PRIsVALUE, existing_inspect, new_inspect);
|
|
848
|
+
static int update_object_record_entry(DDTRACE_UNUSED st_data_t *key, st_data_t *value, st_data_t new_object_record, int existing) {
|
|
849
|
+
if (!existing) {
|
|
850
|
+
(*value) = (st_data_t) new_object_record; // Expected to be a `object_record *`
|
|
851
|
+
} else {
|
|
852
|
+
// If key already existed, we don't touch the existing value, so it can be used for diagnostics
|
|
740
853
|
}
|
|
741
|
-
// Always carry on with the update, we want the new record to be there at the end
|
|
742
|
-
(*value) = (st_data_t) new_object_record;
|
|
743
854
|
return ST_CONTINUE;
|
|
744
855
|
}
|
|
745
856
|
|
|
746
|
-
static void
|
|
747
|
-
// Link the object record with the corresponding heap record. This was the last remaining thing we
|
|
748
|
-
// needed to fully build the object_record.
|
|
749
|
-
recording.object_record->heap_record = heap_record;
|
|
857
|
+
static void inc_tracked_objects_or_fail(heap_record *heap_record) {
|
|
750
858
|
if (heap_record->num_tracked_objects == UINT32_MAX) {
|
|
751
|
-
|
|
859
|
+
raise_error(rb_eRuntimeError, "Reached maximum number of tracked objects for heap record");
|
|
752
860
|
}
|
|
753
861
|
heap_record->num_tracked_objects++;
|
|
754
|
-
|
|
755
|
-
// Update object_records with the data for this new recording
|
|
756
|
-
object_record_update_data update_data = (object_record_update_data) {
|
|
757
|
-
.heap_recorder = heap_recorder,
|
|
758
|
-
.recording = recording,
|
|
759
|
-
};
|
|
760
|
-
st_update(heap_recorder->object_records, recording.object_record->obj_id, update_object_record_entry, (st_data_t) &update_data);
|
|
761
862
|
}
|
|
762
863
|
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
//
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
864
|
+
static void commit_recording(heap_recorder *heap_recorder, heap_record *heap_record, object_record *active_recording) {
|
|
865
|
+
// Link the object record with the corresponding heap record. This was the last remaining thing we
|
|
866
|
+
// needed to fully build the object_record.
|
|
867
|
+
active_recording->heap_record = heap_record;
|
|
868
|
+
|
|
869
|
+
int existing_error = st_update(heap_recorder->object_records, active_recording->obj_id, update_object_record_entry, (st_data_t) active_recording);
|
|
870
|
+
if (existing_error) {
|
|
871
|
+
object_record *existing_record = NULL;
|
|
872
|
+
st_lookup(heap_recorder->object_records, active_recording->obj_id, (st_data_t *) &existing_record);
|
|
873
|
+
if (existing_record == NULL) raise_error(rb_eRuntimeError, "Unexpected NULL when reading existing record");
|
|
874
|
+
|
|
875
|
+
VALUE existing_inspect = object_record_inspect(heap_recorder, existing_record);
|
|
876
|
+
VALUE new_inspect = object_record_inspect(heap_recorder, active_recording);
|
|
877
|
+
raise_error(rb_eRuntimeError, "Object ids are supposed to be unique. We got 2 allocation recordings with "
|
|
878
|
+
"the same id. previous={%"PRIsVALUE"} new={%"PRIsVALUE"}", existing_inspect, new_inspect);
|
|
879
|
+
}
|
|
880
|
+
}
|
|
771
881
|
|
|
772
|
-
// This function assumes ownership of stack_data is passed on to it so it'll either transfer ownership or clean-up.
|
|
773
882
|
static int update_heap_record_entry_with_new_allocation(st_data_t *key, st_data_t *value, st_data_t data, int existing) {
|
|
774
|
-
|
|
883
|
+
heap_record **new_or_existing_record = (heap_record **) data;
|
|
884
|
+
(*new_or_existing_record) = (heap_record *) (*key);
|
|
775
885
|
|
|
776
886
|
if (!existing) {
|
|
777
|
-
|
|
778
|
-
// we need to initialize a heap_record_key with a new stack and use that for the key storage. We can't use the
|
|
779
|
-
// locations-based key we used for the update call because we don't own its lifecycle. So we create a new
|
|
780
|
-
// heap stack and will pass ownership of it to the heap_record.
|
|
781
|
-
heap_stack *stack = heap_stack_new(update_data->locations);
|
|
782
|
-
(*key) = (st_data_t) heap_record_key_new(stack);
|
|
783
|
-
(*value) = (st_data_t) heap_record_new(stack);
|
|
887
|
+
(*value) = (st_data_t) true; // We're only using this hash as a set
|
|
784
888
|
}
|
|
785
889
|
|
|
786
|
-
heap_record *record = (heap_record*) (*value);
|
|
787
|
-
(*update_data->record) = record;
|
|
788
|
-
|
|
789
890
|
return ST_CONTINUE;
|
|
790
891
|
}
|
|
791
892
|
|
|
792
893
|
static heap_record* get_or_create_heap_record(heap_recorder *heap_recorder, ddog_prof_Slice_Location locations) {
|
|
793
|
-
//
|
|
794
|
-
|
|
795
|
-
// NOTE: If we end up creating a new record, we'll create a heap-allocated key we own and use that for storage
|
|
796
|
-
// instead of this one.
|
|
797
|
-
heap_record_key lookup_key = (heap_record_key) {
|
|
798
|
-
.type = LOCATION_SLICE,
|
|
799
|
-
.location_slice = &locations,
|
|
800
|
-
};
|
|
894
|
+
// See note on "heap_records" definition for why we keep this map.
|
|
895
|
+
heap_record *stack = heap_record_new(heap_recorder, locations);
|
|
801
896
|
|
|
802
|
-
heap_record *
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
}
|
|
807
|
-
st_update(heap_recorder->heap_records, (st_data_t) &lookup_key, update_heap_record_entry_with_new_allocation, (st_data_t) &update_data);
|
|
897
|
+
heap_record *new_or_existing_record = NULL; // Will be set inside update_heap_record_entry_with_new_allocation
|
|
898
|
+
bool existing = st_update(heap_recorder->heap_records, (st_data_t) stack, update_heap_record_entry_with_new_allocation, (st_data_t) &new_or_existing_record);
|
|
899
|
+
if (existing) {
|
|
900
|
+
heap_record_free(heap_recorder, stack, true);
|
|
901
|
+
}
|
|
808
902
|
|
|
809
|
-
return
|
|
903
|
+
return new_or_existing_record;
|
|
810
904
|
}
|
|
811
905
|
|
|
812
906
|
static void cleanup_heap_record_if_unused(heap_recorder *heap_recorder, heap_record *heap_record) {
|
|
@@ -815,18 +909,10 @@ static void cleanup_heap_record_if_unused(heap_recorder *heap_recorder, heap_rec
|
|
|
815
909
|
return;
|
|
816
910
|
}
|
|
817
911
|
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
.heap_stack = heap_record->stack,
|
|
821
|
-
};
|
|
822
|
-
// We need to access the deleted key to free it since we gave ownership of the keys to the hash.
|
|
823
|
-
// st_delete will change this pointer to point to the removed key if one is found.
|
|
824
|
-
heap_record_key *deleted_key = &heap_key;
|
|
825
|
-
if (!st_delete(heap_recorder->heap_records, (st_data_t*) &deleted_key, NULL)) {
|
|
826
|
-
rb_raise(rb_eRuntimeError, "Attempted to cleanup an untracked heap_record");
|
|
912
|
+
if (!st_delete(heap_recorder->heap_records, (st_data_t*) &heap_record, NULL)) {
|
|
913
|
+
raise_error(rb_eRuntimeError, "Attempted to cleanup an untracked heap_record");
|
|
827
914
|
};
|
|
828
|
-
|
|
829
|
-
heap_record_free(heap_record);
|
|
915
|
+
heap_record_free(heap_recorder, heap_record, true);
|
|
830
916
|
}
|
|
831
917
|
|
|
832
918
|
static void on_committed_object_record_cleanup(heap_recorder *heap_recorder, object_record *record) {
|
|
@@ -834,68 +920,56 @@ static void on_committed_object_record_cleanup(heap_recorder *heap_recorder, obj
|
|
|
834
920
|
// (See PROF-10656 Datadog-internal for details). Just in case, I've sprinkled a bunch of NULL tests in this function for now.
|
|
835
921
|
// Once we figure out the issue we can get rid of them again.
|
|
836
922
|
|
|
837
|
-
if (heap_recorder == NULL)
|
|
838
|
-
if (heap_recorder->heap_records == NULL)
|
|
839
|
-
if (record == NULL)
|
|
923
|
+
if (heap_recorder == NULL) raise_error(rb_eRuntimeError, "heap_recorder was NULL in on_committed_object_record_cleanup");
|
|
924
|
+
if (heap_recorder->heap_records == NULL) raise_error(rb_eRuntimeError, "heap_recorder->heap_records was NULL in on_committed_object_record_cleanup");
|
|
925
|
+
if (record == NULL) raise_error(rb_eRuntimeError, "record was NULL in on_committed_object_record_cleanup");
|
|
840
926
|
|
|
841
927
|
// Starting with the associated heap record. There will now be one less tracked object pointing to it
|
|
842
928
|
heap_record *heap_record = record->heap_record;
|
|
843
929
|
|
|
844
|
-
if (heap_record == NULL)
|
|
845
|
-
if (heap_record->stack == NULL) rb_raise(rb_eRuntimeError, "heap_record->stack was NULL in on_committed_object_record_cleanup");
|
|
930
|
+
if (heap_record == NULL) raise_error(rb_eRuntimeError, "heap_record was NULL in on_committed_object_record_cleanup");
|
|
846
931
|
|
|
847
932
|
heap_record->num_tracked_objects--;
|
|
848
933
|
|
|
849
934
|
// One less object using this heap record, it may have become unused...
|
|
850
935
|
cleanup_heap_record_if_unused(heap_recorder, heap_record);
|
|
851
936
|
|
|
852
|
-
object_record_free(record);
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
// ===============
|
|
856
|
-
// Heap Record API
|
|
857
|
-
// ===============
|
|
858
|
-
heap_record* heap_record_new(heap_stack *stack) {
|
|
859
|
-
heap_record *record = ruby_xcalloc(1, sizeof(heap_record));
|
|
860
|
-
record->num_tracked_objects = 0;
|
|
861
|
-
record->stack = stack;
|
|
862
|
-
return record;
|
|
863
|
-
}
|
|
864
|
-
|
|
865
|
-
void heap_record_free(heap_record *record) {
|
|
866
|
-
heap_stack_free(record->stack);
|
|
867
|
-
ruby_xfree(record);
|
|
937
|
+
object_record_free(heap_recorder, record, true);
|
|
868
938
|
}
|
|
869
939
|
|
|
870
|
-
|
|
871
940
|
// =================
|
|
872
941
|
// Object Record API
|
|
873
942
|
// =================
|
|
874
943
|
object_record* object_record_new(long obj_id, heap_record *heap_record, live_object_data object_data) {
|
|
875
|
-
object_record *record =
|
|
944
|
+
object_record *record = calloc(1, sizeof(object_record)); // See "note on calloc vs ruby_xcalloc use" above
|
|
876
945
|
record->obj_id = obj_id;
|
|
877
946
|
record->heap_record = heap_record;
|
|
878
947
|
record->object_data = object_data;
|
|
879
948
|
return record;
|
|
880
949
|
}
|
|
881
950
|
|
|
882
|
-
void object_record_free(object_record *record) {
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
951
|
+
void object_record_free(heap_recorder *recorder, object_record *record, bool should_unintern) {
|
|
952
|
+
// When tearing down the whole recorder state, we skip uninterning as it's not needed (the managed
|
|
953
|
+
// string table is going to be destroyed anyway) and if there's any failures we can't raise
|
|
954
|
+
// in the middle of a dfree callback.
|
|
955
|
+
if (should_unintern) unintern_or_raise(recorder, record->object_data.class);
|
|
956
|
+
|
|
957
|
+
free(record); // See "note on calloc vs ruby_xcalloc use" above
|
|
887
958
|
}
|
|
888
959
|
|
|
889
|
-
VALUE object_record_inspect(object_record *record) {
|
|
890
|
-
heap_frame top_frame = record->heap_record->
|
|
960
|
+
VALUE object_record_inspect(heap_recorder *recorder, object_record *record) {
|
|
961
|
+
heap_frame top_frame = record->heap_record->frames[0];
|
|
962
|
+
VALUE filename = get_ruby_string_or_raise(recorder, top_frame.filename);
|
|
891
963
|
live_object_data object_data = record->object_data;
|
|
892
|
-
|
|
893
|
-
|
|
964
|
+
|
|
965
|
+
VALUE inspect = rb_sprintf("obj_id=%ld weight=%d size=%zu location=%"PRIsVALUE":%d alloc_gen=%zu gen_age=%zu frozen=%d ",
|
|
966
|
+
record->obj_id, object_data.weight, object_data.size, filename,
|
|
894
967
|
(int) top_frame.line, object_data.alloc_gen, object_data.gen_age, object_data.is_frozen);
|
|
895
968
|
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
969
|
+
if (record->object_data.class.value > 0) {
|
|
970
|
+
VALUE class = get_ruby_string_or_raise(recorder, record->object_data.class);
|
|
971
|
+
|
|
972
|
+
rb_str_catf(inspect, "class=%"PRIsVALUE" ", class);
|
|
899
973
|
}
|
|
900
974
|
VALUE ref;
|
|
901
975
|
|
|
@@ -915,223 +989,119 @@ VALUE object_record_inspect(object_record *record) {
|
|
|
915
989
|
}
|
|
916
990
|
|
|
917
991
|
// ==============
|
|
918
|
-
// Heap
|
|
919
|
-
// ==============
|
|
920
|
-
int heap_frame_cmp(heap_frame *f1, heap_frame *f2) {
|
|
921
|
-
int line_diff = (int) (f1->line - f2->line);
|
|
922
|
-
if (line_diff != 0) {
|
|
923
|
-
return line_diff;
|
|
924
|
-
}
|
|
925
|
-
int cmp = strcmp(f1->name, f2->name);
|
|
926
|
-
if (cmp != 0) {
|
|
927
|
-
return cmp;
|
|
928
|
-
}
|
|
929
|
-
return strcmp(f1->filename, f2->filename);
|
|
930
|
-
}
|
|
931
|
-
|
|
932
|
-
// TODO: Research potential performance improvements around hashing stuff here
|
|
933
|
-
// once we have a benchmarking suite.
|
|
934
|
-
// Example: Each call to st_hash is calling murmur_finish and we may want
|
|
935
|
-
// to only finish once per structure, not per field?
|
|
936
|
-
// Example: There may be a more efficient hashing for line that is not the
|
|
937
|
-
// generic st_hash algorithm?
|
|
938
|
-
|
|
939
|
-
// WARN: Must be kept in-sync with ::char_slice_hash
|
|
940
|
-
st_index_t string_hash(char *str, st_index_t seed) {
|
|
941
|
-
return st_hash(str, strlen(str), seed);
|
|
942
|
-
}
|
|
943
|
-
|
|
944
|
-
// WARN: Must be kept in-sync with ::string_hash
|
|
945
|
-
st_index_t char_slice_hash(ddog_CharSlice char_slice, st_index_t seed) {
|
|
946
|
-
return st_hash(char_slice.ptr, char_slice.len, seed);
|
|
947
|
-
}
|
|
948
|
-
|
|
949
|
-
// WARN: Must be kept in-sync with ::ddog_location_hash
|
|
950
|
-
st_index_t heap_frame_hash(heap_frame *frame, st_index_t seed) {
|
|
951
|
-
st_index_t hash = string_hash(frame->name, seed);
|
|
952
|
-
hash = string_hash(frame->filename, hash);
|
|
953
|
-
hash = st_hash(&frame->line, sizeof(frame->line), hash);
|
|
954
|
-
return hash;
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
// WARN: Must be kept in-sync with ::heap_frame_hash
|
|
958
|
-
st_index_t ddog_location_hash(ddog_prof_Location location, st_index_t seed) {
|
|
959
|
-
st_index_t hash = char_slice_hash(location.function.name, seed);
|
|
960
|
-
hash = char_slice_hash(location.function.filename, hash);
|
|
961
|
-
// Convert ddog_prof line type to the same type we use for our heap_frames to
|
|
962
|
-
// ensure we have compatible hashes
|
|
963
|
-
int32_t line_as_int32 = (int32_t) location.line;
|
|
964
|
-
hash = st_hash(&line_as_int32, sizeof(line_as_int32), hash);
|
|
965
|
-
return hash;
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
// ==============
|
|
969
|
-
// Heap Stack API
|
|
992
|
+
// Heap Record API
|
|
970
993
|
// ==============
|
|
971
|
-
|
|
994
|
+
heap_record* heap_record_new(heap_recorder *recorder, ddog_prof_Slice_Location locations) {
|
|
972
995
|
uint16_t frames_len = locations.len;
|
|
973
996
|
if (frames_len > MAX_FRAMES_LIMIT) {
|
|
974
|
-
// This
|
|
975
|
-
|
|
976
|
-
// be safe since only allocate with the GVL anyway.
|
|
977
|
-
rb_raise(rb_eRuntimeError, "Found stack with more than %d frames (%d)", MAX_FRAMES_LIMIT, frames_len);
|
|
997
|
+
// This is not expected as MAX_FRAMES_LIMIT is shared with the stacktrace construction mechanism
|
|
998
|
+
raise_error(rb_eRuntimeError, "Found stack with more than %d frames (%d)", MAX_FRAMES_LIMIT, frames_len);
|
|
978
999
|
}
|
|
979
|
-
|
|
1000
|
+
heap_record *stack = calloc(1, sizeof(heap_record) + frames_len * sizeof(heap_frame)); // See "note on calloc vs ruby_xcalloc use" above
|
|
1001
|
+
stack->num_tracked_objects = 0;
|
|
980
1002
|
stack->frames_len = frames_len;
|
|
1003
|
+
|
|
1004
|
+
// Intern all these strings...
|
|
1005
|
+
ddog_CharSlice *strings = recorder->reusable_char_slices;
|
|
1006
|
+
// Put all the char slices in the same array; we'll pull them out in the same order from the ids array
|
|
981
1007
|
for (uint16_t i = 0; i < stack->frames_len; i++) {
|
|
982
1008
|
const ddog_prof_Location *location = &locations.ptr[i];
|
|
1009
|
+
strings[i] = location->function.filename;
|
|
1010
|
+
strings[i + stack->frames_len] = location->function.name;
|
|
1011
|
+
}
|
|
1012
|
+
intern_all_or_raise(recorder->string_storage, (ddog_prof_Slice_CharSlice) { .ptr = strings, .len = stack->frames_len * 2 }, recorder->reusable_ids, stack->frames_len * 2);
|
|
1013
|
+
|
|
1014
|
+
// ...and record them for later use
|
|
1015
|
+
for (uint16_t i = 0; i < stack->frames_len; i++) {
|
|
983
1016
|
stack->frames[i] = (heap_frame) {
|
|
984
|
-
.
|
|
985
|
-
.
|
|
1017
|
+
.filename = recorder->reusable_ids[i],
|
|
1018
|
+
.name = recorder->reusable_ids[i + stack->frames_len],
|
|
986
1019
|
// ddog_prof_Location is a int64_t. We don't expect to have to profile files with more than
|
|
987
1020
|
// 2M lines so this cast should be fairly safe?
|
|
988
|
-
.line = (int32_t)
|
|
1021
|
+
.line = (int32_t) locations.ptr[i].line,
|
|
989
1022
|
};
|
|
990
1023
|
}
|
|
991
|
-
return stack;
|
|
992
|
-
}
|
|
993
|
-
|
|
994
|
-
void heap_stack_free(heap_stack *stack) {
|
|
995
|
-
for (uint64_t i = 0; i < stack->frames_len; i++) {
|
|
996
|
-
heap_frame *frame = &stack->frames[i];
|
|
997
|
-
ruby_xfree(frame->name);
|
|
998
|
-
ruby_xfree(frame->filename);
|
|
999
|
-
}
|
|
1000
|
-
ruby_xfree(stack);
|
|
1001
|
-
}
|
|
1002
1024
|
|
|
1003
|
-
|
|
1004
|
-
st_index_t heap_stack_hash(heap_stack *stack, st_index_t seed) {
|
|
1005
|
-
st_index_t hash = seed;
|
|
1006
|
-
for (uint64_t i = 0; i < stack->frames_len; i++) {
|
|
1007
|
-
hash = heap_frame_hash(&stack->frames[i], hash);
|
|
1008
|
-
}
|
|
1009
|
-
return hash;
|
|
1025
|
+
return stack;
|
|
1010
1026
|
}
|
|
1011
1027
|
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1028
|
+
void heap_record_free(heap_recorder *recorder, heap_record *stack, bool should_unintern) {
|
|
1029
|
+
// When tearing down the whole recorder state, we skip uninterning as it's not needed (the managed
|
|
1030
|
+
// string table is going to be destroyed anyway) and if there's any failures we can't raise
|
|
1031
|
+
// in the middle of a dfree callback.
|
|
1032
|
+
if (should_unintern) {
|
|
1033
|
+
ddog_prof_ManagedStringId *ids = recorder->reusable_ids;
|
|
1034
|
+
|
|
1035
|
+
// Put all the ids in the same array; doesn't really matter the order
|
|
1036
|
+
for (u_int16_t i = 0; i < stack->frames_len; i++) {
|
|
1037
|
+
ids[i] = stack->frames[i].filename;
|
|
1038
|
+
ids[i + stack->frames_len] = stack->frames[i].name;
|
|
1039
|
+
}
|
|
1040
|
+
unintern_all_or_raise(recorder, (ddog_prof_Slice_ManagedStringId) { .ptr = ids, .len = stack->frames_len * 2 });
|
|
1017
1041
|
}
|
|
1018
|
-
return hash;
|
|
1019
|
-
}
|
|
1020
1042
|
|
|
1021
|
-
//
|
|
1022
|
-
// Heap Record Key API
|
|
1023
|
-
// ===================
|
|
1024
|
-
heap_record_key* heap_record_key_new(heap_stack *stack) {
|
|
1025
|
-
heap_record_key *key = ruby_xmalloc(sizeof(heap_record_key));
|
|
1026
|
-
key->type = HEAP_STACK;
|
|
1027
|
-
key->heap_stack = stack;
|
|
1028
|
-
return key;
|
|
1043
|
+
free(stack); // See "note on calloc vs ruby_xcalloc use" above
|
|
1029
1044
|
}
|
|
1030
1045
|
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1046
|
+
// The entire stack is represented by ids (name, filename) and lines (integers) so we can treat is as just
|
|
1047
|
+
// a big string of bytes and compare it all in one go.
|
|
1048
|
+
int heap_record_cmp_st(st_data_t key1, st_data_t key2) {
|
|
1049
|
+
heap_record *stack1 = (heap_record*) key1;
|
|
1050
|
+
heap_record *stack2 = (heap_record*) key2;
|
|
1034
1051
|
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
return key->heap_stack->frames_len;
|
|
1052
|
+
if (stack1->frames_len != stack2->frames_len) {
|
|
1053
|
+
return ((int) stack1->frames_len) - ((int) stack2->frames_len);
|
|
1038
1054
|
} else {
|
|
1039
|
-
return
|
|
1055
|
+
return memcmp(stack1->frames, stack2->frames, stack1->frames_len * sizeof(heap_frame));
|
|
1040
1056
|
}
|
|
1041
1057
|
}
|
|
1042
1058
|
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
return key->heap_stack->frames[entry_i].line;
|
|
1046
|
-
} else {
|
|
1047
|
-
return key->location_slice->ptr[entry_i].line;
|
|
1048
|
-
}
|
|
1049
|
-
}
|
|
1059
|
+
// Initial seed for hash function, same as Ruby uses
|
|
1060
|
+
#define FNV1_32A_INIT 0x811c9dc5
|
|
1050
1061
|
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
} else {
|
|
1057
|
-
ddog_CharSlice name = key->location_slice->ptr[entry_i].function.name;
|
|
1058
|
-
(*name_ptr) = name.ptr;
|
|
1059
|
-
return name.len;
|
|
1060
|
-
}
|
|
1062
|
+
// The entire stack is represented by ids (name, filename) and lines (integers) so we can treat is as just
|
|
1063
|
+
// a big string of bytes and hash it all in one go.
|
|
1064
|
+
st_index_t heap_record_hash_st(st_data_t key) {
|
|
1065
|
+
heap_record *stack = (heap_record*) key;
|
|
1066
|
+
return st_hash(stack->frames, stack->frames_len * sizeof(heap_frame), FNV1_32A_INIT);
|
|
1061
1067
|
}
|
|
1062
1068
|
|
|
1063
|
-
static
|
|
1064
|
-
if (
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
ddog_CharSlice filename = key->location_slice->ptr[entry_i].function.filename;
|
|
1070
|
-
(*filename_ptr) = filename.ptr;
|
|
1071
|
-
return filename.len;
|
|
1069
|
+
static void unintern_or_raise(heap_recorder *recorder, ddog_prof_ManagedStringId id) {
|
|
1070
|
+
if (id.value == 0) return; // Empty string, nothing to do
|
|
1071
|
+
|
|
1072
|
+
ddog_prof_MaybeError result = ddog_prof_ManagedStringStorage_unintern(recorder->string_storage, id);
|
|
1073
|
+
if (result.tag == DDOG_PROF_OPTION_ERROR_SOME_ERROR) {
|
|
1074
|
+
raise_error(rb_eRuntimeError, "Failed to unintern id: %"PRIsVALUE, get_error_details_and_drop(&result.some));
|
|
1072
1075
|
}
|
|
1073
1076
|
}
|
|
1074
1077
|
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
// Fast path, check if lengths differ
|
|
1080
|
-
size_t key_record1_len = heap_record_key_len(key_record1);
|
|
1081
|
-
size_t key_record2_len = heap_record_key_len(key_record2);
|
|
1082
|
-
|
|
1083
|
-
if (key_record1_len != key_record2_len) {
|
|
1084
|
-
return ((int) key_record1_len) - ((int) key_record2_len);
|
|
1078
|
+
static void unintern_all_or_raise(heap_recorder *recorder, ddog_prof_Slice_ManagedStringId ids) {
|
|
1079
|
+
ddog_prof_MaybeError result = ddog_prof_ManagedStringStorage_unintern_all(recorder->string_storage, ids);
|
|
1080
|
+
if (result.tag == DDOG_PROF_OPTION_ERROR_SOME_ERROR) {
|
|
1081
|
+
raise_error(rb_eRuntimeError, "Failed to unintern_all: %"PRIsVALUE, get_error_details_and_drop(&result.some));
|
|
1085
1082
|
}
|
|
1083
|
+
}
|
|
1086
1084
|
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
size_t line2 = heap_record_key_entry_line(key_record2, i);
|
|
1092
|
-
if (line1 != line2) {
|
|
1093
|
-
return ((int) line1) - ((int)line2);
|
|
1094
|
-
}
|
|
1095
|
-
|
|
1096
|
-
// Then come names, they are usually smaller than filenames
|
|
1097
|
-
const char *name1, *name2;
|
|
1098
|
-
size_t name1_len = heap_record_key_entry_name(key_record1, i, &name1);
|
|
1099
|
-
size_t name2_len = heap_record_key_entry_name(key_record2, i, &name2);
|
|
1100
|
-
if (name1_len != name2_len) {
|
|
1101
|
-
return ((int) name1_len) - ((int) name2_len);
|
|
1102
|
-
}
|
|
1103
|
-
int name_cmp_result = strncmp(name1, name2, name1_len);
|
|
1104
|
-
if (name_cmp_result != 0) {
|
|
1105
|
-
return name_cmp_result;
|
|
1106
|
-
}
|
|
1107
|
-
|
|
1108
|
-
// Then come filenames
|
|
1109
|
-
const char *filename1, *filename2;
|
|
1110
|
-
int64_t filename1_len = heap_record_key_entry_filename(key_record1, i, &filename1);
|
|
1111
|
-
int64_t filename2_len = heap_record_key_entry_filename(key_record2, i, &filename2);
|
|
1112
|
-
if (filename1_len != filename2_len) {
|
|
1113
|
-
return ((int) filename1_len) - ((int) filename2_len);
|
|
1114
|
-
}
|
|
1115
|
-
int filename_cmp_result = strncmp(filename1, filename2, filename1_len);
|
|
1116
|
-
if (filename_cmp_result != 0) {
|
|
1117
|
-
return filename_cmp_result;
|
|
1118
|
-
}
|
|
1085
|
+
static VALUE get_ruby_string_or_raise(heap_recorder *recorder, ddog_prof_ManagedStringId id) {
|
|
1086
|
+
ddog_StringWrapperResult get_string_result = ddog_prof_ManagedStringStorage_get_string(recorder->string_storage, id);
|
|
1087
|
+
if (get_string_result.tag == DDOG_STRING_WRAPPER_RESULT_ERR) {
|
|
1088
|
+
raise_error(rb_eRuntimeError, "Failed to get string: %"PRIsVALUE, get_error_details_and_drop(&get_string_result.err));
|
|
1119
1089
|
}
|
|
1090
|
+
VALUE ruby_string = ruby_string_from_vec_u8(get_string_result.ok.message);
|
|
1091
|
+
ddog_StringWrapper_drop((ddog_StringWrapper *) &get_string_result.ok);
|
|
1120
1092
|
|
|
1121
|
-
|
|
1122
|
-
return 0;
|
|
1093
|
+
return ruby_string;
|
|
1123
1094
|
}
|
|
1124
1095
|
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
return heap_stack_hash(record_key->heap_stack, FNV1_32A_INIT);
|
|
1132
|
-
} else {
|
|
1133
|
-
return ddog_location_slice_hash(*record_key->location_slice, FNV1_32A_INIT);
|
|
1096
|
+
static long obj_id_or_fail(VALUE obj) {
|
|
1097
|
+
VALUE ruby_obj_id = rb_obj_id(obj);
|
|
1098
|
+
if (!FIXNUM_P(ruby_obj_id)) {
|
|
1099
|
+
// Bignum object ids indicate the fixnum range is exhausted - all future IDs will also be bignums.
|
|
1100
|
+
// Heap profiling cannot continue.
|
|
1101
|
+
raise_error(rb_eRuntimeError, "Heap profiling: bignum object id detected. Heap profiling cannot continue.");
|
|
1134
1102
|
}
|
|
1103
|
+
|
|
1104
|
+
return FIX2LONG(ruby_obj_id);
|
|
1135
1105
|
}
|
|
1136
1106
|
|
|
1137
1107
|
static inline double ewma_stat(double previous, double current) {
|
|
@@ -1141,7 +1111,7 @@ static inline double ewma_stat(double previous, double current) {
|
|
|
1141
1111
|
|
|
1142
1112
|
VALUE heap_recorder_testonly_is_object_recorded(heap_recorder *heap_recorder, VALUE obj_id) {
|
|
1143
1113
|
if (heap_recorder == NULL) {
|
|
1144
|
-
|
|
1114
|
+
raise_error(rb_eArgError, "heap_recorder is NULL");
|
|
1145
1115
|
}
|
|
1146
1116
|
|
|
1147
1117
|
// Check if object records contains an object with this object_id
|
|
@@ -1150,8 +1120,28 @@ VALUE heap_recorder_testonly_is_object_recorded(heap_recorder *heap_recorder, VA
|
|
|
1150
1120
|
|
|
1151
1121
|
void heap_recorder_testonly_reset_last_update(heap_recorder *heap_recorder) {
|
|
1152
1122
|
if (heap_recorder == NULL) {
|
|
1153
|
-
|
|
1123
|
+
raise_error(rb_eArgError, "heap_recorder is NULL");
|
|
1154
1124
|
}
|
|
1155
1125
|
|
|
1156
1126
|
heap_recorder->last_update_ns = 0;
|
|
1157
1127
|
}
|
|
1128
|
+
|
|
1129
|
+
void heap_recorder_testonly_benchmark_intern(heap_recorder *heap_recorder, ddog_CharSlice string, int times, bool use_all) {
|
|
1130
|
+
if (heap_recorder == NULL) raise_error(rb_eArgError, "heap profiling must be enabled");
|
|
1131
|
+
if (times > REUSABLE_FRAME_DETAILS_SIZE) raise_error(rb_eArgError, "times cannot be > than REUSABLE_FRAME_DETAILS_SIZE");
|
|
1132
|
+
|
|
1133
|
+
if (use_all) {
|
|
1134
|
+
ddog_CharSlice *strings = heap_recorder->reusable_char_slices;
|
|
1135
|
+
|
|
1136
|
+
for (int i = 0; i < times; i++) strings[i] = string;
|
|
1137
|
+
|
|
1138
|
+
intern_all_or_raise(
|
|
1139
|
+
heap_recorder->string_storage,
|
|
1140
|
+
(ddog_prof_Slice_CharSlice) { .ptr = strings, .len = times },
|
|
1141
|
+
heap_recorder->reusable_ids,
|
|
1142
|
+
times
|
|
1143
|
+
);
|
|
1144
|
+
} else {
|
|
1145
|
+
for (int i = 0; i < times; i++) intern_or_raise(heap_recorder->string_storage, string);
|
|
1146
|
+
}
|
|
1147
|
+
}
|