datadog 2.7.1 → 2.17.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 +310 -1
- data/ext/datadog_profiling_native_extension/clock_id.h +2 -2
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +66 -56
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +1 -1
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h +1 -1
- data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +16 -16
- data/ext/datadog_profiling_native_extension/collectors_stack.c +10 -10
- data/ext/datadog_profiling_native_extension/collectors_stack.h +2 -2
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +314 -145
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +1 -4
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +10 -0
- data/ext/datadog_profiling_native_extension/encoded_profile.c +79 -0
- data/ext/datadog_profiling_native_extension/encoded_profile.h +8 -0
- data/ext/datadog_profiling_native_extension/extconf.rb +7 -8
- data/ext/datadog_profiling_native_extension/gvl_profiling_helper.c +2 -0
- data/ext/datadog_profiling_native_extension/gvl_profiling_helper.h +0 -8
- data/ext/datadog_profiling_native_extension/heap_recorder.c +61 -174
- data/ext/datadog_profiling_native_extension/heap_recorder.h +2 -2
- data/ext/datadog_profiling_native_extension/http_transport.c +64 -98
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +68 -1
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +10 -1
- data/ext/datadog_profiling_native_extension/profiling.c +19 -8
- data/ext/datadog_profiling_native_extension/ruby_helpers.c +8 -8
- data/ext/datadog_profiling_native_extension/stack_recorder.c +84 -131
- data/ext/datadog_profiling_native_extension/stack_recorder.h +2 -2
- data/ext/datadog_profiling_native_extension/time_helpers.h +1 -1
- data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.c +47 -0
- data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.h +31 -0
- data/ext/libdatadog_api/crashtracker.c +17 -15
- data/ext/libdatadog_api/crashtracker.h +5 -0
- data/ext/libdatadog_api/datadog_ruby_common.c +1 -4
- data/ext/libdatadog_api/datadog_ruby_common.h +10 -0
- data/ext/libdatadog_api/init.c +15 -0
- data/ext/libdatadog_api/library_config.c +122 -0
- data/ext/libdatadog_api/library_config.h +19 -0
- data/ext/libdatadog_api/macos_development.md +3 -3
- data/ext/libdatadog_api/process_discovery.c +117 -0
- data/ext/libdatadog_api/process_discovery.h +5 -0
- data/ext/libdatadog_extconf_helpers.rb +1 -1
- 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/lru_cache.rb +49 -0
- data/lib/datadog/appsec/api_security.rb +9 -0
- data/lib/datadog/appsec/assets/waf_rules/README.md +50 -5
- data/lib/datadog/appsec/assets/waf_rules/processors.json +239 -10
- data/lib/datadog/appsec/assets/waf_rules/recommended.json +355 -157
- data/lib/datadog/appsec/assets/waf_rules/scanners.json +926 -17
- data/lib/datadog/appsec/assets/waf_rules/strict.json +62 -32
- data/lib/datadog/appsec/autoload.rb +1 -1
- data/lib/datadog/appsec/component.rb +41 -33
- data/lib/datadog/appsec/compressed_json.rb +40 -0
- data/lib/datadog/appsec/configuration/settings.rb +152 -25
- data/lib/datadog/appsec/context.rb +74 -0
- data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +92 -0
- data/lib/datadog/appsec/contrib/active_record/integration.rb +41 -0
- data/lib/datadog/appsec/contrib/active_record/patcher.rb +101 -0
- data/lib/datadog/appsec/contrib/auto_instrument.rb +1 -1
- 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 +1 -2
- data/lib/datadog/appsec/contrib/devise/patcher.rb +33 -25
- data/lib/datadog/appsec/contrib/devise/patches/signin_tracking_patch.rb +102 -0
- data/lib/datadog/appsec/contrib/devise/patches/signup_tracking_patch.rb +69 -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 +106 -0
- data/lib/datadog/appsec/contrib/excon/integration.rb +41 -0
- data/lib/datadog/appsec/contrib/excon/patcher.rb +28 -0
- data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +42 -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 +41 -0
- data/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +1 -7
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +17 -30
- data/lib/datadog/appsec/contrib/graphql/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/graphql/patcher.rb +0 -3
- data/lib/datadog/appsec/contrib/rack/ext.rb +34 -0
- data/lib/datadog/appsec/contrib/rack/gateway/response.rb +3 -3
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +78 -98
- data/lib/datadog/appsec/contrib/rack/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/rack/patcher.rb +0 -3
- data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +10 -11
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +52 -68
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +16 -33
- data/lib/datadog/appsec/contrib/rails/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/rails/patcher.rb +25 -38
- data/lib/datadog/appsec/contrib/rest_client/integration.rb +45 -0
- data/lib/datadog/appsec/contrib/rest_client/patcher.rb +28 -0
- data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +38 -0
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +31 -68
- data/lib/datadog/appsec/contrib/sinatra/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/sinatra/patcher.rb +5 -31
- data/lib/datadog/appsec/event.rb +96 -135
- data/lib/datadog/appsec/ext.rb +12 -3
- data/lib/datadog/appsec/instrumentation/gateway/argument.rb +7 -2
- data/lib/datadog/appsec/instrumentation/gateway/middleware.rb +24 -0
- data/lib/datadog/appsec/instrumentation/gateway.rb +17 -22
- data/lib/datadog/appsec/metrics/collector.rb +38 -0
- data/lib/datadog/appsec/metrics/exporter.rb +35 -0
- data/lib/datadog/appsec/metrics/telemetry.rb +23 -0
- data/lib/datadog/appsec/metrics.rb +13 -0
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +52 -32
- data/lib/datadog/appsec/processor/rule_loader.rb +26 -31
- data/lib/datadog/appsec/processor/rule_merger.rb +7 -6
- data/lib/datadog/appsec/processor.rb +5 -4
- data/lib/datadog/appsec/remote.rb +26 -12
- data/lib/datadog/appsec/response.rb +19 -85
- data/lib/datadog/appsec/security_engine/result.rb +67 -0
- data/lib/datadog/appsec/security_engine/runner.rb +88 -0
- data/lib/datadog/appsec/security_engine.rb +9 -0
- data/lib/datadog/appsec/security_event.rb +39 -0
- data/lib/datadog/appsec/utils.rb +0 -2
- data/lib/datadog/appsec.rb +23 -10
- data/lib/datadog/auto_instrument.rb +3 -0
- data/lib/datadog/core/buffer/random.rb +18 -2
- data/lib/datadog/core/configuration/agent_settings_resolver.rb +42 -14
- data/lib/datadog/core/configuration/agentless_settings_resolver.rb +176 -0
- data/lib/datadog/core/configuration/components.rb +76 -32
- data/lib/datadog/core/configuration/components_state.rb +23 -0
- data/lib/datadog/core/configuration/ext.rb +5 -1
- data/lib/datadog/core/configuration/option.rb +79 -43
- data/lib/datadog/core/configuration/option_definition.rb +6 -4
- data/lib/datadog/core/configuration/options.rb +3 -3
- data/lib/datadog/core/configuration/settings.rb +100 -41
- data/lib/datadog/core/configuration/stable_config.rb +23 -0
- data/lib/datadog/core/configuration.rb +43 -11
- data/lib/datadog/{tracing → core}/contrib/rails/utils.rb +1 -3
- data/lib/datadog/core/crashtracking/component.rb +4 -13
- data/lib/datadog/core/diagnostics/environment_logger.rb +1 -1
- data/lib/datadog/core/encoding.rb +17 -1
- data/lib/datadog/core/environment/agent_info.rb +78 -0
- data/lib/datadog/core/environment/cgroup.rb +10 -12
- data/lib/datadog/core/environment/container.rb +38 -40
- data/lib/datadog/core/environment/ext.rb +6 -6
- data/lib/datadog/core/environment/git.rb +1 -0
- data/lib/datadog/core/environment/identity.rb +3 -3
- data/lib/datadog/core/environment/platform.rb +3 -3
- data/lib/datadog/core/environment/variable_helpers.rb +1 -1
- data/lib/datadog/core/error.rb +11 -9
- data/lib/datadog/core/logger.rb +2 -2
- data/lib/datadog/core/metrics/client.rb +27 -27
- data/lib/datadog/core/metrics/logging.rb +5 -5
- data/lib/datadog/core/process_discovery.rb +32 -0
- data/lib/datadog/core/rate_limiter.rb +4 -2
- data/lib/datadog/core/remote/client/capabilities.rb +6 -0
- data/lib/datadog/core/remote/client.rb +107 -92
- data/lib/datadog/core/remote/component.rb +18 -19
- data/lib/datadog/core/remote/configuration/digest.rb +7 -7
- data/lib/datadog/core/remote/configuration/path.rb +1 -1
- data/lib/datadog/core/remote/configuration/repository.rb +2 -1
- data/lib/datadog/core/remote/negotiation.rb +9 -9
- data/lib/datadog/core/remote/transport/config.rb +4 -3
- data/lib/datadog/core/remote/transport/http/api.rb +13 -18
- data/lib/datadog/core/remote/transport/http/client.rb +5 -4
- data/lib/datadog/core/remote/transport/http/config.rb +27 -55
- data/lib/datadog/core/remote/transport/http/negotiation.rb +8 -51
- data/lib/datadog/core/remote/transport/http.rb +25 -94
- data/lib/datadog/core/remote/transport/negotiation.rb +17 -4
- data/lib/datadog/core/remote/worker.rb +10 -7
- data/lib/datadog/core/runtime/metrics.rb +12 -5
- data/lib/datadog/core/telemetry/component.rb +84 -49
- data/lib/datadog/core/telemetry/emitter.rb +23 -11
- 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_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 +179 -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 +43 -0
- data/lib/datadog/core/telemetry/event.rb +17 -383
- data/lib/datadog/core/telemetry/ext.rb +1 -0
- data/lib/datadog/core/telemetry/http/adapters/net.rb +12 -97
- data/lib/datadog/core/telemetry/logger.rb +1 -1
- data/lib/datadog/core/telemetry/logging.rb +2 -2
- data/lib/datadog/core/telemetry/metric.rb +28 -6
- data/lib/datadog/core/telemetry/request.rb +4 -4
- data/lib/datadog/core/telemetry/transport/http/api.rb +43 -0
- data/lib/datadog/core/telemetry/transport/http/client.rb +49 -0
- data/lib/datadog/core/telemetry/transport/http/telemetry.rb +92 -0
- data/lib/datadog/core/telemetry/transport/http.rb +63 -0
- data/lib/datadog/core/telemetry/transport/telemetry.rb +51 -0
- data/lib/datadog/core/telemetry/worker.rb +128 -25
- data/lib/datadog/core/transport/http/adapters/test.rb +2 -1
- data/lib/datadog/core/transport/http/adapters/unix_socket.rb +1 -1
- data/lib/datadog/{tracing → core}/transport/http/api/instance.rb +18 -1
- data/lib/datadog/core/transport/http/api/spec.rb +36 -0
- data/lib/datadog/{tracing → core}/transport/http/builder.rb +53 -31
- data/lib/datadog/core/transport/http.rb +75 -0
- data/lib/datadog/core/transport/response.rb +4 -0
- data/lib/datadog/core/utils/at_fork_monkey_patch.rb +6 -6
- data/lib/datadog/core/utils/duration.rb +32 -32
- data/lib/datadog/core/utils/forking.rb +2 -2
- data/lib/datadog/core/utils/network.rb +6 -6
- data/lib/datadog/core/utils/only_once_successful.rb +16 -5
- data/lib/datadog/core/utils/time.rb +20 -0
- data/lib/datadog/core/utils/truncation.rb +21 -0
- 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 +29 -12
- data/lib/datadog/core/workers/interval_loop.rb +12 -1
- data/lib/datadog/core/workers/runtime_metrics.rb +2 -2
- data/lib/datadog/core.rb +8 -0
- data/lib/datadog/di/base.rb +115 -0
- data/lib/datadog/di/boot.rb +34 -0
- data/lib/datadog/di/code_tracker.rb +26 -15
- data/lib/datadog/di/component.rb +23 -14
- data/lib/datadog/di/configuration/settings.rb +25 -1
- data/lib/datadog/di/contrib/active_record.rb +1 -0
- data/lib/datadog/di/contrib/railtie.rb +15 -0
- data/lib/datadog/di/contrib.rb +28 -0
- data/lib/datadog/di/error.rb +5 -0
- data/lib/datadog/di/instrumenter.rb +111 -20
- data/lib/datadog/di/logger.rb +30 -0
- data/lib/datadog/di/preload.rb +18 -0
- data/lib/datadog/di/probe.rb +14 -7
- data/lib/datadog/di/probe_builder.rb +1 -0
- data/lib/datadog/di/probe_manager.rb +11 -5
- data/lib/datadog/di/probe_notification_builder.rb +34 -8
- data/lib/datadog/di/probe_notifier_worker.rb +52 -26
- data/lib/datadog/di/redactor.rb +0 -1
- data/lib/datadog/di/remote.rb +147 -0
- data/lib/datadog/di/serializer.rb +14 -7
- data/lib/datadog/di/transport/diagnostics.rb +62 -0
- data/lib/datadog/di/transport/http/api.rb +42 -0
- data/lib/datadog/di/transport/http/client.rb +47 -0
- data/lib/datadog/di/transport/http/diagnostics.rb +65 -0
- data/lib/datadog/di/transport/http/input.rb +67 -0
- data/lib/datadog/di/transport/http.rb +57 -0
- data/lib/datadog/di/transport/input.rb +62 -0
- data/lib/datadog/di/utils.rb +103 -0
- data/lib/datadog/di.rb +14 -76
- data/lib/datadog/error_tracking/collector.rb +87 -0
- data/lib/datadog/error_tracking/component.rb +167 -0
- data/lib/datadog/error_tracking/configuration/settings.rb +63 -0
- data/lib/datadog/error_tracking/configuration.rb +11 -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.rb +15 -3
- data/lib/datadog/kit/identity.rb +9 -5
- data/lib/datadog/opentelemetry/api/baggage.rb +90 -0
- data/lib/datadog/opentelemetry/api/baggage.rbs +26 -0
- data/lib/datadog/opentelemetry/api/context.rb +16 -2
- data/lib/datadog/opentelemetry/sdk/trace/span.rb +1 -1
- data/lib/datadog/opentelemetry.rb +2 -1
- data/lib/datadog/profiling/collectors/code_provenance.rb +1 -1
- data/lib/datadog/profiling/collectors/info.rb +3 -0
- data/lib/datadog/profiling/collectors/thread_context.rb +1 -1
- data/lib/datadog/profiling/component.rb +60 -76
- data/lib/datadog/profiling/encoded_profile.rb +11 -0
- data/lib/datadog/profiling/exporter.rb +3 -4
- data/lib/datadog/profiling/ext.rb +0 -2
- data/lib/datadog/profiling/flush.rb +5 -8
- data/lib/datadog/profiling/http_transport.rb +6 -85
- data/lib/datadog/profiling/load_native_extension.rb +1 -33
- data/lib/datadog/profiling/scheduler.rb +8 -1
- data/lib/datadog/profiling/stack_recorder.rb +4 -4
- data/lib/datadog/profiling/tag_builder.rb +1 -5
- data/lib/datadog/profiling.rb +6 -2
- data/lib/datadog/tracing/analytics.rb +1 -1
- data/lib/datadog/tracing/component.rb +16 -12
- data/lib/datadog/tracing/configuration/ext.rb +8 -1
- data/lib/datadog/tracing/configuration/settings.rb +22 -10
- data/lib/datadog/tracing/context_provider.rb +1 -1
- data/lib/datadog/tracing/contrib/action_cable/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/action_mailer/integration.rb +6 -2
- data/lib/datadog/tracing/contrib/action_pack/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/action_view/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/active_job/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/active_record/integration.rb +7 -3
- data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +7 -2
- data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +36 -1
- data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +4 -0
- data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +14 -4
- data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +10 -0
- data/lib/datadog/tracing/contrib/active_support/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/auto_instrument.rb +2 -2
- data/lib/datadog/tracing/contrib/aws/instrumentation.rb +10 -0
- data/lib/datadog/tracing/contrib/aws/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/aws/parsed_context.rb +5 -1
- data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/elasticsearch/configuration/settings.rb +4 -0
- data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +6 -1
- data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +4 -5
- data/lib/datadog/tracing/contrib/excon/middleware.rb +5 -3
- data/lib/datadog/tracing/contrib/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/extensions.rb +29 -3
- data/lib/datadog/tracing/contrib/faraday/middleware.rb +5 -3
- data/lib/datadog/tracing/contrib/graphql/configuration/error_extension_env_parser.rb +21 -0
- data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +11 -0
- data/lib/datadog/tracing/contrib/graphql/ext.rb +5 -0
- data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +102 -11
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +7 -1
- data/lib/datadog/tracing/contrib/grpc/distributed/propagation.rb +3 -0
- data/lib/datadog/tracing/contrib/http/circuit_breaker.rb +0 -15
- data/lib/datadog/tracing/contrib/http/distributed/propagation.rb +4 -1
- data/lib/datadog/tracing/contrib/http/instrumentation.rb +6 -10
- data/lib/datadog/tracing/contrib/http/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +6 -16
- data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +7 -15
- data/lib/datadog/tracing/contrib/httprb/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/kafka/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/karafka/configuration/settings.rb +27 -0
- data/lib/datadog/tracing/contrib/karafka/distributed/propagation.rb +48 -0
- data/lib/datadog/tracing/contrib/karafka/ext.rb +27 -0
- data/lib/datadog/tracing/contrib/karafka/integration.rb +45 -0
- data/lib/datadog/tracing/contrib/karafka/monitor.rb +66 -0
- data/lib/datadog/tracing/contrib/karafka/patcher.rb +71 -0
- data/lib/datadog/tracing/contrib/karafka.rb +37 -0
- data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +8 -0
- data/lib/datadog/tracing/contrib/mongodb/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/mongodb/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +18 -1
- data/lib/datadog/tracing/contrib/opensearch/configuration/settings.rb +17 -0
- data/lib/datadog/tracing/contrib/opensearch/ext.rb +9 -0
- data/lib/datadog/tracing/contrib/opensearch/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/opensearch/patcher.rb +5 -1
- data/lib/datadog/tracing/contrib/patcher.rb +5 -2
- data/lib/datadog/tracing/contrib/presto/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/rack/header_collection.rb +11 -1
- data/lib/datadog/tracing/contrib/rack/integration.rb +2 -2
- data/lib/datadog/tracing/contrib/rack/middlewares.rb +1 -1
- data/lib/datadog/tracing/contrib/rack/request_queue.rb +1 -1
- data/lib/datadog/tracing/contrib/rails/framework.rb +2 -2
- data/lib/datadog/tracing/contrib/rails/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/rest_client/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +5 -3
- data/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +6 -1
- data/lib/datadog/tracing/contrib/sidekiq/distributed/propagation.rb +3 -0
- data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +1 -1
- data/lib/datadog/tracing/contrib/span_attribute_schema.rb +6 -1
- data/lib/datadog/tracing/contrib/support.rb +28 -0
- data/lib/datadog/tracing/contrib.rb +1 -0
- data/lib/datadog/tracing/correlation.rb +9 -2
- data/lib/datadog/tracing/distributed/b3_multi.rb +1 -1
- data/lib/datadog/tracing/distributed/b3_single.rb +1 -1
- data/lib/datadog/tracing/distributed/baggage.rb +131 -0
- data/lib/datadog/tracing/distributed/datadog.rb +4 -2
- data/lib/datadog/tracing/distributed/propagation.rb +25 -4
- data/lib/datadog/tracing/distributed/propagation_policy.rb +42 -0
- data/lib/datadog/tracing/metadata/errors.rb +4 -4
- data/lib/datadog/tracing/metadata/ext.rb +5 -0
- data/lib/datadog/tracing/metadata/metastruct.rb +36 -0
- data/lib/datadog/tracing/metadata/metastruct_tagging.rb +42 -0
- data/lib/datadog/tracing/metadata.rb +2 -0
- data/lib/datadog/tracing/sampling/rate_sampler.rb +2 -1
- data/lib/datadog/tracing/sampling/span/rule.rb +0 -1
- data/lib/datadog/tracing/span.rb +22 -5
- data/lib/datadog/tracing/span_event.rb +124 -4
- data/lib/datadog/tracing/span_operation.rb +52 -16
- data/lib/datadog/tracing/sync_writer.rb +9 -5
- data/lib/datadog/tracing/trace_digest.rb +9 -2
- data/lib/datadog/tracing/trace_operation.rb +44 -24
- data/lib/datadog/tracing/trace_segment.rb +6 -4
- data/lib/datadog/tracing/tracer.rb +60 -12
- data/lib/datadog/tracing/transport/http/api.rb +5 -4
- data/lib/datadog/tracing/transport/http/client.rb +5 -4
- data/lib/datadog/tracing/transport/http/traces.rb +13 -44
- data/lib/datadog/tracing/transport/http.rb +13 -70
- data/lib/datadog/tracing/transport/serializable_trace.rb +31 -7
- data/lib/datadog/tracing/transport/trace_formatter.rb +7 -0
- data/lib/datadog/tracing/transport/traces.rb +47 -13
- data/lib/datadog/tracing/utils.rb +1 -1
- data/lib/datadog/tracing/workers/trace_writer.rb +8 -5
- data/lib/datadog/tracing/workers.rb +5 -4
- data/lib/datadog/tracing/writer.rb +10 -6
- data/lib/datadog/tracing.rb +16 -3
- data/lib/datadog/version.rb +2 -2
- data/lib/datadog.rb +2 -0
- metadata +143 -50
- data/ext/datadog_profiling_loader/datadog_profiling_loader.c +0 -142
- data/ext/datadog_profiling_loader/extconf.rb +0 -60
- 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/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/actions.rb +0 -49
- data/lib/datadog/appsec/processor/context.rb +0 -107
- 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/builder.rb +0 -219
- 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/di/transport.rb +0 -81
- data/lib/datadog/tracing/transport/http/api/spec.rb +0 -19
@@ -29,10 +29,7 @@ VALUE datadog_gem_version(void) {
|
|
29
29
|
}
|
30
30
|
|
31
31
|
static VALUE log_failure_to_process_tag(VALUE err_details) {
|
32
|
-
|
33
|
-
VALUE logger = rb_funcall(datadog_module, rb_intern("logger"), 0);
|
34
|
-
|
35
|
-
return rb_funcall(logger, rb_intern("warn"), 1, rb_sprintf("Failed to convert tag: %"PRIsVALUE, err_details));
|
32
|
+
return log_warning(rb_sprintf("Failed to convert tag: %"PRIsVALUE, err_details));
|
36
33
|
}
|
37
34
|
|
38
35
|
__attribute__((warn_unused_result))
|
@@ -27,6 +27,9 @@
|
|
27
27
|
#define ENFORCE_BOOLEAN(value) \
|
28
28
|
{ if (RB_UNLIKELY(value != Qtrue && value != Qfalse)) raise_unexpected_type(value, ADD_QUOTES(value), "true or false", __FILE__, __LINE__, __func__); }
|
29
29
|
|
30
|
+
#define ENFORCE_TYPED_DATA(value, type) \
|
31
|
+
{ if (RB_UNLIKELY(!rb_typeddata_is_kind_of(value, type))) raise_unexpected_type(value, ADD_QUOTES(value), "TypedData of type " ADD_QUOTES(type), __FILE__, __LINE__, __func__); }
|
32
|
+
|
30
33
|
NORETURN(void raise_unexpected_type(VALUE value, const char *value_name, const char *type_name, const char *file, int line, const char* function_name));
|
31
34
|
|
32
35
|
// Helper to retrieve Datadog::VERSION::STRING
|
@@ -38,6 +41,13 @@ static inline ddog_CharSlice char_slice_from_ruby_string(VALUE string) {
|
|
38
41
|
return char_slice;
|
39
42
|
}
|
40
43
|
|
44
|
+
static inline VALUE log_warning(VALUE warning) {
|
45
|
+
VALUE datadog_module = rb_const_get(rb_cObject, rb_intern("Datadog"));
|
46
|
+
VALUE logger = rb_funcall(datadog_module, rb_intern("logger"), 0);
|
47
|
+
|
48
|
+
return rb_funcall(logger, rb_intern("warn"), 1, warning);
|
49
|
+
}
|
50
|
+
|
41
51
|
__attribute__((warn_unused_result))
|
42
52
|
ddog_Vec_Tag convert_tags(VALUE tags_as_array);
|
43
53
|
|
@@ -0,0 +1,79 @@
|
|
1
|
+
#include "encoded_profile.h"
|
2
|
+
#include "datadog_ruby_common.h"
|
3
|
+
#include "libdatadog_helpers.h"
|
4
|
+
|
5
|
+
// This class exists to wrap a ddog_prof_EncodedProfile into a Ruby object
|
6
|
+
// This file implements the native bits of the Datadog::Profiling::EncodedProfile class
|
7
|
+
|
8
|
+
static void encoded_profile_typed_data_free(void *state_ptr);
|
9
|
+
static VALUE _native_bytes(VALUE self);
|
10
|
+
|
11
|
+
static VALUE encoded_profile_class = Qnil;
|
12
|
+
|
13
|
+
void encoded_profile_init(VALUE profiling_module) {
|
14
|
+
encoded_profile_class = rb_define_class_under(profiling_module, "EncodedProfile", rb_cObject);
|
15
|
+
|
16
|
+
rb_undef_alloc_func(encoded_profile_class); // Class cannot be created from Ruby code
|
17
|
+
rb_global_variable(&encoded_profile_class);
|
18
|
+
|
19
|
+
rb_define_method(encoded_profile_class, "_native_bytes", _native_bytes, 0);
|
20
|
+
}
|
21
|
+
|
22
|
+
// This structure is used to define a Ruby object that stores a `ddog_prof_EncodedProfile`
|
23
|
+
// See also https://github.com/ruby/ruby/blob/master/doc/extension.rdoc for how this works
|
24
|
+
static const rb_data_type_t encoded_profile_typed_data = {
|
25
|
+
.wrap_struct_name = "Datadog::Profiling::EncodedProfile",
|
26
|
+
.function = {
|
27
|
+
.dmark = NULL, // We don't store references to Ruby objects so we don't need to mark any of them
|
28
|
+
.dfree = encoded_profile_typed_data_free,
|
29
|
+
.dsize = NULL, // We don't track memory usage (although it'd be cool if we did!)
|
30
|
+
//.dcompact = NULL, // Not needed -- we don't store references to Ruby objects
|
31
|
+
},
|
32
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY
|
33
|
+
};
|
34
|
+
|
35
|
+
VALUE from_ddog_prof_EncodedProfile(ddog_prof_EncodedProfile profile) {
|
36
|
+
ddog_prof_EncodedProfile *state = ruby_xcalloc(1, sizeof(ddog_prof_EncodedProfile));
|
37
|
+
*state = profile;
|
38
|
+
return TypedData_Wrap_Struct(encoded_profile_class, &encoded_profile_typed_data, state);
|
39
|
+
}
|
40
|
+
|
41
|
+
static ddog_ByteSlice get_bytes(ddog_prof_EncodedProfile *state) {
|
42
|
+
ddog_prof_Result_ByteSlice raw_bytes = ddog_prof_EncodedProfile_bytes(state);
|
43
|
+
if (raw_bytes.tag == DDOG_PROF_RESULT_BYTE_SLICE_ERR_BYTE_SLICE) {
|
44
|
+
rb_raise(rb_eRuntimeError, "Failed to get bytes from profile: %"PRIsVALUE, get_error_details_and_drop(&raw_bytes.err));
|
45
|
+
}
|
46
|
+
return raw_bytes.ok;
|
47
|
+
}
|
48
|
+
|
49
|
+
static ddog_prof_EncodedProfile *internal_to_ddog_prof_EncodedProfile(VALUE object) {
|
50
|
+
ddog_prof_EncodedProfile *state;
|
51
|
+
TypedData_Get_Struct(object, ddog_prof_EncodedProfile, &encoded_profile_typed_data, state);
|
52
|
+
return state;
|
53
|
+
}
|
54
|
+
|
55
|
+
ddog_prof_EncodedProfile *to_ddog_prof_EncodedProfile(VALUE object) {
|
56
|
+
ddog_prof_EncodedProfile *state = internal_to_ddog_prof_EncodedProfile(object);
|
57
|
+
get_bytes(state); // Validate profile is still usable -- if it's not, this will raise an exception
|
58
|
+
return state;
|
59
|
+
}
|
60
|
+
|
61
|
+
static void encoded_profile_typed_data_free(void *state_ptr) {
|
62
|
+
ddog_prof_EncodedProfile *state = (ddog_prof_EncodedProfile *) state_ptr;
|
63
|
+
|
64
|
+
// This drops the profile itself
|
65
|
+
ddog_prof_EncodedProfile_drop(state);
|
66
|
+
|
67
|
+
// This drops the tiny bit of memory we allocated to contain the ` ddog_prof_EncodedProfile` struct
|
68
|
+
ruby_xfree(state);
|
69
|
+
}
|
70
|
+
|
71
|
+
static VALUE _native_bytes(VALUE self) {
|
72
|
+
ddog_ByteSlice bytes = get_bytes(internal_to_ddog_prof_EncodedProfile(self));
|
73
|
+
return rb_str_new((const char *) bytes.ptr, bytes.len);
|
74
|
+
}
|
75
|
+
|
76
|
+
VALUE enforce_encoded_profile_instance(VALUE object) {
|
77
|
+
ENFORCE_TYPED_DATA(object, &encoded_profile_typed_data);
|
78
|
+
return object;
|
79
|
+
}
|
@@ -0,0 +1,8 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include <ruby.h>
|
4
|
+
#include <datadog/profiling.h>
|
5
|
+
|
6
|
+
VALUE from_ddog_prof_EncodedProfile(ddog_prof_EncodedProfile profile);
|
7
|
+
VALUE enforce_encoded_profile_instance(VALUE object);
|
8
|
+
ddog_prof_EncodedProfile *to_ddog_prof_EncodedProfile(VALUE object);
|
@@ -131,6 +131,9 @@ end
|
|
131
131
|
|
132
132
|
have_func "malloc_stats"
|
133
133
|
|
134
|
+
# On Ruby 3.5, we can't ask the object_id from IMEMOs (https://github.com/ruby/ruby/pull/13347)
|
135
|
+
$defs << "-DNO_IMEMO_OBJECT_ID" unless RUBY_VERSION < "3.5"
|
136
|
+
|
134
137
|
# On Ruby 2.5 and 3.3, this symbol was not visible. It is on 2.6 to 3.2, as well as 3.4+
|
135
138
|
$defs << "-DNO_RB_OBJ_INFO" if RUBY_VERSION.start_with?("2.5", "3.3")
|
136
139
|
|
@@ -164,17 +167,16 @@ $defs << "-DNO_INT_FIRST_LINENO" if RUBY_VERSION < "3.2"
|
|
164
167
|
# On older Rubies, "pop" was not a primitive operation
|
165
168
|
$defs << "-DNO_PRIMITIVE_POP" if RUBY_VERSION < "3.2"
|
166
169
|
|
170
|
+
# We could support this for older Rubies, but since this only gets used by the OTEL context extraction, and that
|
171
|
+
# use-case is only for 3.1+, we didn't bother supporting it farther back yet.
|
172
|
+
$defs << "-DNO_CURRENT_FIBER_FOR" if RUBY_VERSION < "3.1"
|
173
|
+
|
167
174
|
# On older Rubies, there was no tid member in the internal thread structure
|
168
175
|
$defs << "-DNO_THREAD_TID" if RUBY_VERSION < "3.1"
|
169
176
|
|
170
177
|
# On older Rubies, there was no jit_return member on the rb_control_frame_t struct
|
171
178
|
$defs << "-DNO_JIT_RETURN" if RUBY_VERSION < "3.1"
|
172
179
|
|
173
|
-
# On older Rubies, rb_gc_force_recycle allowed to free objects in a way that
|
174
|
-
# would be invisible to free tracepoints, finalizers and without cleaning
|
175
|
-
# obj_to_id_tbl mappings.
|
176
|
-
$defs << "-DHAVE_WORKING_RB_GC_FORCE_RECYCLE" if RUBY_VERSION < "3.1"
|
177
|
-
|
178
180
|
# On older Rubies, there are no Ractors
|
179
181
|
$defs << "-DNO_RACTORS" if RUBY_VERSION < "3"
|
180
182
|
|
@@ -184,9 +186,6 @@ $defs << "-DNO_IMEMO_NAME" if RUBY_VERSION < "3"
|
|
184
186
|
# On older Rubies, objects would not move
|
185
187
|
$defs << "-DNO_T_MOVED" if RUBY_VERSION < "2.7"
|
186
188
|
|
187
|
-
# On older Rubies, there was no RUBY_SEEN_OBJ_ID flag
|
188
|
-
$defs << "-DNO_SEEN_OBJ_ID_FLAG" if RUBY_VERSION < "2.7"
|
189
|
-
|
190
189
|
# On older Rubies, rb_global_vm_lock_struct did not include the owner field
|
191
190
|
$defs << "-DNO_GVL_OWNER" if RUBY_VERSION < "2.6"
|
192
191
|
|
@@ -39,14 +39,6 @@
|
|
39
39
|
|
40
40
|
static inline void gvl_profiling_init(void) { }
|
41
41
|
|
42
|
-
// This header gets included in private_vm_access.c which can't include datadog_ruby_common.h so we replicate this
|
43
|
-
// helper here
|
44
|
-
#ifdef __GNUC__
|
45
|
-
#define DDTRACE_UNUSED __attribute__((unused))
|
46
|
-
#else
|
47
|
-
#define DDTRACE_UNUSED
|
48
|
-
#endif
|
49
|
-
|
50
42
|
// NOTE: This is a hack that relies on the knowledge that on Ruby 3.2 the
|
51
43
|
// RUBY_INTERNAL_THREAD_EVENT_READY and RUBY_INTERNAL_THREAD_EVENT_RESUMED events always get called on the thread they
|
52
44
|
// are about. Thus, we can use our thread local storage hack to get this data, even though the event doesn't include it.
|
@@ -1,16 +1,10 @@
|
|
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
|
|
10
|
-
#if (defined(HAVE_WORKING_RB_GC_FORCE_RECYCLE) && ! defined(NO_SEEN_OBJ_ID_FLAG))
|
11
|
-
#define CAN_APPLY_GC_FORCE_RECYCLE_BUG_WORKAROUND
|
12
|
-
#endif
|
13
|
-
|
14
8
|
// Minimum age (in GC generations) of heap objects we want to include in heap
|
15
9
|
// recorder iterations. Object with age 0 represent objects that have yet to undergo
|
16
10
|
// a GC and, thus, may just be noise/trash at instant of iteration and are usually not
|
@@ -34,7 +28,6 @@ typedef struct {
|
|
34
28
|
char *filename;
|
35
29
|
int32_t line;
|
36
30
|
} heap_frame;
|
37
|
-
static st_index_t heap_frame_hash(heap_frame*, st_index_t seed);
|
38
31
|
|
39
32
|
// A compact representation of a stacktrace for a heap allocation.
|
40
33
|
//
|
@@ -117,17 +110,6 @@ static void object_record_free(object_record*);
|
|
117
110
|
static VALUE object_record_inspect(object_record*);
|
118
111
|
static object_record SKIPPED_RECORD = {0};
|
119
112
|
|
120
|
-
// A wrapper around an object record that is in the process of being recorded and was not
|
121
|
-
// yet committed.
|
122
|
-
typedef struct {
|
123
|
-
// Pointer to the (potentially partial) object_record containing metadata about an ongoing recording.
|
124
|
-
// When NULL, this symbolizes an unstarted/invalid recording.
|
125
|
-
object_record *object_record;
|
126
|
-
// A flag to track whether we had to force set the RUBY_FL_SEEN_OBJ_ID flag on this object
|
127
|
-
// as part of our workaround around rb_gc_force_recycle issues.
|
128
|
-
bool did_recycle_workaround;
|
129
|
-
} recording;
|
130
|
-
|
131
113
|
struct heap_recorder {
|
132
114
|
// Config
|
133
115
|
// Whether the recorder should try to determine approximate sizes for tracked objects.
|
@@ -147,6 +129,9 @@ struct heap_recorder {
|
|
147
129
|
// outside the GVL.
|
148
130
|
// NOTE: This table has ownership of its object_records. The keys are longs and so are
|
149
131
|
// passed as values.
|
132
|
+
//
|
133
|
+
// TODO: @ivoanjo We've evolved to actually never need to look up on object_records (we only insert and iterate),
|
134
|
+
// so right now this seems to be just a really really fancy self-resizing list/set.
|
150
135
|
st_table *object_records;
|
151
136
|
|
152
137
|
// Map[obj_id: long, record: object_record*]
|
@@ -169,7 +154,7 @@ struct heap_recorder {
|
|
169
154
|
long last_update_ns;
|
170
155
|
|
171
156
|
// Data for a heap recording that was started but not yet ended
|
172
|
-
|
157
|
+
object_record *active_recording;
|
173
158
|
|
174
159
|
// Reusable location array, implementing a flyweight pattern for things like iteration.
|
175
160
|
ddog_prof_Location *reusable_locations;
|
@@ -214,7 +199,7 @@ static int st_object_record_update(st_data_t, st_data_t, st_data_t);
|
|
214
199
|
static int st_object_records_iterate(st_data_t, st_data_t, st_data_t);
|
215
200
|
static int st_object_records_debug(st_data_t key, st_data_t value, st_data_t extra);
|
216
201
|
static int update_object_record_entry(st_data_t*, st_data_t*, st_data_t, int);
|
217
|
-
static void commit_recording(heap_recorder*, heap_record*,
|
202
|
+
static void commit_recording(heap_recorder *, heap_record *, object_record *active_recording);
|
218
203
|
static VALUE end_heap_allocation_recording(VALUE end_heap_allocation_args);
|
219
204
|
static void heap_recorder_update(heap_recorder *heap_recorder, bool full_update);
|
220
205
|
static inline double ewma_stat(double previous, double current);
|
@@ -235,7 +220,7 @@ heap_recorder* heap_recorder_new(void) {
|
|
235
220
|
recorder->object_records = st_init_numtable();
|
236
221
|
recorder->object_records_snapshot = NULL;
|
237
222
|
recorder->reusable_locations = ruby_xcalloc(MAX_FRAMES_LIMIT, sizeof(ddog_prof_Location));
|
238
|
-
recorder->active_recording =
|
223
|
+
recorder->active_recording = NULL;
|
239
224
|
recorder->size_enabled = true;
|
240
225
|
recorder->sample_rate = 1; // By default do no sampling on top of what allocation profiling already does
|
241
226
|
|
@@ -261,9 +246,9 @@ void heap_recorder_free(heap_recorder *heap_recorder) {
|
|
261
246
|
st_foreach(heap_recorder->heap_records, st_heap_record_entry_free, 0);
|
262
247
|
st_free_table(heap_recorder->heap_records);
|
263
248
|
|
264
|
-
if (heap_recorder->active_recording
|
249
|
+
if (heap_recorder->active_recording != NULL && heap_recorder->active_recording != &SKIPPED_RECORD) {
|
265
250
|
// If there's a partial object record, clean it up as well
|
266
|
-
object_record_free(heap_recorder->active_recording
|
251
|
+
object_record_free(heap_recorder->active_recording);
|
267
252
|
}
|
268
253
|
|
269
254
|
ruby_xfree(heap_recorder->reusable_locations);
|
@@ -308,7 +293,7 @@ void heap_recorder_after_fork(heap_recorder *heap_recorder) {
|
|
308
293
|
//
|
309
294
|
// There is one small caveat though: fork only preserves one thread and in a Ruby app, that
|
310
295
|
// will be the thread holding on to the GVL. Since we support iteration on the heap recorder
|
311
|
-
// outside of the GVL, any state specific to that interaction may be
|
296
|
+
// outside of the GVL, any state specific to that interaction may be inconsistent after fork
|
312
297
|
// (e.g. an acquired lock for thread safety). Iteration operates on object_records_snapshot
|
313
298
|
// though and that one will be updated on next heap_recorder_prepare_iteration so we really
|
314
299
|
// only need to finish any iteration that might have been left unfinished.
|
@@ -320,18 +305,24 @@ void heap_recorder_after_fork(heap_recorder *heap_recorder) {
|
|
320
305
|
heap_recorder->stats_lifetime = (struct stats_lifetime) {0};
|
321
306
|
}
|
322
307
|
|
323
|
-
void start_heap_allocation_recording(heap_recorder *heap_recorder, VALUE new_obj, unsigned int weight, ddog_CharSlice
|
308
|
+
void start_heap_allocation_recording(heap_recorder *heap_recorder, VALUE new_obj, unsigned int weight, ddog_CharSlice alloc_class) {
|
324
309
|
if (heap_recorder == NULL) {
|
325
310
|
return;
|
326
311
|
}
|
327
312
|
|
328
|
-
if (heap_recorder->active_recording
|
313
|
+
if (heap_recorder->active_recording != NULL) {
|
329
314
|
rb_raise(rb_eRuntimeError, "Detected consecutive heap allocation recording starts without end.");
|
330
315
|
}
|
331
316
|
|
332
|
-
if (heap_recorder->num_recordings_skipped
|
333
|
-
|
334
|
-
|
317
|
+
if (++heap_recorder->num_recordings_skipped < heap_recorder->sample_rate ||
|
318
|
+
#ifdef NO_IMEMO_OBJECT_ID
|
319
|
+
// On Ruby 3.5, we can't ask the object_id from IMEMOs (https://github.com/ruby/ruby/pull/13347)
|
320
|
+
RB_BUILTIN_TYPE(new_obj) == RUBY_T_IMEMO
|
321
|
+
#else
|
322
|
+
false
|
323
|
+
#endif
|
324
|
+
) {
|
325
|
+
heap_recorder->active_recording = &SKIPPED_RECORD;
|
335
326
|
return;
|
336
327
|
}
|
337
328
|
|
@@ -342,47 +333,15 @@ void start_heap_allocation_recording(heap_recorder *heap_recorder, VALUE new_obj
|
|
342
333
|
rb_raise(rb_eRuntimeError, "Detected a bignum object id. These are not supported by heap profiling.");
|
343
334
|
}
|
344
335
|
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
// the original object and the replacement that uses the recycled slot.
|
353
|
-
//
|
354
|
-
// In practice, we've observed (https://github.com/DataDog/dd-trace-rb/pull/3366)
|
355
|
-
// that non-noop implementations of rb_gc_force_recycle have an implementation bug
|
356
|
-
// which results in the object that re-used the recycled slot inheriting the same
|
357
|
-
// object id without setting the FL_SEEN_OBJ_ID flag. We rely on this knowledge to
|
358
|
-
// "observe" implicit frees when an object we are tracking is force-recycled.
|
359
|
-
//
|
360
|
-
// However, it may happen that we start tracking a new object and that object was
|
361
|
-
// allocated on a recycled slot. Due to the bug, this object would be missing the
|
362
|
-
// FL_SEEN_OBJ_ID flag even though it was not recycled itself. If we left it be,
|
363
|
-
// when we're doing our liveness check, the absence of the flag would trigger our
|
364
|
-
// implicit free workaround and the object would be inferred as recycled even though
|
365
|
-
// it might still be alive.
|
366
|
-
//
|
367
|
-
// Thus, if we detect that this new allocation is already missing the flag at the start
|
368
|
-
// of the heap allocation recording, we force-set it. This should be safe since we
|
369
|
-
// just called rb_obj_id on it above and the expectation is that any flaggable object
|
370
|
-
// that goes through it ends up with the flag set (as evidenced by the GC_ASSERT
|
371
|
-
// lines in https://github.com/ruby/ruby/blob/4a8d7246d15b2054eacb20f8ab3d29d39a3e7856/gc.c#L4050C14-L4050C14).
|
372
|
-
if (RB_FL_ABLE(new_obj) && !RB_FL_TEST(new_obj, RUBY_FL_SEEN_OBJ_ID)) {
|
373
|
-
RB_FL_SET(new_obj, RUBY_FL_SEEN_OBJ_ID);
|
374
|
-
did_recycle_workaround = true;
|
336
|
+
heap_recorder->active_recording = object_record_new(
|
337
|
+
FIX2LONG(ruby_obj_id),
|
338
|
+
NULL,
|
339
|
+
(live_object_data) {
|
340
|
+
.weight = weight * heap_recorder->sample_rate,
|
341
|
+
.class = string_from_char_slice(alloc_class),
|
342
|
+
.alloc_gen = rb_gc_count(),
|
375
343
|
}
|
376
|
-
|
377
|
-
|
378
|
-
heap_recorder->active_recording = (recording) {
|
379
|
-
.object_record = object_record_new(FIX2LONG(ruby_obj_id), NULL, (live_object_data) {
|
380
|
-
.weight = weight * heap_recorder->sample_rate,
|
381
|
-
.class = alloc_class != NULL ? string_from_char_slice(*alloc_class) : NULL,
|
382
|
-
.alloc_gen = rb_gc_count(),
|
383
|
-
}),
|
384
|
-
.did_recycle_workaround = did_recycle_workaround,
|
385
|
-
};
|
344
|
+
);
|
386
345
|
}
|
387
346
|
|
388
347
|
// end_heap_allocation_recording_with_rb_protect gets called while the stack_recorder is holding one of the profile
|
@@ -390,6 +349,10 @@ void start_heap_allocation_recording(heap_recorder *heap_recorder, VALUE new_obj
|
|
390
349
|
// with an rb_protect.
|
391
350
|
__attribute__((warn_unused_result))
|
392
351
|
int end_heap_allocation_recording_with_rb_protect(struct heap_recorder *heap_recorder, ddog_prof_Slice_Location locations) {
|
352
|
+
if (heap_recorder == NULL) {
|
353
|
+
return 0;
|
354
|
+
}
|
355
|
+
|
393
356
|
int exception_state;
|
394
357
|
struct end_heap_allocation_args end_heap_allocation_args = {
|
395
358
|
.heap_recorder = heap_recorder,
|
@@ -405,22 +368,18 @@ static VALUE end_heap_allocation_recording(VALUE end_heap_allocation_args) {
|
|
405
368
|
struct heap_recorder *heap_recorder = args->heap_recorder;
|
406
369
|
ddog_prof_Slice_Location locations = args->locations;
|
407
370
|
|
408
|
-
|
409
|
-
return Qnil;
|
410
|
-
}
|
371
|
+
object_record *active_recording = heap_recorder->active_recording;
|
411
372
|
|
412
|
-
|
413
|
-
|
414
|
-
if (active_recording.object_record == NULL) {
|
373
|
+
if (active_recording == NULL) {
|
415
374
|
// Recording ended without having been started?
|
416
375
|
rb_raise(rb_eRuntimeError, "Ended a heap recording that was not started");
|
417
376
|
}
|
418
377
|
// From now on, mark the global active recording as invalid so we can short-circuit at any point
|
419
378
|
// and not end up with a still active recording. the local active_recording still holds the
|
420
379
|
// data required for committing though.
|
421
|
-
heap_recorder->active_recording =
|
380
|
+
heap_recorder->active_recording = NULL;
|
422
381
|
|
423
|
-
if (active_recording
|
382
|
+
if (active_recording == &SKIPPED_RECORD) { // special marker when we decided to skip due to sampling
|
424
383
|
return Qnil;
|
425
384
|
}
|
426
385
|
|
@@ -685,41 +644,6 @@ static int st_object_record_update(st_data_t key, st_data_t value, st_data_t ext
|
|
685
644
|
|
686
645
|
// If we got this far, then we found a valid live object for the tracked id.
|
687
646
|
|
688
|
-
#ifdef CAN_APPLY_GC_FORCE_RECYCLE_BUG_WORKAROUND
|
689
|
-
// If we are in a ruby version that has a working rb_gc_force_recycle implementation,
|
690
|
-
// its usage may lead to an object being re-used outside of the typical GC cycle.
|
691
|
-
//
|
692
|
-
// This re-use is in theory invisible to us and would mean that the ref from which we
|
693
|
-
// collected the object_record metadata may not be the same as the current ref and
|
694
|
-
// thus any further reporting would be innacurately attributed to stale metadata.
|
695
|
-
//
|
696
|
-
// In practice, there is a way for us to notice that this happened because of a bug
|
697
|
-
// in the implementation of rb_gc_force_recycle. Our heap profiler relies on object
|
698
|
-
// ids and id2ref to detect whether objects are still alive. Turns out that when an
|
699
|
-
// object with an id is re-used via rb_gc_force_recycle, it will "inherit" the ID
|
700
|
-
// of the old object but it will NOT have the FL_SEEN_OBJ_ID as per the experiment
|
701
|
-
// in https://github.com/DataDog/dd-trace-rb/pull/3360#discussion_r1442823517
|
702
|
-
//
|
703
|
-
// Thus, if we detect that the ref we just resolved above is missing this flag, we can
|
704
|
-
// safely say re-use happened and thus treat it as an implicit free of the object
|
705
|
-
// we were tracking (the original one which got recycled).
|
706
|
-
if (RB_FL_ABLE(ref) && !RB_FL_TEST(ref, RUBY_FL_SEEN_OBJ_ID)) {
|
707
|
-
|
708
|
-
// NOTE: We don't really need to set this flag for heap recorder to work correctly
|
709
|
-
// but doing so partially mitigates a bug in runtimes with working rb_gc_force_recycle
|
710
|
-
// which leads to broken invariants and leaking of entries in obj_to_id and id_to_obj
|
711
|
-
// tables in objspace. We already do the same thing when we sample a recycled object,
|
712
|
-
// here we apply it as well to objects that replace recycled objects that were being
|
713
|
-
// tracked. More details in https://github.com/DataDog/dd-trace-rb/pull/3366
|
714
|
-
RB_FL_SET(ref, RUBY_FL_SEEN_OBJ_ID);
|
715
|
-
|
716
|
-
on_committed_object_record_cleanup(recorder, record);
|
717
|
-
recorder->stats_last_update.objects_dead++;
|
718
|
-
return ST_DELETE;
|
719
|
-
}
|
720
|
-
|
721
|
-
#endif
|
722
|
-
|
723
647
|
if (
|
724
648
|
recorder->size_enabled &&
|
725
649
|
recorder->update_include_old && // We only update sizes when doing a full update
|
@@ -732,6 +656,10 @@ static int st_object_record_update(st_data_t key, st_data_t value, st_data_t ext
|
|
732
656
|
record->object_data.is_frozen = RB_OBJ_FROZEN(ref);
|
733
657
|
}
|
734
658
|
|
659
|
+
// Ensure that ref is kept on the stack so the Ruby garbage collector does not try to clean up the object before this
|
660
|
+
// point.
|
661
|
+
RB_GC_GUARD(ref);
|
662
|
+
|
735
663
|
recorder->stats_last_update.objects_alive++;
|
736
664
|
if (record->object_data.is_frozen) {
|
737
665
|
recorder->stats_last_update.objects_frozen++;
|
@@ -757,7 +685,7 @@ static int st_object_records_iterate(DDTRACE_UNUSED st_data_t key, st_data_t val
|
|
757
685
|
for (uint16_t i = 0; i < stack->frames_len; i++) {
|
758
686
|
const heap_frame *frame = &stack->frames[i];
|
759
687
|
locations[i] = (ddog_prof_Location) {
|
760
|
-
.mapping = {.filename = DDOG_CHARSLICE_C(""), .build_id = DDOG_CHARSLICE_C("")},
|
688
|
+
.mapping = {.filename = DDOG_CHARSLICE_C(""), .build_id = DDOG_CHARSLICE_C(""), .build_id_id = {}},
|
761
689
|
.function = {
|
762
690
|
.name = {.ptr = frame->name, .len = strlen(frame->name)},
|
763
691
|
.filename = {.ptr = frame->filename, .len = strlen(frame->filename)},
|
@@ -770,6 +698,7 @@ static int st_object_records_iterate(DDTRACE_UNUSED st_data_t key, st_data_t val
|
|
770
698
|
iteration_data.object_data = record->object_data;
|
771
699
|
iteration_data.locations = (ddog_prof_Slice_Location) {.ptr = locations, .len = stack->frames_len};
|
772
700
|
|
701
|
+
// This is expected to be StackRecorder's add_heap_sample_to_active_profile_without_gvl
|
773
702
|
if (!context->for_each_callback(iteration_data, context->for_each_callback_extra_arg)) {
|
774
703
|
return ST_STOP;
|
775
704
|
}
|
@@ -787,55 +716,35 @@ static int st_object_records_debug(DDTRACE_UNUSED st_data_t key, st_data_t value
|
|
787
716
|
return ST_CONTINUE;
|
788
717
|
}
|
789
718
|
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
// [in] The heap recorder where the update is happening.
|
797
|
-
heap_recorder *heap_recorder;
|
798
|
-
} object_record_update_data;
|
799
|
-
|
800
|
-
static int update_object_record_entry(DDTRACE_UNUSED st_data_t *key, st_data_t *value, st_data_t data, int existing) {
|
801
|
-
object_record_update_data *update_data = (object_record_update_data*) data;
|
802
|
-
recording recording = update_data->recording;
|
803
|
-
object_record *new_object_record = recording.object_record;
|
804
|
-
if (existing) {
|
805
|
-
object_record *existing_record = (object_record*) (*value);
|
806
|
-
if (recording.did_recycle_workaround) {
|
807
|
-
// In this case, it's possible for an object id to be re-used and we were lucky enough to have
|
808
|
-
// sampled both the original object and the replacement so cleanup the old one and replace it with
|
809
|
-
// the new object_record (i.e. treat this as a combined free+allocation).
|
810
|
-
on_committed_object_record_cleanup(update_data->heap_recorder, existing_record);
|
811
|
-
} else {
|
812
|
-
// This is not supposed to happen, raising...
|
813
|
-
VALUE existing_inspect = object_record_inspect(existing_record);
|
814
|
-
VALUE new_inspect = object_record_inspect(new_object_record);
|
815
|
-
rb_raise(rb_eRuntimeError, "Object ids are supposed to be unique. We got 2 allocation recordings with "
|
816
|
-
"the same id. previous=%"PRIsVALUE" new=%"PRIsVALUE, existing_inspect, new_inspect);
|
817
|
-
}
|
719
|
+
static int update_object_record_entry(DDTRACE_UNUSED st_data_t *key, st_data_t *value, st_data_t new_object_record, int existing) {
|
720
|
+
if (!existing) {
|
721
|
+
(*value) = (st_data_t) new_object_record; // Expected to be a `object_record *`
|
722
|
+
} else {
|
723
|
+
// If key already existed, we don't touch the existing value, so it can be used for diagnostics
|
818
724
|
}
|
819
|
-
// Always carry on with the update, we want the new record to be there at the end
|
820
|
-
(*value) = (st_data_t) new_object_record;
|
821
725
|
return ST_CONTINUE;
|
822
726
|
}
|
823
727
|
|
824
|
-
static void commit_recording(heap_recorder *heap_recorder, heap_record *heap_record,
|
728
|
+
static void commit_recording(heap_recorder *heap_recorder, heap_record *heap_record, object_record *active_recording) {
|
825
729
|
// Link the object record with the corresponding heap record. This was the last remaining thing we
|
826
730
|
// needed to fully build the object_record.
|
827
|
-
|
731
|
+
active_recording->heap_record = heap_record;
|
828
732
|
if (heap_record->num_tracked_objects == UINT32_MAX) {
|
829
733
|
rb_raise(rb_eRuntimeError, "Reached maximum number of tracked objects for heap record");
|
830
734
|
}
|
831
735
|
heap_record->num_tracked_objects++;
|
832
736
|
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
737
|
+
int existing_error = st_update(heap_recorder->object_records, active_recording->obj_id, update_object_record_entry, (st_data_t) active_recording);
|
738
|
+
if (existing_error) {
|
739
|
+
object_record *existing_record = NULL;
|
740
|
+
st_lookup(heap_recorder->object_records, active_recording->obj_id, (st_data_t *) &existing_record);
|
741
|
+
if (existing_record == NULL) rb_raise(rb_eRuntimeError, "Unexpected NULL when reading existing record");
|
742
|
+
|
743
|
+
VALUE existing_inspect = object_record_inspect(existing_record);
|
744
|
+
VALUE new_inspect = object_record_inspect(active_recording);
|
745
|
+
rb_raise(rb_eRuntimeError, "Object ids are supposed to be unique. We got 2 allocation recordings with "
|
746
|
+
"the same id. previous={%"PRIsVALUE"} new={%"PRIsVALUE"}", existing_inspect, new_inspect);
|
747
|
+
}
|
839
748
|
}
|
840
749
|
|
841
750
|
// Struct holding data required for an update operation on heap_records
|
@@ -945,7 +854,6 @@ void heap_record_free(heap_record *record) {
|
|
945
854
|
ruby_xfree(record);
|
946
855
|
}
|
947
856
|
|
948
|
-
|
949
857
|
// =================
|
950
858
|
// Object Record API
|
951
859
|
// =================
|
@@ -995,25 +903,6 @@ VALUE object_record_inspect(object_record *record) {
|
|
995
903
|
// ==============
|
996
904
|
// Heap Frame API
|
997
905
|
// ==============
|
998
|
-
int heap_frame_cmp(heap_frame *f1, heap_frame *f2) {
|
999
|
-
int line_diff = (int) (f1->line - f2->line);
|
1000
|
-
if (line_diff != 0) {
|
1001
|
-
return line_diff;
|
1002
|
-
}
|
1003
|
-
int cmp = strcmp(f1->name, f2->name);
|
1004
|
-
if (cmp != 0) {
|
1005
|
-
return cmp;
|
1006
|
-
}
|
1007
|
-
return strcmp(f1->filename, f2->filename);
|
1008
|
-
}
|
1009
|
-
|
1010
|
-
// TODO: Research potential performance improvements around hashing stuff here
|
1011
|
-
// once we have a benchmarking suite.
|
1012
|
-
// Example: Each call to st_hash is calling murmur_finish and we may want
|
1013
|
-
// to only finish once per structure, not per field?
|
1014
|
-
// Example: There may be a more efficient hashing for line that is not the
|
1015
|
-
// generic st_hash algorithm?
|
1016
|
-
|
1017
906
|
// WARN: Must be kept in-sync with ::char_slice_hash
|
1018
907
|
st_index_t string_hash(char *str, st_index_t seed) {
|
1019
908
|
return st_hash(str, strlen(str), seed);
|
@@ -1049,9 +938,7 @@ st_index_t ddog_location_hash(ddog_prof_Location location, st_index_t seed) {
|
|
1049
938
|
heap_stack* heap_stack_new(ddog_prof_Slice_Location locations) {
|
1050
939
|
uint16_t frames_len = locations.len;
|
1051
940
|
if (frames_len > MAX_FRAMES_LIMIT) {
|
1052
|
-
// This
|
1053
|
-
// the stacktrace construction mechanism. If it happens, lets just raise. This should
|
1054
|
-
// be safe since only allocate with the GVL anyway.
|
941
|
+
// This is not expected as MAX_FRAMES_LIMIT is shared with the stacktrace construction mechanism
|
1055
942
|
rb_raise(rb_eRuntimeError, "Found stack with more than %d frames (%d)", MAX_FRAMES_LIMIT, frames_len);
|
1056
943
|
}
|
1057
944
|
heap_stack *stack = ruby_xcalloc(1, sizeof(heap_stack) + frames_len * sizeof(heap_frame));
|
@@ -17,7 +17,7 @@
|
|
17
17
|
typedef struct heap_recorder heap_recorder;
|
18
18
|
|
19
19
|
// Extra data associated with each live object being tracked.
|
20
|
-
typedef struct
|
20
|
+
typedef struct {
|
21
21
|
// The weight of this object from a sampling perspective.
|
22
22
|
//
|
23
23
|
// A notion of weight is preserved for each tracked object to allow for an approximate
|
@@ -105,7 +105,7 @@ void heap_recorder_after_fork(heap_recorder *heap_recorder);
|
|
105
105
|
// The sampling weight of this object.
|
106
106
|
//
|
107
107
|
// WARN: It needs to be paired with a ::end_heap_allocation_recording call.
|
108
|
-
void start_heap_allocation_recording(heap_recorder *heap_recorder, VALUE new_obj, unsigned int weight, ddog_CharSlice
|
108
|
+
void start_heap_allocation_recording(heap_recorder *heap_recorder, VALUE new_obj, unsigned int weight, ddog_CharSlice alloc_class);
|
109
109
|
|
110
110
|
// End a previously started heap allocation recording on the heap recorder.
|
111
111
|
//
|