ddtrace 1.4.2 → 1.19.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 +986 -2
- data/LICENSE-3rdparty.csv +2 -0
- data/README.md +10 -12
- data/ext/ddtrace_profiling_loader/ddtrace_profiling_loader.c +9 -2
- data/ext/ddtrace_profiling_loader/extconf.rb +21 -3
- data/ext/ddtrace_profiling_native_extension/NativeExtensionDesign.md +48 -12
- data/ext/ddtrace_profiling_native_extension/clock_id.h +1 -3
- data/ext/ddtrace_profiling_native_extension/clock_id_from_pthread.c +6 -23
- data/ext/ddtrace_profiling_native_extension/clock_id_noop.c +0 -1
- data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +719 -129
- data/ext/ddtrace_profiling_native_extension/collectors_dynamic_sampling_rate.c +150 -0
- data/ext/ddtrace_profiling_native_extension/collectors_dynamic_sampling_rate.h +18 -0
- data/ext/ddtrace_profiling_native_extension/collectors_gc_profiling_helper.c +156 -0
- data/ext/ddtrace_profiling_native_extension/collectors_gc_profiling_helper.h +5 -0
- data/ext/ddtrace_profiling_native_extension/collectors_idle_sampling_helper.c +244 -0
- data/ext/ddtrace_profiling_native_extension/collectors_idle_sampling_helper.h +3 -0
- data/ext/ddtrace_profiling_native_extension/collectors_stack.c +184 -94
- data/ext/ddtrace_profiling_native_extension/collectors_stack.h +20 -2
- data/ext/ddtrace_profiling_native_extension/collectors_thread_context.c +1301 -0
- data/ext/ddtrace_profiling_native_extension/collectors_thread_context.h +15 -0
- data/ext/ddtrace_profiling_native_extension/extconf.rb +103 -28
- data/ext/ddtrace_profiling_native_extension/heap_recorder.c +970 -0
- data/ext/ddtrace_profiling_native_extension/heap_recorder.h +155 -0
- data/ext/ddtrace_profiling_native_extension/helpers.h +7 -0
- data/ext/ddtrace_profiling_native_extension/http_transport.c +133 -88
- data/ext/ddtrace_profiling_native_extension/libdatadog_helpers.c +62 -0
- data/ext/ddtrace_profiling_native_extension/libdatadog_helpers.h +32 -4
- data/ext/ddtrace_profiling_native_extension/native_extension_helpers.rb +55 -26
- data/ext/ddtrace_profiling_native_extension/pid_controller.c +57 -0
- data/ext/ddtrace_profiling_native_extension/pid_controller.h +45 -0
- data/ext/ddtrace_profiling_native_extension/private_vm_api_access.c +317 -131
- data/ext/ddtrace_profiling_native_extension/private_vm_api_access.h +25 -1
- data/ext/ddtrace_profiling_native_extension/profiling.c +219 -4
- data/ext/ddtrace_profiling_native_extension/ruby_helpers.c +233 -1
- data/ext/ddtrace_profiling_native_extension/ruby_helpers.h +60 -8
- data/ext/ddtrace_profiling_native_extension/setup_signal_handler.c +115 -0
- data/ext/ddtrace_profiling_native_extension/setup_signal_handler.h +11 -0
- data/ext/ddtrace_profiling_native_extension/stack_recorder.c +585 -66
- data/ext/ddtrace_profiling_native_extension/stack_recorder.h +19 -30
- data/ext/ddtrace_profiling_native_extension/time_helpers.c +53 -0
- data/ext/ddtrace_profiling_native_extension/time_helpers.h +24 -0
- data/lib/datadog/appsec/assets/blocked.html +98 -3
- data/lib/datadog/appsec/assets/blocked.json +1 -0
- data/lib/datadog/appsec/assets/blocked.text +5 -0
- data/lib/datadog/appsec/assets/waf_rules/processors.json +92 -0
- data/lib/datadog/appsec/assets/waf_rules/recommended.json +2861 -796
- data/lib/datadog/appsec/assets/waf_rules/scanners.json +114 -0
- data/lib/datadog/appsec/assets/waf_rules/strict.json +459 -122
- data/lib/datadog/appsec/assets.rb +10 -4
- data/lib/datadog/appsec/autoload.rb +4 -11
- data/lib/datadog/appsec/component.rb +94 -0
- data/lib/datadog/appsec/configuration/settings.rb +170 -162
- data/lib/datadog/appsec/configuration.rb +1 -70
- data/lib/datadog/appsec/contrib/auto_instrument.rb +3 -5
- data/lib/datadog/appsec/contrib/devise/event.rb +57 -0
- data/lib/datadog/appsec/contrib/devise/ext.rb +13 -0
- data/lib/datadog/appsec/contrib/devise/integration.rb +42 -0
- data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +76 -0
- data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +54 -0
- data/lib/datadog/appsec/contrib/devise/patcher.rb +45 -0
- data/lib/datadog/appsec/contrib/devise/resource.rb +35 -0
- data/lib/datadog/appsec/contrib/devise/tracking.rb +49 -0
- data/lib/datadog/appsec/contrib/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/patcher.rb +1 -1
- data/lib/datadog/appsec/contrib/rack/ext.rb +1 -3
- data/lib/datadog/appsec/contrib/rack/gateway/request.rb +104 -0
- data/lib/datadog/appsec/contrib/rack/gateway/response.rb +30 -0
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +112 -121
- data/lib/datadog/appsec/contrib/rack/integration.rb +0 -7
- data/lib/datadog/appsec/contrib/rack/patcher.rb +3 -1
- data/lib/datadog/appsec/contrib/rack/reactive/request.rb +33 -39
- data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +19 -23
- data/lib/datadog/appsec/contrib/rack/reactive/response.rb +25 -23
- data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +11 -8
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +122 -41
- data/lib/datadog/appsec/contrib/rails/ext.rb +2 -4
- data/lib/datadog/appsec/contrib/rails/framework.rb +2 -16
- data/lib/datadog/appsec/contrib/rails/gateway/request.rb +67 -0
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +40 -52
- data/lib/datadog/appsec/contrib/rails/integration.rb +1 -8
- data/lib/datadog/appsec/contrib/rails/patcher.rb +23 -20
- data/lib/datadog/appsec/contrib/rails/reactive/action.rb +21 -23
- data/lib/datadog/appsec/contrib/rails/request.rb +4 -1
- data/lib/datadog/appsec/contrib/rails/request_middleware.rb +1 -1
- data/lib/datadog/appsec/contrib/sinatra/ext.rb +2 -3
- data/lib/datadog/appsec/contrib/sinatra/framework.rb +2 -16
- data/lib/datadog/appsec/contrib/sinatra/gateway/request.rb +17 -0
- data/lib/datadog/appsec/contrib/sinatra/gateway/route_params.rb +23 -0
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +78 -87
- data/lib/datadog/appsec/contrib/sinatra/integration.rb +0 -7
- data/lib/datadog/appsec/contrib/sinatra/patcher.rb +33 -15
- data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +19 -21
- data/lib/datadog/appsec/contrib/sinatra/request_middleware.rb +1 -1
- data/lib/datadog/appsec/event.rb +98 -50
- data/lib/datadog/appsec/ext.rb +10 -0
- data/lib/datadog/appsec/extensions.rb +2 -105
- data/lib/datadog/appsec/instrumentation/gateway/argument.rb +22 -0
- data/lib/datadog/appsec/instrumentation/gateway.rb +26 -6
- data/lib/datadog/appsec/instrumentation.rb +9 -0
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +67 -0
- data/lib/datadog/appsec/monitor/reactive/set_user.rb +58 -0
- data/lib/datadog/appsec/monitor.rb +11 -0
- data/lib/datadog/appsec/processor/actions.rb +49 -0
- data/lib/datadog/appsec/processor/rule_loader.rb +123 -0
- data/lib/datadog/appsec/processor/rule_merger.rb +152 -0
- data/lib/datadog/appsec/processor.rb +68 -61
- data/lib/datadog/appsec/rate_limiter.rb +1 -3
- data/lib/datadog/appsec/reactive/address_hash.rb +6 -2
- data/lib/datadog/appsec/reactive/engine.rb +10 -7
- data/lib/datadog/appsec/reactive/operation.rb +19 -2
- data/lib/datadog/appsec/reactive/subscriber.rb +2 -1
- data/lib/datadog/appsec/remote.rb +129 -0
- data/lib/datadog/appsec/response.rb +151 -0
- data/lib/datadog/appsec/sample_rate.rb +21 -0
- data/lib/datadog/appsec/scope.rb +61 -0
- data/lib/datadog/appsec/utils/http/media_range.rb +199 -0
- data/lib/datadog/appsec/utils/http/media_type.rb +85 -0
- data/lib/datadog/appsec/utils/http.rb +11 -0
- data/lib/datadog/appsec/utils.rb +9 -0
- data/lib/datadog/appsec.rb +41 -4
- data/lib/datadog/core/backport.rb +51 -0
- data/lib/datadog/core/buffer/cruby.rb +1 -1
- data/lib/datadog/core/buffer/random.rb +1 -1
- data/lib/datadog/core/buffer/thread_safe.rb +1 -1
- data/lib/datadog/core/chunker.rb +1 -1
- data/lib/datadog/core/configuration/agent_settings_resolver.rb +96 -56
- data/lib/datadog/core/configuration/base.rb +7 -16
- data/lib/datadog/core/configuration/components.rb +40 -296
- data/lib/datadog/core/configuration/ext.rb +47 -0
- data/lib/datadog/core/configuration/option.rb +270 -22
- data/lib/datadog/core/configuration/option_definition.rb +81 -31
- data/lib/datadog/core/configuration/options.rb +26 -16
- data/lib/datadog/core/configuration/settings.rb +419 -305
- data/lib/datadog/core/configuration.rb +10 -6
- data/lib/datadog/core/diagnostics/environment_logger.rb +129 -230
- data/lib/datadog/core/diagnostics/health.rb +4 -22
- data/lib/datadog/core/encoding.rb +0 -4
- data/lib/datadog/core/environment/cgroup.rb +0 -4
- data/lib/datadog/core/environment/class_count.rb +1 -1
- data/lib/datadog/core/environment/container.rb +0 -4
- data/lib/datadog/core/environment/execution.rb +103 -0
- data/lib/datadog/core/environment/ext.rb +12 -12
- data/lib/datadog/core/environment/gc.rb +1 -1
- data/lib/datadog/core/environment/identity.rb +57 -1
- data/lib/datadog/core/environment/platform.rb +0 -2
- data/lib/datadog/core/environment/socket.rb +1 -1
- data/lib/datadog/core/environment/thread_count.rb +1 -1
- data/lib/datadog/core/environment/variable_helpers.rb +29 -44
- data/lib/datadog/core/environment/vm_cache.rb +18 -1
- data/lib/datadog/core/environment/yjit.rb +58 -0
- data/lib/datadog/core/error.rb +1 -2
- data/lib/datadog/core/extensions.rb +1 -1
- data/lib/datadog/core/git/ext.rb +25 -23
- data/lib/datadog/core/header_collection.rb +43 -0
- data/lib/datadog/core/logger.rb +0 -2
- data/lib/datadog/core/logging/ext.rb +3 -1
- data/lib/datadog/core/metrics/client.rb +3 -4
- data/lib/datadog/core/metrics/ext.rb +6 -8
- data/lib/datadog/core/metrics/helpers.rb +1 -1
- data/lib/datadog/core/metrics/logging.rb +0 -2
- data/lib/datadog/core/metrics/metric.rb +1 -1
- data/lib/datadog/core/metrics/options.rb +0 -2
- data/lib/datadog/core/pin.rb +0 -2
- data/lib/datadog/core/remote/client/capabilities.rb +62 -0
- data/lib/datadog/core/remote/client.rb +232 -0
- data/lib/datadog/core/remote/component.rb +149 -0
- data/lib/datadog/core/remote/configuration/content.rb +111 -0
- data/lib/datadog/core/remote/configuration/digest.rb +62 -0
- data/lib/datadog/core/remote/configuration/path.rb +90 -0
- data/lib/datadog/core/remote/configuration/repository.rb +294 -0
- data/lib/datadog/core/remote/configuration/target.rb +74 -0
- data/lib/datadog/core/remote/configuration.rb +18 -0
- data/lib/datadog/core/remote/dispatcher.rb +59 -0
- data/lib/datadog/core/remote/ext.rb +12 -0
- data/lib/datadog/core/remote/negotiation.rb +70 -0
- data/lib/datadog/core/remote/transport/config.rb +60 -0
- data/lib/datadog/core/remote/transport/http/api/instance.rb +39 -0
- data/lib/datadog/core/remote/transport/http/api/spec.rb +21 -0
- data/lib/datadog/core/remote/transport/http/api.rb +58 -0
- data/lib/datadog/core/remote/transport/http/builder.rb +219 -0
- data/lib/datadog/core/remote/transport/http/client.rb +48 -0
- data/lib/datadog/core/remote/transport/http/config.rb +280 -0
- data/lib/datadog/core/remote/transport/http/negotiation.rb +146 -0
- data/lib/datadog/core/remote/transport/http.rb +179 -0
- data/lib/datadog/core/remote/transport/negotiation.rb +62 -0
- data/lib/datadog/core/remote/worker.rb +99 -0
- data/lib/datadog/core/remote.rb +24 -0
- data/lib/datadog/core/runtime/ext.rb +21 -11
- data/lib/datadog/core/runtime/metrics.rb +64 -7
- data/lib/datadog/core/telemetry/client.rb +12 -4
- data/lib/datadog/core/telemetry/collector.rb +34 -18
- data/lib/datadog/core/telemetry/emitter.rb +4 -4
- data/lib/datadog/core/telemetry/event.rb +20 -8
- data/lib/datadog/core/telemetry/ext.rb +6 -2
- data/lib/datadog/core/telemetry/heartbeat.rb +3 -5
- data/lib/datadog/core/telemetry/http/adapters/net.rb +0 -2
- data/lib/datadog/core/telemetry/http/env.rb +1 -1
- data/lib/datadog/core/telemetry/http/ext.rb +10 -8
- data/lib/datadog/core/telemetry/http/response.rb +0 -4
- data/lib/datadog/core/telemetry/http/transport.rb +4 -1
- data/lib/datadog/core/telemetry/v1/app_event.rb +10 -3
- data/lib/datadog/core/telemetry/v1/application.rb +7 -1
- data/lib/datadog/core/telemetry/v1/dependency.rb +9 -2
- data/lib/datadog/core/telemetry/v1/host.rb +9 -1
- data/lib/datadog/core/telemetry/v1/install_signature.rb +38 -0
- data/lib/datadog/core/telemetry/v1/integration.rb +7 -1
- data/lib/datadog/core/telemetry/v1/product.rb +9 -1
- data/lib/datadog/core/telemetry/v1/telemetry_request.rb +7 -1
- data/lib/datadog/core/telemetry/v2/app_client_configuration_change.rb +41 -0
- data/lib/datadog/core/telemetry/v2/request.rb +29 -0
- data/lib/datadog/core/transport/ext.rb +47 -0
- data/lib/datadog/core/transport/http/adapters/net.rb +168 -0
- data/lib/datadog/core/transport/http/adapters/registry.rb +29 -0
- data/lib/datadog/core/transport/http/adapters/test.rb +89 -0
- data/lib/datadog/core/transport/http/adapters/unix_socket.rb +83 -0
- data/lib/datadog/core/transport/http/api/endpoint.rb +31 -0
- data/lib/datadog/core/transport/http/api/fallbacks.rb +26 -0
- data/lib/datadog/core/transport/http/api/map.rb +18 -0
- data/lib/datadog/core/transport/http/env.rb +62 -0
- data/lib/datadog/core/transport/http/response.rb +60 -0
- data/lib/datadog/core/transport/parcel.rb +22 -0
- data/lib/datadog/core/transport/request.rb +17 -0
- data/lib/datadog/core/transport/response.rb +64 -0
- data/lib/datadog/core/utils/compression.rb +6 -2
- data/lib/datadog/core/utils/duration.rb +52 -0
- data/lib/datadog/core/utils/forking.rb +0 -2
- data/lib/datadog/core/utils/hash.rb +79 -0
- data/lib/datadog/core/utils/network.rb +140 -0
- data/lib/datadog/core/utils/only_once.rb +0 -2
- data/lib/datadog/core/utils/safe_dup.rb +35 -12
- data/lib/datadog/core/utils/sequence.rb +1 -1
- data/lib/datadog/core/utils/time.rb +1 -3
- data/lib/datadog/core/utils.rb +1 -24
- data/lib/datadog/core/vendor/ipaddr.rb +78 -0
- data/lib/datadog/core/vendor/multipart-post/multipart/post/composite_read_io.rb +0 -2
- data/lib/datadog/core/vendor/multipart-post/multipart/post/multipartable.rb +0 -2
- data/lib/datadog/core/vendor/multipart-post/multipart/post/parts.rb +0 -2
- data/lib/datadog/core/vendor/multipart-post/multipart/post/version.rb +0 -2
- data/lib/datadog/core/vendor/multipart-post/multipart/post.rb +0 -2
- data/lib/datadog/core/vendor/multipart-post/multipart.rb +0 -2
- data/lib/datadog/core/vendor/multipart-post/net/http/post/multipart.rb +0 -2
- data/lib/datadog/core/worker.rb +1 -1
- data/lib/datadog/core/workers/async.rb +7 -6
- data/lib/datadog/core/workers/interval_loop.rb +6 -2
- data/lib/datadog/core/workers/polling.rb +2 -4
- data/lib/datadog/core/workers/queue.rb +1 -1
- data/lib/datadog/core/workers/runtime_metrics.rb +1 -1
- data/lib/datadog/core.rb +20 -55
- data/lib/datadog/kit/appsec/events.rb +169 -0
- data/lib/datadog/kit/enable_core_dumps.rb +8 -9
- data/lib/datadog/kit/identity.rb +90 -49
- data/lib/datadog/kit.rb +1 -1
- data/lib/datadog/opentelemetry/api/context.rb +193 -0
- data/lib/datadog/opentelemetry/api/trace/span.rb +14 -0
- data/lib/datadog/opentelemetry/sdk/configurator.rb +37 -0
- data/lib/datadog/opentelemetry/sdk/id_generator.rb +26 -0
- data/lib/datadog/opentelemetry/sdk/propagator.rb +91 -0
- data/lib/datadog/opentelemetry/sdk/span_processor.rb +134 -0
- data/lib/datadog/opentelemetry/sdk/trace/span.rb +167 -0
- data/lib/datadog/opentelemetry/trace.rb +58 -0
- data/lib/datadog/opentelemetry.rb +48 -0
- data/lib/datadog/opentracer/binary_propagator.rb +1 -1
- data/lib/datadog/opentracer/carrier.rb +1 -1
- data/lib/datadog/opentracer/distributed_headers.rb +7 -11
- data/lib/datadog/opentracer/global_tracer.rb +1 -1
- data/lib/datadog/opentracer/propagator.rb +1 -1
- data/lib/datadog/opentracer/rack_propagator.rb +0 -5
- data/lib/datadog/opentracer/scope.rb +1 -1
- data/lib/datadog/opentracer/scope_manager.rb +1 -1
- data/lib/datadog/opentracer/span.rb +0 -2
- data/lib/datadog/opentracer/span_context.rb +1 -1
- data/lib/datadog/opentracer/span_context_factory.rb +1 -1
- data/lib/datadog/opentracer/text_map_propagator.rb +6 -9
- data/lib/datadog/opentracer/thread_local_scope.rb +1 -1
- data/lib/datadog/opentracer/thread_local_scope_manager.rb +0 -2
- data/lib/datadog/opentracer/tracer.rb +0 -2
- data/lib/datadog/opentracer.rb +10 -1
- data/lib/datadog/profiling/collectors/code_provenance.rb +0 -2
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +53 -19
- data/lib/datadog/profiling/collectors/dynamic_sampling_rate.rb +14 -0
- data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +68 -0
- data/lib/datadog/profiling/collectors/stack.rb +1 -1
- data/lib/datadog/profiling/collectors/thread_context.rb +61 -0
- data/lib/datadog/profiling/component.rb +434 -0
- data/lib/datadog/profiling/diagnostics/environment_logger.rb +39 -0
- data/lib/datadog/profiling/exporter.rb +12 -7
- data/lib/datadog/profiling/ext/forking.rb +0 -2
- data/lib/datadog/profiling/ext.rb +20 -32
- data/lib/datadog/profiling/flush.rb +8 -6
- data/lib/datadog/profiling/http_transport.rb +19 -8
- data/lib/datadog/profiling/load_native_extension.rb +7 -3
- data/lib/datadog/profiling/native_extension.rb +1 -22
- data/lib/datadog/profiling/preload.rb +1 -1
- data/lib/datadog/profiling/profiler.rb +42 -14
- data/lib/datadog/profiling/scheduler.rb +27 -25
- data/lib/datadog/profiling/stack_recorder.rb +30 -6
- data/lib/datadog/profiling/tag_builder.rb +1 -1
- data/lib/datadog/profiling/tasks/exec.rb +0 -2
- data/lib/datadog/profiling/tasks/help.rb +0 -2
- data/lib/datadog/profiling/tasks/setup.rb +0 -35
- data/lib/datadog/profiling.rb +53 -74
- data/lib/datadog/tracing/analytics.rb +1 -1
- data/lib/datadog/tracing/buffer.rb +0 -5
- data/lib/datadog/tracing/client_ip.rb +61 -0
- data/lib/datadog/tracing/component.rb +235 -0
- data/lib/datadog/tracing/configuration/agent_settings_resolver.rb +13 -0
- data/lib/datadog/tracing/configuration/dynamic/option.rb +71 -0
- data/lib/datadog/tracing/configuration/dynamic.rb +64 -0
- data/lib/datadog/tracing/configuration/ext.rb +73 -15
- data/lib/datadog/tracing/configuration/http.rb +74 -0
- data/lib/datadog/tracing/configuration/settings.rb +501 -0
- data/lib/datadog/tracing/context.rb +1 -1
- data/lib/datadog/tracing/context_provider.rb +0 -2
- data/lib/datadog/tracing/contrib/action_cable/configuration/settings.rb +10 -7
- data/lib/datadog/tracing/contrib/action_cable/event.rb +1 -1
- data/lib/datadog/tracing/contrib/action_cable/events/broadcast.rb +0 -2
- data/lib/datadog/tracing/contrib/action_cable/events/perform_action.rb +0 -2
- data/lib/datadog/tracing/contrib/action_cable/events/transmit.rb +0 -2
- data/lib/datadog/tracing/contrib/action_cable/events.rb +1 -1
- data/lib/datadog/tracing/contrib/action_cable/ext.rb +19 -19
- data/lib/datadog/tracing/contrib/action_cable/instrumentation.rb +0 -2
- data/lib/datadog/tracing/contrib/action_cable/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/action_cable/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/action_mailer/configuration/settings.rb +10 -7
- data/lib/datadog/tracing/contrib/action_mailer/event.rb +1 -1
- data/lib/datadog/tracing/contrib/action_mailer/events/deliver.rb +0 -2
- data/lib/datadog/tracing/contrib/action_mailer/events/process.rb +0 -2
- data/lib/datadog/tracing/contrib/action_mailer/events.rb +1 -1
- data/lib/datadog/tracing/contrib/action_mailer/ext.rb +19 -19
- data/lib/datadog/tracing/contrib/action_mailer/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/action_mailer/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +2 -26
- data/lib/datadog/tracing/contrib/action_pack/action_controller/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/action_pack/configuration/settings.rb +22 -9
- data/lib/datadog/tracing/contrib/action_pack/ext.rb +9 -9
- data/lib/datadog/tracing/contrib/action_pack/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/action_pack/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/action_pack/utils.rb +0 -2
- data/lib/datadog/tracing/contrib/action_view/configuration/settings.rb +9 -8
- data/lib/datadog/tracing/contrib/action_view/event.rb +1 -1
- data/lib/datadog/tracing/contrib/action_view/events/render_partial.rb +0 -2
- data/lib/datadog/tracing/contrib/action_view/events/render_template.rb +0 -2
- data/lib/datadog/tracing/contrib/action_view/events.rb +1 -1
- data/lib/datadog/tracing/contrib/action_view/ext.rb +11 -11
- data/lib/datadog/tracing/contrib/action_view/instrumentation/partial_renderer.rb +0 -2
- data/lib/datadog/tracing/contrib/action_view/instrumentation/template_renderer.rb +0 -2
- data/lib/datadog/tracing/contrib/action_view/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/action_view/patcher.rb +0 -2
- data/lib/datadog/tracing/contrib/action_view/utils.rb +0 -2
- data/lib/datadog/tracing/contrib/active_job/configuration/settings.rb +14 -8
- data/lib/datadog/tracing/contrib/active_job/event.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/discard.rb +0 -2
- data/lib/datadog/tracing/contrib/active_job/events/enqueue.rb +0 -2
- data/lib/datadog/tracing/contrib/active_job/events/enqueue_at.rb +0 -2
- data/lib/datadog/tracing/contrib/active_job/events/enqueue_retry.rb +0 -2
- data/lib/datadog/tracing/contrib/active_job/events/perform.rb +0 -2
- data/lib/datadog/tracing/contrib/active_job/events/retry_stopped.rb +0 -2
- data/lib/datadog/tracing/contrib/active_job/events.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/ext.rb +24 -24
- data/lib/datadog/tracing/contrib/active_job/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/active_job/log_injection.rb +2 -2
- data/lib/datadog/tracing/contrib/active_job/patcher.rb +2 -2
- data/lib/datadog/tracing/contrib/active_model_serializers/configuration/settings.rb +10 -7
- data/lib/datadog/tracing/contrib/active_model_serializers/event.rb +1 -1
- data/lib/datadog/tracing/contrib/active_model_serializers/events/render.rb +0 -2
- data/lib/datadog/tracing/contrib/active_model_serializers/events/serialize.rb +0 -2
- data/lib/datadog/tracing/contrib/active_model_serializers/events.rb +1 -1
- data/lib/datadog/tracing/contrib/active_model_serializers/ext.rb +11 -11
- data/lib/datadog/tracing/contrib/active_model_serializers/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/active_model_serializers/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/configuration/makara_resolver.rb +0 -2
- data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +18 -13
- data/lib/datadog/tracing/contrib/active_record/configuration/settings.rb +16 -9
- data/lib/datadog/tracing/contrib/active_record/event.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +0 -2
- data/lib/datadog/tracing/contrib/active_record/events/sql.rb +3 -6
- data/lib/datadog/tracing/contrib/active_record/events.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/ext.rb +16 -16
- data/lib/datadog/tracing/contrib/active_record/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/active_record/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/utils.rb +1 -3
- data/lib/datadog/tracing/contrib/active_record/vendor/connection_specification.rb +0 -2
- data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +107 -201
- data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +4 -1
- data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +1 -1
- data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +18 -8
- data/lib/datadog/tracing/contrib/active_support/ext.rb +17 -17
- data/lib/datadog/tracing/contrib/active_support/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/active_support/notifications/event.rb +1 -1
- data/lib/datadog/tracing/contrib/active_support/notifications/subscriber.rb +1 -1
- data/lib/datadog/tracing/contrib/active_support/notifications/subscription.rb +0 -2
- data/lib/datadog/tracing/contrib/active_support/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/analytics.rb +1 -1
- data/lib/datadog/tracing/contrib/auto_instrument.rb +1 -1
- data/lib/datadog/tracing/contrib/aws/configuration/settings.rb +24 -8
- data/lib/datadog/tracing/contrib/aws/ext.rb +36 -14
- data/lib/datadog/tracing/contrib/aws/instrumentation.rb +28 -3
- data/lib/datadog/tracing/contrib/aws/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/aws/parsed_context.rb +4 -2
- data/lib/datadog/tracing/contrib/aws/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/aws/service/base.rb +16 -0
- data/lib/datadog/tracing/contrib/aws/service/dynamodb.rb +22 -0
- data/lib/datadog/tracing/contrib/aws/service/eventbridge.rb +22 -0
- data/lib/datadog/tracing/contrib/aws/service/kinesis.rb +32 -0
- data/lib/datadog/tracing/contrib/aws/service/s3.rb +22 -0
- data/lib/datadog/tracing/contrib/aws/service/sns.rb +30 -0
- data/lib/datadog/tracing/contrib/aws/service/sqs.rb +27 -0
- data/lib/datadog/tracing/contrib/aws/service/states.rb +40 -0
- data/lib/datadog/tracing/contrib/aws/services.rb +17 -3
- data/lib/datadog/tracing/contrib/concurrent_ruby/configuration/settings.rb +4 -3
- data/lib/datadog/tracing/contrib/concurrent_ruby/context_composite_executor_service.rb +15 -15
- data/lib/datadog/tracing/contrib/concurrent_ruby/ext.rb +3 -3
- data/lib/datadog/tracing/contrib/concurrent_ruby/future_patch.rb +4 -11
- data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +2 -3
- data/lib/datadog/tracing/contrib/concurrent_ruby/patcher.rb +9 -3
- data/lib/datadog/tracing/contrib/concurrent_ruby/promises_future_patch.rb +22 -0
- data/lib/datadog/tracing/contrib/configurable.rb +1 -1
- data/lib/datadog/tracing/contrib/configuration/resolver.rb +1 -1
- data/lib/datadog/tracing/contrib/configuration/resolvers/pattern_resolver.rb +1 -1
- data/lib/datadog/tracing/contrib/configuration/settings.rb +1 -5
- data/lib/datadog/tracing/contrib/dalli/configuration/settings.rb +29 -8
- data/lib/datadog/tracing/contrib/dalli/ext.rb +25 -10
- data/lib/datadog/tracing/contrib/dalli/instrumentation.rb +23 -7
- data/lib/datadog/tracing/contrib/dalli/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/dalli/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/dalli/quantize.rb +0 -2
- data/lib/datadog/tracing/contrib/delayed_job/configuration/settings.rb +14 -8
- data/lib/datadog/tracing/contrib/delayed_job/ext.rb +15 -15
- data/lib/datadog/tracing/contrib/delayed_job/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/delayed_job/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/delayed_job/plugin.rb +9 -1
- data/lib/datadog/tracing/contrib/delayed_job/server_internal_tracer/worker.rb +3 -1
- data/lib/datadog/tracing/contrib/elasticsearch/configuration/settings.rb +24 -8
- data/lib/datadog/tracing/contrib/elasticsearch/ext.rb +20 -13
- data/lib/datadog/tracing/contrib/elasticsearch/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +105 -95
- data/lib/datadog/tracing/contrib/elasticsearch/quantize.rb +0 -4
- data/lib/datadog/tracing/contrib/ethon/configuration/settings.rb +27 -10
- data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +52 -7
- data/lib/datadog/tracing/contrib/ethon/ext.rb +18 -11
- data/lib/datadog/tracing/contrib/ethon/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/ethon/multi_patch.rb +10 -3
- data/lib/datadog/tracing/contrib/ethon/patcher.rb +1 -2
- data/lib/datadog/tracing/contrib/excon/configuration/settings.rb +29 -11
- data/lib/datadog/tracing/contrib/excon/ext.rb +15 -8
- data/lib/datadog/tracing/contrib/excon/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/excon/middleware.rb +27 -4
- data/lib/datadog/tracing/contrib/excon/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/ext.rb +55 -0
- data/lib/datadog/tracing/contrib/extensions.rb +32 -2
- data/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +30 -11
- data/lib/datadog/tracing/contrib/faraday/connection.rb +1 -1
- data/lib/datadog/tracing/contrib/faraday/ext.rb +15 -8
- data/lib/datadog/tracing/contrib/faraday/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/faraday/middleware.rb +24 -6
- data/lib/datadog/tracing/contrib/faraday/patcher.rb +0 -2
- data/lib/datadog/tracing/contrib/faraday/rack_builder.rb +1 -1
- data/lib/datadog/tracing/contrib/grape/configuration/settings.rb +9 -7
- data/lib/datadog/tracing/contrib/grape/endpoint.rb +0 -4
- data/lib/datadog/tracing/contrib/grape/ext.rb +15 -15
- data/lib/datadog/tracing/contrib/grape/instrumentation.rb +0 -2
- data/lib/datadog/tracing/contrib/grape/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/grape/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +10 -8
- data/lib/datadog/tracing/contrib/graphql/ext.rb +6 -6
- data/lib/datadog/tracing/contrib/graphql/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/graphql/patcher.rb +0 -2
- data/lib/datadog/tracing/contrib/grpc/configuration/settings.rb +50 -10
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +45 -19
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +43 -26
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor.rb +0 -6
- data/lib/datadog/tracing/contrib/grpc/distributed/fetcher.rb +26 -0
- data/lib/datadog/tracing/contrib/grpc/distributed/propagation.rb +42 -0
- data/lib/datadog/tracing/contrib/grpc/ext.rb +15 -11
- data/lib/datadog/tracing/contrib/grpc/formatting.rb +127 -0
- data/lib/datadog/tracing/contrib/grpc/integration.rb +8 -3
- data/lib/datadog/tracing/contrib/grpc/intercept_with_datadog.rb +1 -1
- data/lib/datadog/tracing/contrib/grpc/patcher.rb +1 -4
- data/lib/datadog/tracing/contrib/hanami/action_tracer.rb +47 -0
- data/lib/datadog/tracing/contrib/hanami/configuration/settings.rb +23 -0
- data/lib/datadog/tracing/contrib/hanami/ext.rb +24 -0
- data/lib/datadog/tracing/contrib/hanami/integration.rb +42 -0
- data/lib/datadog/tracing/contrib/hanami/patcher.rb +33 -0
- data/lib/datadog/tracing/contrib/hanami/plugin.rb +23 -0
- data/lib/datadog/tracing/contrib/hanami/renderer_policy_tracing.rb +41 -0
- data/lib/datadog/tracing/contrib/hanami/router_tracing.rb +44 -0
- data/lib/datadog/tracing/contrib/http/circuit_breaker.rb +6 -9
- data/lib/datadog/tracing/contrib/http/configuration/settings.rb +47 -10
- data/lib/datadog/tracing/contrib/http/distributed/fetcher.rb +38 -0
- data/lib/datadog/tracing/contrib/http/distributed/propagation.rb +37 -0
- data/lib/datadog/tracing/contrib/http/ext.rb +15 -8
- data/lib/datadog/tracing/contrib/http/instrumentation.rb +32 -12
- data/lib/datadog/tracing/contrib/http/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/http/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/http_annotation_helper.rb +1 -1
- data/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb +47 -10
- data/lib/datadog/tracing/contrib/httpclient/ext.rb +16 -8
- data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +27 -8
- data/lib/datadog/tracing/contrib/httpclient/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/httpclient/patcher.rb +0 -2
- data/lib/datadog/tracing/contrib/httprb/configuration/settings.rb +47 -10
- data/lib/datadog/tracing/contrib/httprb/ext.rb +15 -8
- data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +27 -9
- data/lib/datadog/tracing/contrib/httprb/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/httprb/patcher.rb +0 -2
- data/lib/datadog/tracing/contrib/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/kafka/configuration/settings.rb +10 -7
- data/lib/datadog/tracing/contrib/kafka/consumer_event.rb +2 -1
- data/lib/datadog/tracing/contrib/kafka/consumer_group_event.rb +1 -1
- data/lib/datadog/tracing/contrib/kafka/event.rb +2 -1
- data/lib/datadog/tracing/contrib/kafka/events/connection/request.rb +0 -2
- data/lib/datadog/tracing/contrib/kafka/events/consumer/process_batch.rb +0 -2
- data/lib/datadog/tracing/contrib/kafka/events/consumer/process_message.rb +0 -2
- data/lib/datadog/tracing/contrib/kafka/events/consumer_group/heartbeat.rb +0 -2
- data/lib/datadog/tracing/contrib/kafka/events/consumer_group/join_group.rb +0 -2
- data/lib/datadog/tracing/contrib/kafka/events/consumer_group/leave_group.rb +0 -2
- data/lib/datadog/tracing/contrib/kafka/events/consumer_group/sync_group.rb +0 -2
- data/lib/datadog/tracing/contrib/kafka/events/produce_operation/send_messages.rb +1 -2
- data/lib/datadog/tracing/contrib/kafka/events/producer/deliver_messages.rb +1 -2
- data/lib/datadog/tracing/contrib/kafka/events.rb +1 -1
- data/lib/datadog/tracing/contrib/kafka/ext.rb +41 -39
- data/lib/datadog/tracing/contrib/kafka/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/kafka/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/lograge/configuration/settings.rb +4 -3
- data/lib/datadog/tracing/contrib/lograge/ext.rb +2 -2
- data/lib/datadog/tracing/contrib/lograge/instrumentation.rb +3 -18
- data/lib/datadog/tracing/contrib/lograge/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/lograge/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +24 -8
- data/lib/datadog/tracing/contrib/mongodb/ext.rb +24 -14
- data/lib/datadog/tracing/contrib/mongodb/instrumentation.rb +1 -1
- data/lib/datadog/tracing/contrib/mongodb/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/mongodb/parsers.rb +0 -2
- data/lib/datadog/tracing/contrib/mongodb/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +22 -4
- data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +35 -8
- data/lib/datadog/tracing/contrib/mysql2/ext.rb +14 -9
- data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +38 -4
- data/lib/datadog/tracing/contrib/mysql2/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/mysql2/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/opensearch/configuration/settings.rb +52 -0
- data/lib/datadog/tracing/contrib/opensearch/ext.rb +37 -0
- data/lib/datadog/tracing/contrib/opensearch/integration.rb +44 -0
- data/lib/datadog/tracing/contrib/opensearch/patcher.rb +135 -0
- data/lib/datadog/tracing/contrib/opensearch/quantize.rb +81 -0
- data/lib/datadog/tracing/contrib/patchable.rb +1 -1
- data/lib/datadog/tracing/contrib/patcher.rb +3 -5
- data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +36 -8
- data/lib/datadog/tracing/contrib/pg/ext.rb +21 -18
- data/lib/datadog/tracing/contrib/pg/instrumentation.rb +115 -39
- data/lib/datadog/tracing/contrib/pg/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/pg/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/presto/configuration/settings.rb +23 -8
- data/lib/datadog/tracing/contrib/presto/ext.rb +24 -19
- data/lib/datadog/tracing/contrib/presto/instrumentation.rb +17 -5
- data/lib/datadog/tracing/contrib/presto/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/presto/patcher.rb +0 -2
- data/lib/datadog/tracing/contrib/propagation/sql_comment/comment.rb +41 -0
- data/lib/datadog/tracing/contrib/propagation/sql_comment/ext.rb +33 -0
- data/lib/datadog/tracing/contrib/propagation/sql_comment/mode.rb +28 -0
- data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +53 -0
- data/lib/datadog/tracing/contrib/qless/configuration/settings.rb +13 -9
- data/lib/datadog/tracing/contrib/qless/ext.rb +13 -13
- data/lib/datadog/tracing/contrib/qless/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/qless/patcher.rb +1 -2
- data/lib/datadog/tracing/contrib/qless/qless_job.rb +3 -2
- data/lib/datadog/tracing/contrib/qless/tracer_cleaner.rb +1 -1
- data/lib/datadog/tracing/contrib/que/configuration/settings.rb +21 -14
- data/lib/datadog/tracing/contrib/que/ext.rb +0 -2
- data/lib/datadog/tracing/contrib/que/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/que/patcher.rb +0 -2
- data/lib/datadog/tracing/contrib/que/tracer.rb +4 -2
- data/lib/datadog/tracing/contrib/racecar/configuration/settings.rb +18 -8
- data/lib/datadog/tracing/contrib/racecar/event.rb +7 -4
- data/lib/datadog/tracing/contrib/racecar/events/batch.rb +4 -3
- data/lib/datadog/tracing/contrib/racecar/events/consume.rb +0 -2
- data/lib/datadog/tracing/contrib/racecar/events/message.rb +4 -3
- data/lib/datadog/tracing/contrib/racecar/events.rb +1 -1
- data/lib/datadog/tracing/contrib/racecar/ext.rb +19 -18
- data/lib/datadog/tracing/contrib/racecar/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/racecar/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/rack/configuration/settings.rb +16 -14
- data/lib/datadog/tracing/contrib/rack/ext.rb +17 -12
- data/lib/datadog/tracing/contrib/rack/header_collection.rb +38 -0
- data/lib/datadog/tracing/contrib/rack/header_tagging.rb +63 -0
- data/lib/datadog/tracing/contrib/rack/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/rack/middlewares.rb +130 -81
- data/lib/datadog/tracing/contrib/rack/patcher.rb +0 -2
- data/lib/datadog/tracing/contrib/rack/request_queue.rb +0 -2
- data/lib/datadog/tracing/contrib/rails/auto_instrument_railtie.rb +0 -4
- data/lib/datadog/tracing/contrib/rails/configuration/settings.rb +28 -19
- data/lib/datadog/tracing/contrib/rails/ext.rb +6 -6
- data/lib/datadog/tracing/contrib/rails/framework.rb +1 -1
- data/lib/datadog/tracing/contrib/rails/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/rails/log_injection.rb +7 -12
- data/lib/datadog/tracing/contrib/rails/middlewares.rb +1 -1
- data/lib/datadog/tracing/contrib/rails/patcher.rb +10 -43
- data/lib/datadog/tracing/contrib/rails/railtie.rb +3 -5
- data/lib/datadog/tracing/contrib/rails/utils.rb +2 -2
- data/lib/datadog/tracing/contrib/rake/configuration/settings.rb +14 -11
- data/lib/datadog/tracing/contrib/rake/ext.rb +13 -13
- data/lib/datadog/tracing/contrib/rake/instrumentation.rb +0 -2
- data/lib/datadog/tracing/contrib/rake/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/rake/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/redis/configuration/resolver.rb +0 -2
- data/lib/datadog/tracing/contrib/redis/configuration/settings.rb +26 -10
- data/lib/datadog/tracing/contrib/redis/ext.rb +21 -13
- data/lib/datadog/tracing/contrib/redis/instrumentation.rb +13 -39
- data/lib/datadog/tracing/contrib/redis/integration.rb +34 -3
- data/lib/datadog/tracing/contrib/redis/patcher.rb +53 -11
- data/lib/datadog/tracing/contrib/redis/quantize.rb +11 -10
- data/lib/datadog/tracing/contrib/redis/tags.rb +24 -9
- data/lib/datadog/tracing/contrib/redis/trace_middleware.rb +83 -0
- data/lib/datadog/tracing/contrib/redis/vendor/resolver.rb +0 -2
- data/lib/datadog/tracing/contrib/registerable.rb +1 -1
- data/lib/datadog/tracing/contrib/registry.rb +1 -1
- data/lib/datadog/tracing/contrib/resque/configuration/settings.rb +14 -8
- data/lib/datadog/tracing/contrib/resque/ext.rb +8 -8
- data/lib/datadog/tracing/contrib/resque/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/resque/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/resque/resque_job.rb +5 -1
- data/lib/datadog/tracing/contrib/rest_client/configuration/settings.rb +27 -10
- data/lib/datadog/tracing/contrib/rest_client/ext.rb +14 -8
- data/lib/datadog/tracing/contrib/rest_client/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/rest_client/patcher.rb +1 -2
- data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +28 -3
- data/lib/datadog/tracing/contrib/roda/configuration/settings.rb +37 -0
- data/lib/datadog/tracing/contrib/roda/ext.rb +18 -0
- data/lib/datadog/tracing/contrib/roda/instrumentation.rb +76 -0
- data/lib/datadog/tracing/contrib/roda/integration.rb +45 -0
- data/lib/datadog/{ci/contrib/cucumber → tracing/contrib/roda}/patcher.rb +10 -7
- data/lib/datadog/tracing/contrib/semantic_logger/configuration/settings.rb +4 -3
- data/lib/datadog/tracing/contrib/semantic_logger/ext.rb +2 -2
- data/lib/datadog/tracing/contrib/semantic_logger/instrumentation.rb +6 -21
- data/lib/datadog/tracing/contrib/semantic_logger/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/semantic_logger/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/sequel/configuration/settings.rb +10 -7
- data/lib/datadog/tracing/contrib/sequel/database.rb +4 -3
- data/lib/datadog/tracing/contrib/sequel/dataset.rb +5 -2
- data/lib/datadog/tracing/contrib/sequel/ext.rb +9 -9
- data/lib/datadog/tracing/contrib/sequel/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/sequel/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/sequel/utils.rb +7 -6
- data/lib/datadog/tracing/contrib/shoryuken/configuration/settings.rb +15 -9
- data/lib/datadog/tracing/contrib/shoryuken/ext.rb +13 -12
- data/lib/datadog/tracing/contrib/shoryuken/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/shoryuken/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/shoryuken/tracer.rb +5 -1
- data/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +18 -4
- data/lib/datadog/tracing/contrib/sidekiq/configuration/settings.rb +19 -11
- data/lib/datadog/tracing/contrib/sidekiq/distributed/propagation.rb +38 -0
- data/lib/datadog/tracing/contrib/sidekiq/ext.rb +31 -31
- data/lib/datadog/tracing/contrib/sidekiq/integration.rb +8 -2
- data/lib/datadog/tracing/contrib/sidekiq/patcher.rb +15 -3
- data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/heartbeat.rb +14 -5
- data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/job_fetch.rb +3 -1
- data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/redis_info.rb +3 -1
- data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/scheduled_poller.rb +5 -1
- data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/stop.rb +34 -0
- data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +24 -3
- data/lib/datadog/tracing/contrib/sidekiq/{tracing.rb → utils.rb} +2 -2
- data/lib/datadog/tracing/contrib/sinatra/configuration/settings.rb +11 -11
- data/lib/datadog/tracing/contrib/sinatra/env.rb +11 -41
- data/lib/datadog/tracing/contrib/sinatra/ext.rb +23 -19
- data/lib/datadog/tracing/contrib/sinatra/framework.rb +0 -2
- data/lib/datadog/tracing/contrib/sinatra/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/sinatra/patcher.rb +2 -3
- data/lib/datadog/tracing/contrib/sinatra/tracer.rb +8 -82
- data/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb +14 -20
- data/lib/datadog/tracing/contrib/sneakers/configuration/settings.rb +14 -10
- data/lib/datadog/tracing/contrib/sneakers/ext.rb +2 -2
- data/lib/datadog/tracing/contrib/sneakers/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/sneakers/patcher.rb +0 -2
- data/lib/datadog/tracing/contrib/sneakers/tracer.rb +5 -2
- data/lib/datadog/tracing/contrib/span_attribute_schema.rb +92 -0
- data/lib/datadog/tracing/contrib/status_code_matcher.rb +0 -3
- data/lib/datadog/tracing/contrib/stripe/configuration/settings.rb +36 -0
- data/lib/datadog/tracing/contrib/stripe/ext.rb +26 -0
- data/lib/datadog/tracing/contrib/stripe/integration.rb +43 -0
- data/lib/datadog/tracing/contrib/stripe/patcher.rb +28 -0
- data/lib/datadog/tracing/contrib/stripe/request.rb +67 -0
- data/lib/datadog/tracing/contrib/sucker_punch/configuration/settings.rb +10 -7
- data/lib/datadog/tracing/contrib/sucker_punch/exception_handler.rb +1 -1
- data/lib/datadog/tracing/contrib/sucker_punch/ext.rb +14 -14
- data/lib/datadog/tracing/contrib/sucker_punch/instrumentation.rb +0 -2
- data/lib/datadog/tracing/contrib/sucker_punch/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/sucker_punch/patcher.rb +1 -2
- data/lib/datadog/tracing/contrib/utils/database.rb +4 -4
- data/lib/datadog/tracing/contrib/utils/quantization/hash.rb +0 -2
- data/lib/datadog/tracing/contrib/utils/quantization/http.rb +92 -14
- data/lib/datadog/tracing/contrib.rb +5 -1
- data/lib/datadog/tracing/correlation.rb +42 -14
- data/lib/datadog/tracing/diagnostics/environment_logger.rb +165 -0
- data/lib/datadog/{core → tracing}/diagnostics/ext.rb +21 -26
- data/lib/datadog/tracing/diagnostics/health.rb +40 -0
- data/lib/datadog/tracing/distributed/b3_multi.rb +72 -0
- data/lib/datadog/tracing/distributed/b3_single.rb +68 -0
- data/lib/datadog/tracing/distributed/datadog.rb +199 -0
- data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +84 -0
- data/lib/datadog/tracing/distributed/fetcher.rb +21 -0
- data/lib/datadog/tracing/distributed/headers/ext.rb +19 -16
- data/lib/datadog/tracing/distributed/helpers.rb +26 -39
- data/lib/datadog/tracing/distributed/none.rb +18 -0
- data/lib/datadog/tracing/distributed/propagation.rb +127 -0
- data/lib/datadog/tracing/distributed/trace_context.rb +415 -0
- data/lib/datadog/tracing/event.rb +0 -4
- data/lib/datadog/tracing/flush.rb +58 -36
- data/lib/datadog/tracing/metadata/analytics.rb +1 -1
- data/lib/datadog/tracing/metadata/errors.rb +1 -1
- data/lib/datadog/tracing/metadata/ext.rb +29 -14
- data/lib/datadog/tracing/metadata/tagging.rb +17 -4
- data/lib/datadog/tracing/metadata.rb +1 -1
- data/lib/datadog/tracing/pipeline/span_filter.rb +1 -1
- data/lib/datadog/tracing/pipeline/span_processor.rb +1 -1
- data/lib/datadog/tracing/pipeline.rb +0 -4
- data/lib/datadog/tracing/propagation/http.rb +4 -99
- data/lib/datadog/tracing/remote.rb +78 -0
- data/lib/datadog/tracing/runtime/metrics.rb +1 -3
- data/lib/datadog/tracing/sampling/all_sampler.rb +1 -1
- data/lib/datadog/tracing/sampling/ext.rb +30 -1
- data/lib/datadog/tracing/sampling/matcher.rb +1 -1
- data/lib/datadog/tracing/sampling/priority_sampler.rb +58 -5
- data/lib/datadog/tracing/sampling/rate_by_key_sampler.rb +8 -11
- data/lib/datadog/tracing/sampling/rate_by_service_sampler.rb +29 -8
- data/lib/datadog/tracing/sampling/rate_limiter.rb +3 -2
- data/lib/datadog/tracing/sampling/rate_sampler.rb +23 -10
- data/lib/datadog/tracing/sampling/rule.rb +0 -4
- data/lib/datadog/tracing/sampling/rule_sampler.rb +33 -7
- data/lib/datadog/tracing/sampling/sampler.rb +0 -2
- data/lib/datadog/tracing/sampling/span/ext.rb +25 -0
- data/lib/datadog/tracing/sampling/span/matcher.rb +9 -0
- data/lib/datadog/tracing/sampling/span/rule.rb +82 -0
- data/lib/datadog/tracing/sampling/span/rule_parser.rb +104 -0
- data/lib/datadog/tracing/sampling/span/sampler.rb +77 -0
- data/lib/datadog/tracing/span.rb +3 -21
- data/lib/datadog/tracing/span_operation.rb +8 -24
- data/lib/datadog/tracing/sync_writer.rb +4 -6
- data/lib/datadog/tracing/trace_digest.rb +120 -3
- data/lib/datadog/tracing/trace_operation.rb +61 -13
- data/lib/datadog/tracing/trace_segment.rb +20 -7
- data/lib/datadog/tracing/tracer.rb +46 -10
- data/lib/datadog/tracing/transport/http/api/instance.rb +37 -0
- data/lib/datadog/tracing/transport/http/api/spec.rb +19 -0
- data/lib/datadog/tracing/transport/http/api.rb +43 -0
- data/lib/datadog/tracing/transport/http/builder.rb +162 -0
- data/lib/datadog/tracing/transport/http/client.rb +57 -0
- data/lib/datadog/tracing/transport/http/statistics.rb +47 -0
- data/lib/datadog/tracing/transport/http/traces.rb +152 -0
- data/lib/datadog/tracing/transport/http.rb +124 -0
- data/lib/datadog/tracing/transport/io/client.rb +89 -0
- data/lib/datadog/tracing/transport/io/response.rb +27 -0
- data/lib/datadog/tracing/transport/io/traces.rb +101 -0
- data/lib/datadog/tracing/transport/io.rb +30 -0
- data/lib/datadog/tracing/transport/serializable_trace.rb +126 -0
- data/lib/datadog/tracing/transport/statistics.rb +77 -0
- data/lib/datadog/tracing/transport/trace_formatter.rb +209 -0
- data/lib/datadog/tracing/transport/traces.rb +224 -0
- data/lib/datadog/tracing/utils.rb +83 -0
- data/lib/datadog/tracing/workers/trace_writer.rb +6 -7
- data/lib/datadog/tracing/workers.rb +4 -6
- data/lib/datadog/tracing/writer.rb +12 -6
- data/lib/datadog/tracing.rb +1 -1
- data/lib/ddtrace/auto_instrument.rb +1 -1
- data/lib/ddtrace/auto_instrument_base.rb +1 -1
- data/lib/ddtrace/profiling/preload.rb +0 -2
- data/lib/ddtrace/transport/ext.rb +21 -15
- data/lib/ddtrace/version.rb +14 -15
- data/lib/ddtrace.rb +3 -5
- metadata +230 -113
- data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time.c +0 -390
- data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time.h +0 -6
- data/lib/datadog/appsec/assets/waf_rules/risky.json +0 -1499
- data/lib/datadog/appsec/contrib/configuration/settings.rb +0 -20
- data/lib/datadog/appsec/contrib/rack/configuration/settings.rb +0 -22
- data/lib/datadog/appsec/contrib/rack/request.rb +0 -58
- data/lib/datadog/appsec/contrib/rack/response.rb +0 -24
- data/lib/datadog/appsec/contrib/rails/configuration/settings.rb +0 -22
- data/lib/datadog/appsec/contrib/sinatra/configuration/settings.rb +0 -22
- data/lib/datadog/ci/configuration/components.rb +0 -32
- data/lib/datadog/ci/configuration/settings.rb +0 -53
- data/lib/datadog/ci/contrib/cucumber/configuration/settings.rb +0 -33
- data/lib/datadog/ci/contrib/cucumber/ext.rb +0 -22
- data/lib/datadog/ci/contrib/cucumber/formatter.rb +0 -94
- data/lib/datadog/ci/contrib/cucumber/instrumentation.rb +0 -28
- data/lib/datadog/ci/contrib/cucumber/integration.rb +0 -49
- data/lib/datadog/ci/contrib/rspec/configuration/settings.rb +0 -33
- data/lib/datadog/ci/contrib/rspec/example.rb +0 -70
- data/lib/datadog/ci/contrib/rspec/ext.rb +0 -21
- data/lib/datadog/ci/contrib/rspec/integration.rb +0 -50
- data/lib/datadog/ci/contrib/rspec/patcher.rb +0 -27
- data/lib/datadog/ci/ext/app_types.rb +0 -11
- data/lib/datadog/ci/ext/environment.rb +0 -505
- data/lib/datadog/ci/ext/settings.rb +0 -12
- data/lib/datadog/ci/ext/test.rb +0 -37
- data/lib/datadog/ci/extensions.rb +0 -19
- data/lib/datadog/ci/flush.rb +0 -38
- data/lib/datadog/ci/test.rb +0 -83
- data/lib/datadog/ci.rb +0 -20
- data/lib/datadog/core/configuration/dependency_resolver.rb +0 -28
- data/lib/datadog/core/configuration/option_definition_set.rb +0 -22
- data/lib/datadog/core/configuration/option_set.rb +0 -10
- data/lib/datadog/core/utils/object_set.rb +0 -43
- data/lib/datadog/core/utils/string_table.rb +0 -49
- data/lib/datadog/profiling/backtrace_location.rb +0 -34
- data/lib/datadog/profiling/buffer.rb +0 -43
- data/lib/datadog/profiling/collectors/cpu_and_wall_time.rb +0 -27
- data/lib/datadog/profiling/collectors/old_stack.rb +0 -298
- data/lib/datadog/profiling/encoding/profile.rb +0 -43
- data/lib/datadog/profiling/event.rb +0 -15
- data/lib/datadog/profiling/events/stack.rb +0 -82
- data/lib/datadog/profiling/old_ext.rb +0 -42
- data/lib/datadog/profiling/old_recorder.rb +0 -101
- data/lib/datadog/profiling/pprof/builder.rb +0 -127
- data/lib/datadog/profiling/pprof/converter.rb +0 -104
- data/lib/datadog/profiling/pprof/message_set.rb +0 -16
- data/lib/datadog/profiling/pprof/payload.rb +0 -20
- data/lib/datadog/profiling/pprof/pprof.proto +0 -212
- data/lib/datadog/profiling/pprof/pprof_pb.rb +0 -83
- data/lib/datadog/profiling/pprof/stack_sample.rb +0 -141
- data/lib/datadog/profiling/pprof/string_table.rb +0 -12
- data/lib/datadog/profiling/pprof/template.rb +0 -120
- data/lib/datadog/profiling/trace_identifiers/ddtrace.rb +0 -45
- data/lib/datadog/profiling/trace_identifiers/helper.rb +0 -47
- data/lib/datadog/profiling/transport/http/api/endpoint.rb +0 -85
- data/lib/datadog/profiling/transport/http/api/instance.rb +0 -38
- data/lib/datadog/profiling/transport/http/api/spec.rb +0 -42
- data/lib/datadog/profiling/transport/http/api.rb +0 -45
- data/lib/datadog/profiling/transport/http/builder.rb +0 -30
- data/lib/datadog/profiling/transport/http/client.rb +0 -37
- data/lib/datadog/profiling/transport/http/response.rb +0 -21
- data/lib/datadog/profiling/transport/http.rb +0 -118
- data/lib/datadog/tracing/contrib/sinatra/headers.rb +0 -35
- data/lib/datadog/tracing/distributed/headers/b3.rb +0 -55
- data/lib/datadog/tracing/distributed/headers/b3_single.rb +0 -67
- data/lib/datadog/tracing/distributed/headers/datadog.rb +0 -52
- data/lib/datadog/tracing/distributed/headers/parser.rb +0 -37
- data/lib/datadog/tracing/distributed/metadata/b3.rb +0 -55
- data/lib/datadog/tracing/distributed/metadata/b3_single.rb +0 -66
- data/lib/datadog/tracing/distributed/metadata/datadog.rb +0 -73
- data/lib/datadog/tracing/distributed/metadata/parser.rb +0 -34
- data/lib/datadog/tracing/propagation/grpc.rb +0 -98
- data/lib/ddtrace/transport/http/adapters/net.rb +0 -158
- data/lib/ddtrace/transport/http/adapters/registry.rb +0 -27
- data/lib/ddtrace/transport/http/adapters/test.rb +0 -87
- data/lib/ddtrace/transport/http/adapters/unix_socket.rb +0 -79
- data/lib/ddtrace/transport/http/api/endpoint.rb +0 -29
- data/lib/ddtrace/transport/http/api/fallbacks.rb +0 -24
- data/lib/ddtrace/transport/http/api/instance.rb +0 -35
- data/lib/ddtrace/transport/http/api/map.rb +0 -16
- data/lib/ddtrace/transport/http/api/spec.rb +0 -17
- data/lib/ddtrace/transport/http/api.rb +0 -41
- data/lib/ddtrace/transport/http/builder.rb +0 -178
- data/lib/ddtrace/transport/http/client.rb +0 -54
- data/lib/ddtrace/transport/http/env.rb +0 -58
- data/lib/ddtrace/transport/http/response.rb +0 -58
- data/lib/ddtrace/transport/http/statistics.rb +0 -45
- data/lib/ddtrace/transport/http/traces.rb +0 -146
- data/lib/ddtrace/transport/http.rb +0 -121
- data/lib/ddtrace/transport/io/client.rb +0 -87
- data/lib/ddtrace/transport/io/response.rb +0 -25
- data/lib/ddtrace/transport/io/traces.rb +0 -101
- data/lib/ddtrace/transport/io.rb +0 -28
- data/lib/ddtrace/transport/parcel.rb +0 -22
- data/lib/ddtrace/transport/request.rb +0 -15
- data/lib/ddtrace/transport/response.rb +0 -62
- data/lib/ddtrace/transport/serializable_trace.rb +0 -118
- data/lib/ddtrace/transport/statistics.rb +0 -75
- data/lib/ddtrace/transport/trace_formatter.rb +0 -187
- data/lib/ddtrace/transport/traces.rb +0 -216
|
@@ -3,14 +3,21 @@
|
|
|
3
3
|
#include <ruby/thread_native.h>
|
|
4
4
|
#include <ruby/debug.h>
|
|
5
5
|
#include <stdbool.h>
|
|
6
|
+
#include <stdatomic.h>
|
|
6
7
|
#include <signal.h>
|
|
8
|
+
#include <errno.h>
|
|
9
|
+
|
|
7
10
|
#include "helpers.h"
|
|
8
11
|
#include "ruby_helpers.h"
|
|
9
|
-
#include "
|
|
12
|
+
#include "collectors_thread_context.h"
|
|
13
|
+
#include "collectors_dynamic_sampling_rate.h"
|
|
14
|
+
#include "collectors_idle_sampling_helper.h"
|
|
10
15
|
#include "private_vm_api_access.h"
|
|
16
|
+
#include "setup_signal_handler.h"
|
|
17
|
+
#include "time_helpers.h"
|
|
11
18
|
|
|
12
|
-
// Used to trigger the
|
|
13
|
-
// itself; this class only implements the "
|
|
19
|
+
// Used to trigger the execution of Collectors::ThreadState, which implements all of the sampling logic
|
|
20
|
+
// itself; this class only implements the "when to do it" part.
|
|
14
21
|
//
|
|
15
22
|
// This file implements the native bits of the Datadog::Profiling::Collectors::CpuAndWallTimeWorker class
|
|
16
23
|
|
|
@@ -29,7 +36,7 @@
|
|
|
29
36
|
// internals, we may be able to figure out a way of overcoming it. But it's definitely going to be hard so for now
|
|
30
37
|
// we're considering it as a given.
|
|
31
38
|
//
|
|
32
|
-
// ### Flow for triggering samples
|
|
39
|
+
// ### Flow for triggering CPU/Wall-time samples
|
|
33
40
|
//
|
|
34
41
|
// The flow for triggering samples is as follows:
|
|
35
42
|
//
|
|
@@ -54,35 +61,116 @@
|
|
|
54
61
|
// "as soon as it can".
|
|
55
62
|
//
|
|
56
63
|
// 4. The Ruby VM calls our `sample_from_postponed_job` from a thread holding the global VM lock. A sample is recorded by
|
|
57
|
-
// calling `
|
|
64
|
+
// calling `thread_context_collector_sample`.
|
|
65
|
+
//
|
|
66
|
+
// ### TracePoints and Forking
|
|
67
|
+
//
|
|
68
|
+
// When the Ruby VM forks, the CPU/Wall-time profiling stops naturally because it's triggered by a background thread
|
|
69
|
+
// that doesn't get automatically restarted by the VM on the child process. (The profiler does trigger its restart at
|
|
70
|
+
// some point -- see `Profiling::Tasks::Setup` for details).
|
|
71
|
+
//
|
|
72
|
+
// But this doesn't apply to any `TracePoint`s this class may use, which will continue to be active. Thus, we need to
|
|
73
|
+
// always remember consider this case of -- the worker thread may not be alive but the `TracePoint`s can continue to
|
|
74
|
+
// trigger samples.
|
|
58
75
|
//
|
|
59
76
|
// ---
|
|
60
77
|
|
|
78
|
+
#ifndef NO_POSTPONED_TRIGGER
|
|
79
|
+
// Used to call the rb_postponed_job_trigger from Ruby 3.3+. These get initialized in
|
|
80
|
+
// `collectors_cpu_and_wall_time_worker_init` below and always get reused after that.
|
|
81
|
+
static rb_postponed_job_handle_t sample_from_postponed_job_handle;
|
|
82
|
+
static rb_postponed_job_handle_t after_gc_from_postponed_job_handle;
|
|
83
|
+
#endif
|
|
84
|
+
|
|
61
85
|
// Contains state for a single CpuAndWallTimeWorker instance
|
|
62
86
|
struct cpu_and_wall_time_worker_state {
|
|
63
|
-
//
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
87
|
+
// These are immutable after initialization
|
|
88
|
+
|
|
89
|
+
bool gc_profiling_enabled;
|
|
90
|
+
bool no_signals_workaround_enabled;
|
|
91
|
+
bool dynamic_sampling_rate_enabled;
|
|
92
|
+
int allocation_sample_every;
|
|
93
|
+
bool allocation_profiling_enabled;
|
|
94
|
+
VALUE self_instance;
|
|
95
|
+
VALUE thread_context_collector_instance;
|
|
96
|
+
VALUE idle_sampling_helper_instance;
|
|
97
|
+
VALUE owner_thread;
|
|
98
|
+
dynamic_sampling_rate_state dynamic_sampling_rate;
|
|
99
|
+
VALUE gc_tracepoint; // Used to get gc start/finish information
|
|
100
|
+
VALUE object_allocation_tracepoint; // Used to get allocation counts and allocation profiling
|
|
101
|
+
|
|
102
|
+
// These are mutable and used to signal things between the worker thread and other threads
|
|
103
|
+
|
|
104
|
+
atomic_bool should_run;
|
|
69
105
|
// When something goes wrong during sampling, we record the Ruby exception here, so that it can be "re-raised" on
|
|
70
106
|
// the CpuAndWallTimeWorker thread
|
|
71
107
|
VALUE failure_exception;
|
|
108
|
+
// Used by `_native_stop` to flag the worker thread to start (see comment on `_native_sampling_loop`)
|
|
109
|
+
VALUE stop_thread;
|
|
110
|
+
|
|
111
|
+
// Others
|
|
112
|
+
|
|
113
|
+
// Used to detect/avoid nested sampling, e.g. when the object_allocation_tracepoint gets triggered by a memory allocation
|
|
114
|
+
// that happens during another sample.
|
|
115
|
+
bool during_sample;
|
|
116
|
+
|
|
117
|
+
struct stats {
|
|
118
|
+
// How many times we tried to trigger a sample
|
|
119
|
+
unsigned int trigger_sample_attempts;
|
|
120
|
+
// How many times we tried to simulate signal delivery
|
|
121
|
+
unsigned int trigger_simulated_signal_delivery_attempts;
|
|
122
|
+
// How many times we actually simulated signal delivery
|
|
123
|
+
unsigned int simulated_signal_delivery;
|
|
124
|
+
// How many times we actually called rb_postponed_job_register_one from a signal handler
|
|
125
|
+
unsigned int signal_handler_enqueued_sample;
|
|
126
|
+
// How many times the signal handler was called from the wrong thread
|
|
127
|
+
unsigned int signal_handler_wrong_thread;
|
|
128
|
+
// How many times we actually sampled (except GC samples)
|
|
129
|
+
unsigned int sampled;
|
|
130
|
+
// How many times we skipped a sample because of the dynamic sampling rate mechanism
|
|
131
|
+
unsigned int skipped_sample_because_of_dynamic_sampling_rate;
|
|
132
|
+
|
|
133
|
+
// Stats for the results of calling rb_postponed_job_register_one
|
|
134
|
+
// The same function was already waiting to be executed
|
|
135
|
+
unsigned int postponed_job_skipped_already_existed;
|
|
136
|
+
// The function was added to the queue successfully
|
|
137
|
+
unsigned int postponed_job_success;
|
|
138
|
+
// The queue was full
|
|
139
|
+
unsigned int postponed_job_full;
|
|
140
|
+
// The function returned an unknown result code
|
|
141
|
+
unsigned int postponed_job_unknown_result;
|
|
142
|
+
|
|
143
|
+
// Min/max/total wall-time spent sampling (except GC samples)
|
|
144
|
+
uint64_t sampling_time_ns_min;
|
|
145
|
+
uint64_t sampling_time_ns_max;
|
|
146
|
+
uint64_t sampling_time_ns_total;
|
|
147
|
+
// How many times we saw allocations being done inside a sample
|
|
148
|
+
unsigned int allocations_during_sample;
|
|
149
|
+
} stats;
|
|
72
150
|
};
|
|
73
151
|
|
|
74
152
|
static VALUE _native_new(VALUE klass);
|
|
75
|
-
static VALUE _native_initialize(
|
|
153
|
+
static VALUE _native_initialize(
|
|
154
|
+
DDTRACE_UNUSED VALUE _self,
|
|
155
|
+
VALUE self_instance,
|
|
156
|
+
VALUE thread_context_collector_instance,
|
|
157
|
+
VALUE gc_profiling_enabled,
|
|
158
|
+
VALUE idle_sampling_helper_instance,
|
|
159
|
+
VALUE no_signals_workaround_enabled,
|
|
160
|
+
VALUE dynamic_sampling_rate_enabled,
|
|
161
|
+
VALUE dynamic_sampling_rate_overhead_target_percentage,
|
|
162
|
+
VALUE allocation_sample_every,
|
|
163
|
+
VALUE allocation_profiling_enabled
|
|
164
|
+
);
|
|
76
165
|
static void cpu_and_wall_time_worker_typed_data_mark(void *state_ptr);
|
|
77
166
|
static VALUE _native_sampling_loop(VALUE self, VALUE instance);
|
|
78
|
-
static VALUE _native_stop(DDTRACE_UNUSED VALUE _self, VALUE self_instance);
|
|
79
|
-
static
|
|
80
|
-
static void remove_sigprof_signal_handler(void);
|
|
81
|
-
static void block_sigprof_signal_handler_from_running_in_current_thread(void);
|
|
167
|
+
static VALUE _native_stop(DDTRACE_UNUSED VALUE _self, VALUE self_instance, VALUE worker_thread);
|
|
168
|
+
static VALUE stop(VALUE self_instance, VALUE optional_exception);
|
|
82
169
|
static void handle_sampling_signal(DDTRACE_UNUSED int _signal, DDTRACE_UNUSED siginfo_t *_info, DDTRACE_UNUSED void *_ucontext);
|
|
83
170
|
static void *run_sampling_trigger_loop(void *state_ptr);
|
|
84
171
|
static void interrupt_sampling_trigger_loop(void *state_ptr);
|
|
85
172
|
static void sample_from_postponed_job(DDTRACE_UNUSED void *_unused);
|
|
173
|
+
static VALUE rescued_sample_from_postponed_job(VALUE self_instance);
|
|
86
174
|
static VALUE handle_sampling_failure(VALUE self_instance, VALUE exception);
|
|
87
175
|
static VALUE _native_current_sigprof_signal_handler(DDTRACE_UNUSED VALUE self);
|
|
88
176
|
static VALUE release_gvl_and_run_sampling_trigger_loop(VALUE instance);
|
|
@@ -90,19 +178,56 @@ static VALUE _native_is_running(DDTRACE_UNUSED VALUE self, VALUE instance);
|
|
|
90
178
|
static void testing_signal_handler(DDTRACE_UNUSED int _signal, DDTRACE_UNUSED siginfo_t *_info, DDTRACE_UNUSED void *_ucontext);
|
|
91
179
|
static VALUE _native_install_testing_signal_handler(DDTRACE_UNUSED VALUE self);
|
|
92
180
|
static VALUE _native_remove_testing_signal_handler(DDTRACE_UNUSED VALUE self);
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
181
|
+
static VALUE _native_trigger_sample(DDTRACE_UNUSED VALUE self);
|
|
182
|
+
static VALUE _native_gc_tracepoint(DDTRACE_UNUSED VALUE self, VALUE instance);
|
|
183
|
+
static void on_gc_event(VALUE tracepoint_data, DDTRACE_UNUSED void *unused);
|
|
184
|
+
static void after_gc_from_postponed_job(DDTRACE_UNUSED void *_unused);
|
|
185
|
+
static VALUE safely_call(VALUE (*function_to_call_safely)(VALUE), VALUE function_to_call_safely_arg, VALUE instance);
|
|
186
|
+
static VALUE _native_simulate_handle_sampling_signal(DDTRACE_UNUSED VALUE self);
|
|
187
|
+
static VALUE _native_simulate_sample_from_postponed_job(DDTRACE_UNUSED VALUE self);
|
|
188
|
+
static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE instance);
|
|
189
|
+
static VALUE _native_is_sigprof_blocked_in_current_thread(DDTRACE_UNUSED VALUE self);
|
|
190
|
+
static VALUE _native_stats(DDTRACE_UNUSED VALUE self, VALUE instance);
|
|
191
|
+
void *simulate_sampling_signal_delivery(DDTRACE_UNUSED void *_unused);
|
|
192
|
+
static void grab_gvl_and_sample(void);
|
|
193
|
+
static void reset_stats(struct cpu_and_wall_time_worker_state *state);
|
|
194
|
+
static void sleep_for(uint64_t time_ns);
|
|
195
|
+
static VALUE _native_allocation_count(DDTRACE_UNUSED VALUE self);
|
|
196
|
+
static void on_newobj_event(VALUE tracepoint_data, DDTRACE_UNUSED void *unused);
|
|
197
|
+
static void disable_tracepoints(struct cpu_and_wall_time_worker_state *state);
|
|
198
|
+
static VALUE _native_with_blocked_sigprof(DDTRACE_UNUSED VALUE self);
|
|
199
|
+
static VALUE rescued_sample_allocation(VALUE tracepoint_data);
|
|
200
|
+
|
|
201
|
+
// Note on sampler global state safety:
|
|
202
|
+
//
|
|
203
|
+
// Both `active_sampler_instance` and `active_sampler_instance_state` are **GLOBAL** state. Be careful when accessing
|
|
204
|
+
// or modifying them.
|
|
205
|
+
// In particular, it's important to only mutate them while holding the global VM lock, to ensure correctness.
|
|
206
|
+
//
|
|
207
|
+
// This global state is needed because a bunch of functions on this file need to access it from situations
|
|
208
|
+
// (e.g. signal handler) where it's impossible or just awkward to pass it as an argument.
|
|
98
209
|
static VALUE active_sampler_instance = Qnil;
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
210
|
+
static struct cpu_and_wall_time_worker_state *active_sampler_instance_state = NULL;
|
|
211
|
+
|
|
212
|
+
// Used to implement CpuAndWallTimeWorker._native_allocation_count . To be able to use cheap thread-local variables
|
|
213
|
+
// (here with `__thread`, see https://gcc.gnu.org/onlinedocs/gcc/Thread-Local.html), this needs to be global.
|
|
214
|
+
//
|
|
215
|
+
// Carryover of state between profiler instances can happen and is not considered to be a problem -- see expectations for this
|
|
216
|
+
// API documented in profiling.rb .
|
|
217
|
+
__thread uint64_t allocation_count = 0;
|
|
102
218
|
|
|
103
219
|
void collectors_cpu_and_wall_time_worker_init(VALUE profiling_module) {
|
|
104
220
|
rb_global_variable(&active_sampler_instance);
|
|
105
|
-
|
|
221
|
+
|
|
222
|
+
#ifndef NO_POSTPONED_TRIGGER
|
|
223
|
+
int unused_flags = 0;
|
|
224
|
+
sample_from_postponed_job_handle = rb_postponed_job_preregister(unused_flags, sample_from_postponed_job, NULL);
|
|
225
|
+
after_gc_from_postponed_job_handle = rb_postponed_job_preregister(unused_flags, after_gc_from_postponed_job, NULL);
|
|
226
|
+
|
|
227
|
+
if (sample_from_postponed_job_handle == POSTPONED_JOB_HANDLE_INVALID || after_gc_from_postponed_job_handle == POSTPONED_JOB_HANDLE_INVALID) {
|
|
228
|
+
rb_raise(rb_eRuntimeError, "Failed to register profiler postponed jobs (got POSTPONED_JOB_HANDLE_INVALID)");
|
|
229
|
+
}
|
|
230
|
+
#endif
|
|
106
231
|
|
|
107
232
|
VALUE collectors_module = rb_define_module_under(profiling_module, "Collectors");
|
|
108
233
|
VALUE collectors_cpu_and_wall_time_worker_class = rb_define_class_under(collectors_module, "CpuAndWallTimeWorker", rb_cObject);
|
|
@@ -119,13 +244,22 @@ void collectors_cpu_and_wall_time_worker_init(VALUE profiling_module) {
|
|
|
119
244
|
// https://bugs.ruby-lang.org/issues/18007 for a discussion around this.
|
|
120
245
|
rb_define_alloc_func(collectors_cpu_and_wall_time_worker_class, _native_new);
|
|
121
246
|
|
|
122
|
-
rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_initialize", _native_initialize,
|
|
247
|
+
rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_initialize", _native_initialize, 9);
|
|
123
248
|
rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_sampling_loop", _native_sampling_loop, 1);
|
|
124
|
-
rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_stop", _native_stop,
|
|
249
|
+
rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_stop", _native_stop, 2);
|
|
250
|
+
rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_reset_after_fork", _native_reset_after_fork, 1);
|
|
251
|
+
rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_stats", _native_stats, 1);
|
|
252
|
+
rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_allocation_count", _native_allocation_count, 0);
|
|
125
253
|
rb_define_singleton_method(testing_module, "_native_current_sigprof_signal_handler", _native_current_sigprof_signal_handler, 0);
|
|
126
254
|
rb_define_singleton_method(testing_module, "_native_is_running?", _native_is_running, 1);
|
|
127
255
|
rb_define_singleton_method(testing_module, "_native_install_testing_signal_handler", _native_install_testing_signal_handler, 0);
|
|
128
256
|
rb_define_singleton_method(testing_module, "_native_remove_testing_signal_handler", _native_remove_testing_signal_handler, 0);
|
|
257
|
+
rb_define_singleton_method(testing_module, "_native_trigger_sample", _native_trigger_sample, 0);
|
|
258
|
+
rb_define_singleton_method(testing_module, "_native_gc_tracepoint", _native_gc_tracepoint, 1);
|
|
259
|
+
rb_define_singleton_method(testing_module, "_native_simulate_handle_sampling_signal", _native_simulate_handle_sampling_signal, 0);
|
|
260
|
+
rb_define_singleton_method(testing_module, "_native_simulate_sample_from_postponed_job", _native_simulate_sample_from_postponed_job, 0);
|
|
261
|
+
rb_define_singleton_method(testing_module, "_native_is_sigprof_blocked_in_current_thread", _native_is_sigprof_blocked_in_current_thread, 0);
|
|
262
|
+
rb_define_singleton_method(testing_module, "_native_with_blocked_sigprof", _native_with_blocked_sigprof, 0);
|
|
129
263
|
}
|
|
130
264
|
|
|
131
265
|
// This structure is used to define a Ruby object that stores a pointer to a struct cpu_and_wall_time_worker_state
|
|
@@ -135,7 +269,7 @@ static const rb_data_type_t cpu_and_wall_time_worker_typed_data = {
|
|
|
135
269
|
.function = {
|
|
136
270
|
.dmark = cpu_and_wall_time_worker_typed_data_mark,
|
|
137
271
|
.dfree = RUBY_DEFAULT_FREE,
|
|
138
|
-
.dsize = NULL, // We don't track
|
|
272
|
+
.dsize = NULL, // We don't track memory usage (although it'd be cool if we did!)
|
|
139
273
|
//.dcompact = NULL, // FIXME: Add support for compaction
|
|
140
274
|
},
|
|
141
275
|
.flags = RUBY_TYPED_FREE_IMMEDIATELY
|
|
@@ -144,18 +278,69 @@ static const rb_data_type_t cpu_and_wall_time_worker_typed_data = {
|
|
|
144
278
|
static VALUE _native_new(VALUE klass) {
|
|
145
279
|
struct cpu_and_wall_time_worker_state *state = ruby_xcalloc(1, sizeof(struct cpu_and_wall_time_worker_state));
|
|
146
280
|
|
|
147
|
-
state
|
|
148
|
-
|
|
281
|
+
// Note: Any exceptions raised from this note until the TypedData_Wrap_Struct call will lead to the state memory
|
|
282
|
+
// being leaked.
|
|
283
|
+
|
|
284
|
+
state->gc_profiling_enabled = false;
|
|
285
|
+
state->no_signals_workaround_enabled = false;
|
|
286
|
+
state->dynamic_sampling_rate_enabled = true;
|
|
287
|
+
state->allocation_sample_every = 0;
|
|
288
|
+
state->allocation_profiling_enabled = false;
|
|
289
|
+
state->thread_context_collector_instance = Qnil;
|
|
290
|
+
state->idle_sampling_helper_instance = Qnil;
|
|
291
|
+
state->owner_thread = Qnil;
|
|
292
|
+
dynamic_sampling_rate_init(&state->dynamic_sampling_rate);
|
|
293
|
+
state->gc_tracepoint = Qnil;
|
|
294
|
+
state->object_allocation_tracepoint = Qnil;
|
|
295
|
+
|
|
296
|
+
atomic_init(&state->should_run, false);
|
|
149
297
|
state->failure_exception = Qnil;
|
|
298
|
+
state->stop_thread = Qnil;
|
|
150
299
|
|
|
151
|
-
|
|
300
|
+
state->during_sample = false;
|
|
301
|
+
|
|
302
|
+
reset_stats(state);
|
|
303
|
+
|
|
304
|
+
return state->self_instance = TypedData_Wrap_Struct(klass, &cpu_and_wall_time_worker_typed_data, state);
|
|
152
305
|
}
|
|
153
306
|
|
|
154
|
-
static VALUE _native_initialize(
|
|
307
|
+
static VALUE _native_initialize(
|
|
308
|
+
DDTRACE_UNUSED VALUE _self,
|
|
309
|
+
VALUE self_instance,
|
|
310
|
+
VALUE thread_context_collector_instance,
|
|
311
|
+
VALUE gc_profiling_enabled,
|
|
312
|
+
VALUE idle_sampling_helper_instance,
|
|
313
|
+
VALUE no_signals_workaround_enabled,
|
|
314
|
+
VALUE dynamic_sampling_rate_enabled,
|
|
315
|
+
VALUE dynamic_sampling_rate_overhead_target_percentage,
|
|
316
|
+
VALUE allocation_sample_every,
|
|
317
|
+
VALUE allocation_profiling_enabled
|
|
318
|
+
) {
|
|
319
|
+
ENFORCE_BOOLEAN(gc_profiling_enabled);
|
|
320
|
+
ENFORCE_BOOLEAN(no_signals_workaround_enabled);
|
|
321
|
+
ENFORCE_BOOLEAN(dynamic_sampling_rate_enabled);
|
|
322
|
+
ENFORCE_TYPE(allocation_sample_every, T_FIXNUM);
|
|
323
|
+
ENFORCE_TYPE(dynamic_sampling_rate_overhead_target_percentage, T_FLOAT);
|
|
324
|
+
ENFORCE_BOOLEAN(allocation_profiling_enabled);
|
|
325
|
+
|
|
155
326
|
struct cpu_and_wall_time_worker_state *state;
|
|
156
327
|
TypedData_Get_Struct(self_instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
|
157
328
|
|
|
158
|
-
state->
|
|
329
|
+
state->gc_profiling_enabled = (gc_profiling_enabled == Qtrue);
|
|
330
|
+
state->no_signals_workaround_enabled = (no_signals_workaround_enabled == Qtrue);
|
|
331
|
+
state->dynamic_sampling_rate_enabled = (dynamic_sampling_rate_enabled == Qtrue);
|
|
332
|
+
dynamic_sampling_rate_set_overhead_target_percentage(&state->dynamic_sampling_rate, NUM2DBL(dynamic_sampling_rate_overhead_target_percentage));
|
|
333
|
+
state->allocation_sample_every = NUM2INT(allocation_sample_every);
|
|
334
|
+
state->allocation_profiling_enabled = (allocation_profiling_enabled == Qtrue);
|
|
335
|
+
|
|
336
|
+
if (state->allocation_sample_every <= 0) {
|
|
337
|
+
rb_raise(rb_eArgError, "Unexpected value for allocation_sample_every: %d. This value must be > 0.", state->allocation_sample_every);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
state->thread_context_collector_instance = enforce_thread_context_collector_instance(thread_context_collector_instance);
|
|
341
|
+
state->idle_sampling_helper_instance = idle_sampling_helper_instance;
|
|
342
|
+
state->gc_tracepoint = rb_tracepoint_new(Qnil, RUBY_INTERNAL_EVENT_GC_ENTER | RUBY_INTERNAL_EVENT_GC_EXIT, on_gc_event, NULL /* unused */);
|
|
343
|
+
state->object_allocation_tracepoint = rb_tracepoint_new(Qnil, RUBY_INTERNAL_EVENT_NEWOBJ, on_newobj_event, NULL /* unused */);
|
|
159
344
|
|
|
160
345
|
return Qtrue;
|
|
161
346
|
}
|
|
@@ -164,8 +349,13 @@ static VALUE _native_initialize(DDTRACE_UNUSED VALUE _self, VALUE self_instance,
|
|
|
164
349
|
static void cpu_and_wall_time_worker_typed_data_mark(void *state_ptr) {
|
|
165
350
|
struct cpu_and_wall_time_worker_state *state = (struct cpu_and_wall_time_worker_state *) state_ptr;
|
|
166
351
|
|
|
167
|
-
rb_gc_mark(state->
|
|
352
|
+
rb_gc_mark(state->thread_context_collector_instance);
|
|
353
|
+
rb_gc_mark(state->idle_sampling_helper_instance);
|
|
354
|
+
rb_gc_mark(state->owner_thread);
|
|
168
355
|
rb_gc_mark(state->failure_exception);
|
|
356
|
+
rb_gc_mark(state->stop_thread);
|
|
357
|
+
rb_gc_mark(state->gc_tracepoint);
|
|
358
|
+
rb_gc_mark(state->object_allocation_tracepoint);
|
|
169
359
|
}
|
|
170
360
|
|
|
171
361
|
// Called in a background thread created in CpuAndWallTimeWorker#start
|
|
@@ -173,32 +363,74 @@ static VALUE _native_sampling_loop(DDTRACE_UNUSED VALUE _self, VALUE instance) {
|
|
|
173
363
|
struct cpu_and_wall_time_worker_state *state;
|
|
174
364
|
TypedData_Get_Struct(instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
|
175
365
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
366
|
+
struct cpu_and_wall_time_worker_state *old_state = active_sampler_instance_state;
|
|
367
|
+
if (old_state != NULL) {
|
|
368
|
+
if (is_thread_alive(old_state->owner_thread)) {
|
|
369
|
+
rb_raise(
|
|
370
|
+
rb_eRuntimeError,
|
|
371
|
+
"Could not start CpuAndWallTimeWorker: There's already another instance of CpuAndWallTimeWorker active in a different thread"
|
|
372
|
+
);
|
|
373
|
+
} else {
|
|
374
|
+
// The previously active thread seems to have died without cleaning up after itself.
|
|
375
|
+
// In this case, we can still go ahead and start the profiler BUT we make sure to disable any existing tracepoint
|
|
376
|
+
// first as:
|
|
377
|
+
// a) If this is a new instance of the CpuAndWallTimeWorker, we don't want the tracepoint from the old instance
|
|
378
|
+
// being kept around
|
|
379
|
+
// b) If this is the same instance of the CpuAndWallTimeWorker if we call enable on a tracepoint that is already
|
|
380
|
+
// enabled, it will start firing more than once, see https://bugs.ruby-lang.org/issues/19114 for details.
|
|
381
|
+
disable_tracepoints(old_state);
|
|
382
|
+
}
|
|
181
383
|
}
|
|
182
384
|
|
|
385
|
+
// We use `stop_thread` to distinguish when `_native_stop` was called before we actually had a chance to start. In this
|
|
386
|
+
// situation we stop immediately and never even start the sampling trigger loop.
|
|
387
|
+
if (state->stop_thread == rb_thread_current()) return Qnil;
|
|
388
|
+
|
|
389
|
+
// Reset the dynamic sampling rate state, if any (reminder: the monotonic clock reference may change after a fork)
|
|
390
|
+
dynamic_sampling_rate_reset(&state->dynamic_sampling_rate);
|
|
391
|
+
|
|
183
392
|
// This write to a global is thread-safe BECAUSE we're still holding on to the global VM lock at this point
|
|
393
|
+
active_sampler_instance_state = state;
|
|
184
394
|
active_sampler_instance = instance;
|
|
185
|
-
|
|
395
|
+
state->owner_thread = rb_thread_current();
|
|
186
396
|
|
|
187
|
-
state->should_run
|
|
397
|
+
atomic_store(&state->should_run, true);
|
|
188
398
|
|
|
189
399
|
block_sigprof_signal_handler_from_running_in_current_thread(); // We want to interrupt the thread with the global VM lock, never this one
|
|
190
400
|
|
|
191
|
-
install_sigprof_signal_handler(handle_sampling_signal);
|
|
192
|
-
|
|
193
401
|
// Release GVL, get to the actual work!
|
|
194
402
|
int exception_state;
|
|
195
403
|
rb_protect(release_gvl_and_run_sampling_trigger_loop, instance, &exception_state);
|
|
196
404
|
|
|
197
405
|
// The sample trigger loop finished (either cleanly or with an error); let's clean up
|
|
198
406
|
|
|
199
|
-
|
|
407
|
+
disable_tracepoints(state);
|
|
408
|
+
|
|
409
|
+
active_sampler_instance_state = NULL;
|
|
200
410
|
active_sampler_instance = Qnil;
|
|
201
|
-
|
|
411
|
+
state->owner_thread = Qnil;
|
|
412
|
+
|
|
413
|
+
// If this `Thread` is about to die, why is this important? It's because Ruby caches native threads for a period after
|
|
414
|
+
// the `Thread` dies, and reuses them if a new Ruby `Thread` gets created. This means that while conceptually the
|
|
415
|
+
// worker background `Thread` is about to die, the low-level native OS thread can be reused for something else in the Ruby app.
|
|
416
|
+
// Then, the reused thread would "inherit" the SIGPROF blocking, which is... really unexpected.
|
|
417
|
+
// This actually caused a flaky test -- the `native_extension_spec.rb` creates a `Thread` and tries to specifically
|
|
418
|
+
// send SIGPROF signals to it, and oops it could fail if it got the reused native thread from the worker which still
|
|
419
|
+
// had SIGPROF delivery blocked. :hide_the_pain_harold:
|
|
420
|
+
unblock_sigprof_signal_handler_from_running_in_current_thread();
|
|
421
|
+
|
|
422
|
+
// Why replace and not use remove the signal handler? We do this because when a process receives a SIGPROF without
|
|
423
|
+
// having an explicit signal handler set up, the process will instantly terminate with a confusing
|
|
424
|
+
// "Profiling timer expired" message left behind. (This message doesn't come from us -- it's the default message for
|
|
425
|
+
// an unhandled SIGPROF. Pretty confusing UNIX/POSIX behavior...)
|
|
426
|
+
//
|
|
427
|
+
// Unfortunately, because signal delivery is asynchronous, there's no way to guarantee that there are no pending
|
|
428
|
+
// profiler-sent signals by the time we get here and want to clean up.
|
|
429
|
+
// @ivoanjo: I suspect this will never happen, but the cost of getting it wrong is really high (VM terminates) so this
|
|
430
|
+
// is a just-in-case situation.
|
|
431
|
+
//
|
|
432
|
+
// Note 2: This can raise exceptions as well, so make sure that all cleanups are done by the time we get here.
|
|
433
|
+
replace_sigprof_signal_handler_with_empty_handler(handle_sampling_signal);
|
|
202
434
|
|
|
203
435
|
// Ensure that instance is not garbage collected while the native sampling loop is running; this is probably not needed, but just in case
|
|
204
436
|
RB_GC_GUARD(instance);
|
|
@@ -208,95 +440,128 @@ static VALUE _native_sampling_loop(DDTRACE_UNUSED VALUE _self, VALUE instance) {
|
|
|
208
440
|
return Qnil;
|
|
209
441
|
}
|
|
210
442
|
|
|
211
|
-
static VALUE _native_stop(DDTRACE_UNUSED VALUE _self, VALUE self_instance) {
|
|
443
|
+
static VALUE _native_stop(DDTRACE_UNUSED VALUE _self, VALUE self_instance, VALUE worker_thread) {
|
|
212
444
|
struct cpu_and_wall_time_worker_state *state;
|
|
213
445
|
TypedData_Get_Struct(self_instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
|
214
446
|
|
|
215
|
-
state->
|
|
447
|
+
state->stop_thread = worker_thread;
|
|
216
448
|
|
|
217
|
-
return
|
|
449
|
+
return stop(self_instance, /* optional_exception: */ Qnil);
|
|
218
450
|
}
|
|
219
451
|
|
|
220
|
-
static
|
|
221
|
-
struct
|
|
222
|
-
struct
|
|
223
|
-
.sa_flags = SA_RESTART | SA_SIGINFO,
|
|
224
|
-
.sa_sigaction = signal_handler_function
|
|
225
|
-
};
|
|
226
|
-
sigemptyset(&signal_handler_config.sa_mask);
|
|
227
|
-
|
|
228
|
-
if (sigaction(SIGPROF, &signal_handler_config, &existing_signal_handler_config) != 0) {
|
|
229
|
-
rb_sys_fail("Could not start CpuAndWallTimeWorker: Could not install signal handler");
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
// In some corner cases (e.g. after a fork), our signal handler may still be around, and that's ok
|
|
233
|
-
if (existing_signal_handler_config.sa_sigaction == handle_sampling_signal) return;
|
|
234
|
-
|
|
235
|
-
if (existing_signal_handler_config.sa_handler != NULL || existing_signal_handler_config.sa_sigaction != NULL) {
|
|
236
|
-
// A previous signal handler already existed. Currently we don't support this situation, so let's just back out
|
|
237
|
-
// of the installation.
|
|
238
|
-
|
|
239
|
-
if (sigaction(SIGPROF, &existing_signal_handler_config, NULL) != 0) {
|
|
240
|
-
rb_sys_fail(
|
|
241
|
-
"Could not start CpuAndWallTimeWorker: Could not re-install pre-existing SIGPROF signal handler. " \
|
|
242
|
-
"This may break the component had installed it."
|
|
243
|
-
);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
rb_raise(rb_eRuntimeError, "Could not start CpuAndWallTimeWorker: There's a pre-existing SIGPROF signal handler");
|
|
247
|
-
}
|
|
248
|
-
}
|
|
452
|
+
static VALUE stop(VALUE self_instance, VALUE optional_exception) {
|
|
453
|
+
struct cpu_and_wall_time_worker_state *state;
|
|
454
|
+
TypedData_Get_Struct(self_instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
|
249
455
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
.sa_handler = SIG_DFL, // Reset back to default
|
|
253
|
-
.sa_flags = SA_RESTART // TODO: Unclear if this is actually needed/does anything at all
|
|
254
|
-
};
|
|
255
|
-
sigemptyset(&signal_handler_config.sa_mask);
|
|
456
|
+
atomic_store(&state->should_run, false);
|
|
457
|
+
state->failure_exception = optional_exception;
|
|
256
458
|
|
|
257
|
-
|
|
258
|
-
|
|
459
|
+
// Disable the tracepoints as soon as possible, so the VM doesn't keep on calling them
|
|
460
|
+
disable_tracepoints(state);
|
|
259
461
|
|
|
260
|
-
|
|
261
|
-
sigset_t signals_to_block;
|
|
262
|
-
sigemptyset(&signals_to_block);
|
|
263
|
-
sigaddset(&signals_to_block, SIGPROF);
|
|
264
|
-
pthread_sigmask(SIG_BLOCK, &signals_to_block, NULL);
|
|
462
|
+
return Qtrue;
|
|
265
463
|
}
|
|
266
464
|
|
|
465
|
+
// NOTE: Remember that this will run in the thread and within the scope of user code, including user C code.
|
|
466
|
+
// We need to be careful not to change any state that may be observed OR to restore it if we do. For instance, if anything
|
|
467
|
+
// we do here can set `errno`, then we must be careful to restore the old `errno` after the fact.
|
|
267
468
|
static void handle_sampling_signal(DDTRACE_UNUSED int _signal, DDTRACE_UNUSED siginfo_t *_info, DDTRACE_UNUSED void *_ucontext) {
|
|
268
|
-
|
|
269
|
-
|
|
469
|
+
struct cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
|
|
470
|
+
|
|
471
|
+
// This can potentially happen if the CpuAndWallTimeWorker was stopped while the signal delivery was happening; nothing to do
|
|
472
|
+
if (state == NULL) return;
|
|
473
|
+
|
|
474
|
+
if (
|
|
475
|
+
!ruby_native_thread_p() || // Not a Ruby thread
|
|
476
|
+
!is_current_thread_holding_the_gvl() || // Not safe to enqueue a sample from this thread
|
|
477
|
+
!ddtrace_rb_ractor_main_p() // We're not on the main Ractor; we currently don't support profiling non-main Ractors
|
|
478
|
+
) {
|
|
479
|
+
state->stats.signal_handler_wrong_thread++;
|
|
480
|
+
return;
|
|
270
481
|
}
|
|
271
482
|
|
|
272
483
|
// We implicitly assume there can be no concurrent nor nested calls to handle_sampling_signal because
|
|
273
|
-
// a) we get triggered using SIGPROF, and the docs state second SIGPROF will not interrupt an existing one
|
|
484
|
+
// a) we get triggered using SIGPROF, and the docs state a second SIGPROF will not interrupt an existing one
|
|
274
485
|
// b) we validate we are in the thread that has the global VM lock; if a different thread gets a signal, it will return early
|
|
275
486
|
// because it will not have the global VM lock
|
|
276
|
-
// TODO: Validate that this does not impact Ractors
|
|
277
487
|
|
|
278
488
|
// Note: rb_postponed_job_register_one ensures that if there's a previous sample_from_postponed_job queued for execution
|
|
279
489
|
// then we will not queue a second one. It does this by doing a linear scan on the existing jobs; in the future we
|
|
280
490
|
// may want to implement that check ourselves.
|
|
281
491
|
|
|
282
|
-
|
|
283
|
-
|
|
492
|
+
state->stats.signal_handler_enqueued_sample++;
|
|
493
|
+
|
|
494
|
+
// Note: If we ever want to get rid of rb_postponed_job_register_one, remember not to clobber Ruby exceptions, as
|
|
495
|
+
// this function does this helpful job for us now -- https://github.com/ruby/ruby/commit/a98e343d39c4d7bf1e2190b076720f32d9f298b3.
|
|
496
|
+
#ifndef NO_POSTPONED_TRIGGER // Ruby 3.3+
|
|
497
|
+
rb_postponed_job_trigger(sample_from_postponed_job_handle);
|
|
498
|
+
state->stats.postponed_job_success++; // Always succeeds
|
|
499
|
+
#else
|
|
500
|
+
int result = rb_postponed_job_register_one(0, sample_from_postponed_job, NULL);
|
|
501
|
+
|
|
502
|
+
// Officially, the result of rb_postponed_job_register_one is documented as being opaque, but in practice it does not
|
|
503
|
+
// seem to have changed between Ruby 2.3 and 3.2, and so we track it as a debugging mechanism
|
|
504
|
+
switch (result) {
|
|
505
|
+
case 0:
|
|
506
|
+
state->stats.postponed_job_full++; break;
|
|
507
|
+
case 1:
|
|
508
|
+
state->stats.postponed_job_success++; break;
|
|
509
|
+
case 2:
|
|
510
|
+
state->stats.postponed_job_skipped_already_existed++; break;
|
|
511
|
+
default:
|
|
512
|
+
state->stats.postponed_job_unknown_result++;
|
|
513
|
+
}
|
|
514
|
+
#endif
|
|
284
515
|
}
|
|
285
516
|
|
|
286
517
|
// The actual sampling trigger loop always runs **without** the global vm lock.
|
|
287
518
|
static void *run_sampling_trigger_loop(void *state_ptr) {
|
|
288
519
|
struct cpu_and_wall_time_worker_state *state = (struct cpu_and_wall_time_worker_state *) state_ptr;
|
|
289
520
|
|
|
290
|
-
|
|
521
|
+
uint64_t minimum_time_between_signals = MILLIS_AS_NS(10);
|
|
522
|
+
|
|
523
|
+
while (atomic_load(&state->should_run)) {
|
|
524
|
+
state->stats.trigger_sample_attempts++;
|
|
525
|
+
|
|
526
|
+
if (state->no_signals_workaround_enabled) {
|
|
527
|
+
// In the no_signals_workaround_enabled mode, the profiler never sends SIGPROF signals.
|
|
528
|
+
//
|
|
529
|
+
// This is a fallback for a few incompatibilities and limitations -- see the code that decides when to enable
|
|
530
|
+
// `no_signals_workaround_enabled` in `Profiling::Component` for details.
|
|
531
|
+
//
|
|
532
|
+
// Thus, we instead pretty please ask Ruby to let us run. This means profiling data can be biased by when the Ruby
|
|
533
|
+
// scheduler chooses to schedule us.
|
|
534
|
+
state->stats.trigger_simulated_signal_delivery_attempts++;
|
|
535
|
+
grab_gvl_and_sample(); // Note: Can raise exceptions
|
|
536
|
+
} else {
|
|
537
|
+
current_gvl_owner owner = gvl_owner();
|
|
538
|
+
if (owner.valid) {
|
|
539
|
+
// Note that reading the GVL owner and sending them a signal is a race -- the Ruby VM keeps on executing while
|
|
540
|
+
// we're doing this, so we may still not signal the correct thread from time to time, but our signal handler
|
|
541
|
+
// includes a check to see if it got called in the right thread
|
|
542
|
+
pthread_kill(owner.owner, SIGPROF);
|
|
543
|
+
} else {
|
|
544
|
+
// If no thread owns the Global VM Lock, the application is probably idle at the moment. We still want to sample
|
|
545
|
+
// so we "ask a friend" (the IdleSamplingHelper component) to grab the GVL and simulate getting a SIGPROF.
|
|
546
|
+
//
|
|
547
|
+
// In a previous version of the code, we called `grab_gvl_and_sample` directly BUT this was problematic because
|
|
548
|
+
// Ruby may concurrently get busy and so the CpuAndWallTimeWorker would be blocked in line to acquire the GVL
|
|
549
|
+
// for an uncontrolled amount of time. (This can still happen to the IdleSamplingHelper, but the
|
|
550
|
+
// CpuAndWallTimeWorker will still be free to interrupt the Ruby VM and keep sampling for the entire blocking period).
|
|
551
|
+
state->stats.trigger_simulated_signal_delivery_attempts++;
|
|
552
|
+
idle_sampling_helper_request_action(state->idle_sampling_helper_instance, grab_gvl_and_sample);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
291
555
|
|
|
292
|
-
|
|
293
|
-
// TODO: This is still a placeholder for a more complex mechanism. In particular:
|
|
294
|
-
// * We want to signal a particular thread or threads, not the process in general
|
|
295
|
-
// * We want to track if a signal landed on the thread holding the global VM lock and do something about it
|
|
296
|
-
// * We want to do more than having a fixed sampling rate
|
|
556
|
+
sleep_for(minimum_time_between_signals);
|
|
297
557
|
|
|
298
|
-
|
|
299
|
-
|
|
558
|
+
// The dynamic sampling rate module keeps track of how long samples are taking, and in here we extend our sleep time
|
|
559
|
+
// to take that into account.
|
|
560
|
+
// Note that we deliberately should NOT combine this sleep_for with the one above because the result of
|
|
561
|
+
// `dynamic_sampling_rate_get_sleep` may have changed while the above sleep was ongoing.
|
|
562
|
+
uint64_t extra_sleep =
|
|
563
|
+
dynamic_sampling_rate_get_sleep(&state->dynamic_sampling_rate, monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE));
|
|
564
|
+
if (state->dynamic_sampling_rate_enabled && extra_sleep > 0) sleep_for(extra_sleep);
|
|
300
565
|
}
|
|
301
566
|
|
|
302
567
|
return NULL; // Unused
|
|
@@ -306,43 +571,68 @@ static void *run_sampling_trigger_loop(void *state_ptr) {
|
|
|
306
571
|
static void interrupt_sampling_trigger_loop(void *state_ptr) {
|
|
307
572
|
struct cpu_and_wall_time_worker_state *state = (struct cpu_and_wall_time_worker_state *) state_ptr;
|
|
308
573
|
|
|
309
|
-
state->should_run
|
|
574
|
+
atomic_store(&state->should_run, false);
|
|
310
575
|
}
|
|
311
576
|
|
|
312
577
|
static void sample_from_postponed_job(DDTRACE_UNUSED void *_unused) {
|
|
313
|
-
|
|
578
|
+
struct cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
|
|
314
579
|
|
|
315
580
|
// This can potentially happen if the CpuAndWallTimeWorker was stopped while the postponed job was waiting to be executed; nothing to do
|
|
316
|
-
if (
|
|
581
|
+
if (state == NULL) return;
|
|
317
582
|
|
|
318
|
-
|
|
319
|
-
|
|
583
|
+
// @ivoanjo: I'm not sure this can ever happen because `handle_sampling_signal` only enqueues this callback if
|
|
584
|
+
// it's running on the main Ractor, but just in case...
|
|
585
|
+
if (!ddtrace_rb_ractor_main_p()) {
|
|
586
|
+
return; // We're not on the main Ractor; we currently don't support profiling non-main Ractors
|
|
587
|
+
}
|
|
320
588
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
function_to_call_safely,
|
|
328
|
-
function_to_call_safely_arg,
|
|
329
|
-
exception_handler_function,
|
|
330
|
-
exception_handler_function_arg,
|
|
331
|
-
rb_eException, // rb_eException is the base class of all Ruby exceptions
|
|
332
|
-
0 // Required by API to be the last argument
|
|
333
|
-
);
|
|
589
|
+
state->during_sample = true;
|
|
590
|
+
|
|
591
|
+
// Rescue against any exceptions that happen during sampling
|
|
592
|
+
safely_call(rescued_sample_from_postponed_job, state->self_instance, state->self_instance);
|
|
593
|
+
|
|
594
|
+
state->during_sample = false;
|
|
334
595
|
}
|
|
335
596
|
|
|
336
|
-
static VALUE
|
|
597
|
+
static VALUE rescued_sample_from_postponed_job(VALUE self_instance) {
|
|
337
598
|
struct cpu_and_wall_time_worker_state *state;
|
|
338
599
|
TypedData_Get_Struct(self_instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
|
339
600
|
|
|
340
|
-
|
|
341
|
-
|
|
601
|
+
long wall_time_ns_before_sample = monotonic_wall_time_now_ns(RAISE_ON_FAILURE);
|
|
602
|
+
|
|
603
|
+
if (state->dynamic_sampling_rate_enabled && !dynamic_sampling_rate_should_sample(&state->dynamic_sampling_rate, wall_time_ns_before_sample)) {
|
|
604
|
+
state->stats.skipped_sample_because_of_dynamic_sampling_rate++;
|
|
605
|
+
return Qnil;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
state->stats.sampled++;
|
|
609
|
+
|
|
610
|
+
VALUE profiler_overhead_stack_thread = state->owner_thread; // Used to attribute profiler overhead to a different stack
|
|
611
|
+
thread_context_collector_sample(state->thread_context_collector_instance, wall_time_ns_before_sample, profiler_overhead_stack_thread);
|
|
612
|
+
|
|
613
|
+
long wall_time_ns_after_sample = monotonic_wall_time_now_ns(RAISE_ON_FAILURE);
|
|
614
|
+
long delta_ns = wall_time_ns_after_sample - wall_time_ns_before_sample;
|
|
615
|
+
|
|
616
|
+
// Guard against wall-time going backwards, see https://github.com/DataDog/dd-trace-rb/pull/2336 for discussion.
|
|
617
|
+
uint64_t sampling_time_ns = delta_ns < 0 ? 0 : delta_ns;
|
|
618
|
+
|
|
619
|
+
state->stats.sampling_time_ns_min = uint64_min_of(sampling_time_ns, state->stats.sampling_time_ns_min);
|
|
620
|
+
state->stats.sampling_time_ns_max = uint64_max_of(sampling_time_ns, state->stats.sampling_time_ns_max);
|
|
621
|
+
state->stats.sampling_time_ns_total += sampling_time_ns;
|
|
342
622
|
|
|
623
|
+
dynamic_sampling_rate_after_sample(&state->dynamic_sampling_rate, wall_time_ns_after_sample, sampling_time_ns);
|
|
624
|
+
|
|
625
|
+
// Return a dummy VALUE because we're called from rb_rescue2 which requires it
|
|
626
|
+
return Qnil;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
static VALUE handle_sampling_failure(VALUE self_instance, VALUE exception) {
|
|
630
|
+
stop(self_instance, exception);
|
|
343
631
|
return Qnil;
|
|
344
632
|
}
|
|
345
633
|
|
|
634
|
+
// This method exists only to enable testing Datadog::Profiling::Collectors::CpuAndWallTimeWorker behavior using RSpec.
|
|
635
|
+
// It SHOULD NOT be used for other purposes.
|
|
346
636
|
static VALUE _native_current_sigprof_signal_handler(DDTRACE_UNUSED VALUE self) {
|
|
347
637
|
struct sigaction existing_signal_handler_config = {.sa_sigaction = NULL};
|
|
348
638
|
if (sigaction(SIGPROF, NULL, &existing_signal_handler_config) != 0) {
|
|
@@ -351,6 +641,8 @@ static VALUE _native_current_sigprof_signal_handler(DDTRACE_UNUSED VALUE self) {
|
|
|
351
641
|
|
|
352
642
|
if (existing_signal_handler_config.sa_sigaction == handle_sampling_signal) {
|
|
353
643
|
return ID2SYM(rb_intern("profiling"));
|
|
644
|
+
} else if (existing_signal_handler_config.sa_sigaction == empty_signal_handler) {
|
|
645
|
+
return ID2SYM(rb_intern("empty"));
|
|
354
646
|
} else if (existing_signal_handler_config.sa_sigaction != NULL) {
|
|
355
647
|
return ID2SYM(rb_intern("other"));
|
|
356
648
|
} else {
|
|
@@ -362,6 +654,12 @@ static VALUE release_gvl_and_run_sampling_trigger_loop(VALUE instance) {
|
|
|
362
654
|
struct cpu_and_wall_time_worker_state *state;
|
|
363
655
|
TypedData_Get_Struct(instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
|
364
656
|
|
|
657
|
+
// Final preparations: Setup signal handler and enable tracepoints. We run these here and not in `_native_sampling_loop`
|
|
658
|
+
// because they may raise exceptions.
|
|
659
|
+
install_sigprof_signal_handler(handle_sampling_signal, "handle_sampling_signal");
|
|
660
|
+
if (state->gc_profiling_enabled) rb_tracepoint_enable(state->gc_tracepoint);
|
|
661
|
+
if (state->allocation_profiling_enabled) rb_tracepoint_enable(state->object_allocation_tracepoint);
|
|
662
|
+
|
|
365
663
|
rb_thread_call_without_gvl(run_sampling_trigger_loop, state, interrupt_sampling_trigger_loop, state);
|
|
366
664
|
|
|
367
665
|
// If we stopped sampling due to an exception, re-raise it (now in the worker thread)
|
|
@@ -370,22 +668,314 @@ static VALUE release_gvl_and_run_sampling_trigger_loop(VALUE instance) {
|
|
|
370
668
|
return Qnil;
|
|
371
669
|
}
|
|
372
670
|
|
|
671
|
+
// This method exists only to enable testing Datadog::Profiling::Collectors::CpuAndWallTimeWorker behavior using RSpec.
|
|
672
|
+
// It SHOULD NOT be used for other purposes.
|
|
373
673
|
static VALUE _native_is_running(DDTRACE_UNUSED VALUE self, VALUE instance) {
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
674
|
+
struct cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
|
|
675
|
+
|
|
676
|
+
return (state != NULL && is_thread_alive(state->owner_thread) && state->self_instance == instance) ? Qtrue : Qfalse;
|
|
377
677
|
}
|
|
378
678
|
|
|
379
679
|
static void testing_signal_handler(DDTRACE_UNUSED int _signal, DDTRACE_UNUSED siginfo_t *_info, DDTRACE_UNUSED void *_ucontext) {
|
|
380
680
|
/* Does nothing on purpose */
|
|
381
681
|
}
|
|
382
682
|
|
|
683
|
+
// This method exists only to enable testing Datadog::Profiling::Collectors::CpuAndWallTimeWorker behavior using RSpec.
|
|
684
|
+
// It SHOULD NOT be used for other purposes.
|
|
383
685
|
static VALUE _native_install_testing_signal_handler(DDTRACE_UNUSED VALUE self) {
|
|
384
|
-
install_sigprof_signal_handler(testing_signal_handler);
|
|
686
|
+
install_sigprof_signal_handler(testing_signal_handler, "testing_signal_handler");
|
|
385
687
|
return Qtrue;
|
|
386
688
|
}
|
|
387
689
|
|
|
690
|
+
// This method exists only to enable testing Datadog::Profiling::Collectors::CpuAndWallTimeWorker behavior using RSpec.
|
|
691
|
+
// It SHOULD NOT be used for other purposes.
|
|
388
692
|
static VALUE _native_remove_testing_signal_handler(DDTRACE_UNUSED VALUE self) {
|
|
389
693
|
remove_sigprof_signal_handler();
|
|
390
694
|
return Qtrue;
|
|
391
695
|
}
|
|
696
|
+
|
|
697
|
+
// This method exists only to enable testing Datadog::Profiling::Collectors::CpuAndWallTimeWorker behavior using RSpec.
|
|
698
|
+
// It SHOULD NOT be used for other purposes.
|
|
699
|
+
static VALUE _native_trigger_sample(DDTRACE_UNUSED VALUE self) {
|
|
700
|
+
sample_from_postponed_job(NULL);
|
|
701
|
+
return Qtrue;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
// This method exists only to enable testing Datadog::Profiling::Collectors::CpuAndWallTimeWorker behavior using RSpec.
|
|
705
|
+
// It SHOULD NOT be used for other purposes.
|
|
706
|
+
static VALUE _native_gc_tracepoint(DDTRACE_UNUSED VALUE self, VALUE instance) {
|
|
707
|
+
struct cpu_and_wall_time_worker_state *state;
|
|
708
|
+
TypedData_Get_Struct(instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
|
709
|
+
|
|
710
|
+
return state->gc_tracepoint;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
// Implements tracking of cpu-time and wall-time spent doing GC. This function is called by Ruby from the `gc_tracepoint`
|
|
714
|
+
// when the RUBY_INTERNAL_EVENT_GC_ENTER and RUBY_INTERNAL_EVENT_GC_EXIT events are triggered.
|
|
715
|
+
//
|
|
716
|
+
// See the comments on
|
|
717
|
+
// * thread_context_collector_on_gc_start
|
|
718
|
+
// * thread_context_collector_on_gc_finish
|
|
719
|
+
// * thread_context_collector_sample_after_gc
|
|
720
|
+
//
|
|
721
|
+
// For the expected times in which to call them, and their assumptions.
|
|
722
|
+
//
|
|
723
|
+
// Safety: This function gets called while Ruby is doing garbage collection. While Ruby is doing garbage collection,
|
|
724
|
+
// *NO ALLOCATION* is allowed. This function, and any it calls must never trigger memory or object allocation.
|
|
725
|
+
// This includes exceptions and use of ruby_xcalloc (because xcalloc can trigger GC)!
|
|
726
|
+
static void on_gc_event(VALUE tracepoint_data, DDTRACE_UNUSED void *unused) {
|
|
727
|
+
if (!ddtrace_rb_ractor_main_p()) {
|
|
728
|
+
return; // We're not on the main Ractor; we currently don't support profiling non-main Ractors
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
int event = rb_tracearg_event_flag(rb_tracearg_from_tracepoint(tracepoint_data));
|
|
732
|
+
if (event != RUBY_INTERNAL_EVENT_GC_ENTER && event != RUBY_INTERNAL_EVENT_GC_EXIT) return; // Unknown event
|
|
733
|
+
|
|
734
|
+
struct cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
|
|
735
|
+
|
|
736
|
+
// This should not happen in a normal situation because the tracepoint is always enabled after the instance is set
|
|
737
|
+
// and disabled before it is cleared, but just in case...
|
|
738
|
+
if (state == NULL) return;
|
|
739
|
+
|
|
740
|
+
if (event == RUBY_INTERNAL_EVENT_GC_ENTER) {
|
|
741
|
+
thread_context_collector_on_gc_start(state->thread_context_collector_instance);
|
|
742
|
+
} else if (event == RUBY_INTERNAL_EVENT_GC_EXIT) {
|
|
743
|
+
bool should_flush = thread_context_collector_on_gc_finish(state->thread_context_collector_instance);
|
|
744
|
+
|
|
745
|
+
// We use rb_postponed_job_register_one to ask Ruby to run thread_context_collector_sample_after_gc when the
|
|
746
|
+
// thread collector flags it's time to flush.
|
|
747
|
+
if (should_flush) {
|
|
748
|
+
#ifndef NO_POSTPONED_TRIGGER // Ruby 3.3+
|
|
749
|
+
rb_postponed_job_trigger(after_gc_from_postponed_job_handle);
|
|
750
|
+
#else
|
|
751
|
+
rb_postponed_job_register_one(0, after_gc_from_postponed_job, NULL);
|
|
752
|
+
#endif
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
static void after_gc_from_postponed_job(DDTRACE_UNUSED void *_unused) {
|
|
758
|
+
struct cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
|
|
759
|
+
|
|
760
|
+
// This can potentially happen if the CpuAndWallTimeWorker was stopped while the postponed job was waiting to be executed; nothing to do
|
|
761
|
+
if (state == NULL) return;
|
|
762
|
+
|
|
763
|
+
// @ivoanjo: I'm not sure this can ever happen because `on_gc_event` only enqueues this callback if
|
|
764
|
+
// it's running on the main Ractor, but just in case...
|
|
765
|
+
if (!ddtrace_rb_ractor_main_p()) {
|
|
766
|
+
return; // We're not on the main Ractor; we currently don't support profiling non-main Ractors
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
state->during_sample = true;
|
|
770
|
+
|
|
771
|
+
// Trigger sampling using the Collectors::ThreadState; rescue against any exceptions that happen during sampling
|
|
772
|
+
safely_call(thread_context_collector_sample_after_gc, state->thread_context_collector_instance, state->self_instance);
|
|
773
|
+
|
|
774
|
+
state->during_sample = false;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
// Equivalent to Ruby begin/rescue call, where we call a C function and jump to the exception handler if an
|
|
778
|
+
// exception gets raised within
|
|
779
|
+
static VALUE safely_call(VALUE (*function_to_call_safely)(VALUE), VALUE function_to_call_safely_arg, VALUE instance) {
|
|
780
|
+
VALUE exception_handler_function_arg = instance;
|
|
781
|
+
return rb_rescue2(
|
|
782
|
+
function_to_call_safely,
|
|
783
|
+
function_to_call_safely_arg,
|
|
784
|
+
handle_sampling_failure,
|
|
785
|
+
exception_handler_function_arg,
|
|
786
|
+
rb_eException, // rb_eException is the base class of all Ruby exceptions
|
|
787
|
+
0 // Required by API to be the last argument
|
|
788
|
+
);
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
// This method exists only to enable testing Datadog::Profiling::Collectors::CpuAndWallTimeWorker behavior using RSpec.
|
|
792
|
+
// It SHOULD NOT be used for other purposes.
|
|
793
|
+
static VALUE _native_simulate_handle_sampling_signal(DDTRACE_UNUSED VALUE self) {
|
|
794
|
+
handle_sampling_signal(0, NULL, NULL);
|
|
795
|
+
return Qtrue;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
// This method exists only to enable testing Datadog::Profiling::Collectors::CpuAndWallTimeWorker behavior using RSpec.
|
|
799
|
+
// It SHOULD NOT be used for other purposes.
|
|
800
|
+
static VALUE _native_simulate_sample_from_postponed_job(DDTRACE_UNUSED VALUE self) {
|
|
801
|
+
sample_from_postponed_job(NULL);
|
|
802
|
+
return Qtrue;
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
// After the Ruby VM forks, this method gets called in the child process to clean up any leftover state from the parent.
|
|
806
|
+
//
|
|
807
|
+
// Assumption: This method gets called BEFORE restarting profiling. Note that profiling-related tracepoints may still
|
|
808
|
+
// be active, so we make sure to disable them before calling into anything else, so that there are no components
|
|
809
|
+
// attempting to trigger samples at the same time as the reset is done.
|
|
810
|
+
//
|
|
811
|
+
// In the future, if we add more other components with tracepoints, we will need to coordinate stopping all such
|
|
812
|
+
// tracepoints before doing the other cleaning steps.
|
|
813
|
+
static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE instance) {
|
|
814
|
+
struct cpu_and_wall_time_worker_state *state;
|
|
815
|
+
TypedData_Get_Struct(instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
|
816
|
+
|
|
817
|
+
// Disable all tracepoints, so that there are no more attempts to mutate the profile
|
|
818
|
+
disable_tracepoints(state);
|
|
819
|
+
|
|
820
|
+
reset_stats(state);
|
|
821
|
+
|
|
822
|
+
// Remove all state from the `Collectors::ThreadState` and connected downstream components
|
|
823
|
+
rb_funcall(state->thread_context_collector_instance, rb_intern("reset_after_fork"), 0);
|
|
824
|
+
|
|
825
|
+
return Qtrue;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
static VALUE _native_is_sigprof_blocked_in_current_thread(DDTRACE_UNUSED VALUE self) {
|
|
829
|
+
return is_sigprof_blocked_in_current_thread();
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
static VALUE _native_stats(DDTRACE_UNUSED VALUE self, VALUE instance) {
|
|
833
|
+
struct cpu_and_wall_time_worker_state *state;
|
|
834
|
+
TypedData_Get_Struct(instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
|
835
|
+
|
|
836
|
+
VALUE pretty_sampling_time_ns_min = state->stats.sampling_time_ns_min == UINT64_MAX ? Qnil : ULL2NUM(state->stats.sampling_time_ns_min);
|
|
837
|
+
VALUE pretty_sampling_time_ns_max = state->stats.sampling_time_ns_max == 0 ? Qnil : ULL2NUM(state->stats.sampling_time_ns_max);
|
|
838
|
+
VALUE pretty_sampling_time_ns_total = state->stats.sampling_time_ns_total == 0 ? Qnil : ULL2NUM(state->stats.sampling_time_ns_total);
|
|
839
|
+
VALUE pretty_sampling_time_ns_avg =
|
|
840
|
+
state->stats.sampled == 0 ? Qnil : DBL2NUM(((double) state->stats.sampling_time_ns_total) / state->stats.sampled);
|
|
841
|
+
|
|
842
|
+
VALUE stats_as_hash = rb_hash_new();
|
|
843
|
+
VALUE arguments[] = {
|
|
844
|
+
ID2SYM(rb_intern("trigger_sample_attempts")), /* => */ UINT2NUM(state->stats.trigger_sample_attempts),
|
|
845
|
+
ID2SYM(rb_intern("trigger_simulated_signal_delivery_attempts")), /* => */ UINT2NUM(state->stats.trigger_simulated_signal_delivery_attempts),
|
|
846
|
+
ID2SYM(rb_intern("simulated_signal_delivery")), /* => */ UINT2NUM(state->stats.simulated_signal_delivery),
|
|
847
|
+
ID2SYM(rb_intern("signal_handler_enqueued_sample")), /* => */ UINT2NUM(state->stats.signal_handler_enqueued_sample),
|
|
848
|
+
ID2SYM(rb_intern("signal_handler_wrong_thread")), /* => */ UINT2NUM(state->stats.signal_handler_wrong_thread),
|
|
849
|
+
ID2SYM(rb_intern("sampled")), /* => */ UINT2NUM(state->stats.sampled),
|
|
850
|
+
ID2SYM(rb_intern("skipped_sample_because_of_dynamic_sampling_rate")), /* => */ UINT2NUM(state->stats.skipped_sample_because_of_dynamic_sampling_rate),
|
|
851
|
+
ID2SYM(rb_intern("postponed_job_skipped_already_existed")), /* => */ UINT2NUM(state->stats.postponed_job_skipped_already_existed),
|
|
852
|
+
ID2SYM(rb_intern("postponed_job_success")), /* => */ UINT2NUM(state->stats.postponed_job_success),
|
|
853
|
+
ID2SYM(rb_intern("postponed_job_full")), /* => */ UINT2NUM(state->stats.postponed_job_full),
|
|
854
|
+
ID2SYM(rb_intern("postponed_job_unknown_result")), /* => */ UINT2NUM(state->stats.postponed_job_unknown_result),
|
|
855
|
+
ID2SYM(rb_intern("sampling_time_ns_min")), /* => */ pretty_sampling_time_ns_min,
|
|
856
|
+
ID2SYM(rb_intern("sampling_time_ns_max")), /* => */ pretty_sampling_time_ns_max,
|
|
857
|
+
ID2SYM(rb_intern("sampling_time_ns_total")), /* => */ pretty_sampling_time_ns_total,
|
|
858
|
+
ID2SYM(rb_intern("sampling_time_ns_avg")), /* => */ pretty_sampling_time_ns_avg,
|
|
859
|
+
ID2SYM(rb_intern("allocations_during_sample")), /* => */ UINT2NUM(state->stats.allocations_during_sample),
|
|
860
|
+
};
|
|
861
|
+
for (long unsigned int i = 0; i < VALUE_COUNT(arguments); i += 2) rb_hash_aset(stats_as_hash, arguments[i], arguments[i+1]);
|
|
862
|
+
return stats_as_hash;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
void *simulate_sampling_signal_delivery(DDTRACE_UNUSED void *_unused) {
|
|
866
|
+
struct cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
|
|
867
|
+
|
|
868
|
+
// This can potentially happen if the CpuAndWallTimeWorker was stopped while the IdleSamplingHelper was trying to execute this action
|
|
869
|
+
if (state == NULL) return NULL;
|
|
870
|
+
|
|
871
|
+
state->stats.simulated_signal_delivery++;
|
|
872
|
+
|
|
873
|
+
// @ivoanjo: We could instead directly call sample_from_postponed_job, but I chose to go through the signal handler
|
|
874
|
+
// so that the simulated case is as close to the original one as well (including any metrics increases, etc).
|
|
875
|
+
handle_sampling_signal(0, NULL, NULL);
|
|
876
|
+
|
|
877
|
+
return NULL; // Unused
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
static void grab_gvl_and_sample(void) { rb_thread_call_with_gvl(simulate_sampling_signal_delivery, NULL); }
|
|
881
|
+
|
|
882
|
+
static void reset_stats(struct cpu_and_wall_time_worker_state *state) {
|
|
883
|
+
state->stats = (struct stats) {}; // Resets all stats back to zero
|
|
884
|
+
state->stats.sampling_time_ns_min = UINT64_MAX; // Since we always take the min between existing and latest sample
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
static void sleep_for(uint64_t time_ns) {
|
|
888
|
+
// As a simplification, we currently only support setting .tv_nsec
|
|
889
|
+
if (time_ns >= SECONDS_AS_NS(1)) {
|
|
890
|
+
grab_gvl_and_raise(rb_eArgError, "sleep_for can only sleep for less than 1 second, time_ns: %"PRIu64, time_ns);
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
struct timespec time_to_sleep = {.tv_nsec = time_ns};
|
|
894
|
+
|
|
895
|
+
while (nanosleep(&time_to_sleep, &time_to_sleep) != 0) {
|
|
896
|
+
if (errno == EINTR) {
|
|
897
|
+
// We were interrupted. nanosleep updates "time_to_sleep" to contain only the remaining time, so we just let the
|
|
898
|
+
// loop keep going.
|
|
899
|
+
} else {
|
|
900
|
+
ENFORCE_SUCCESS_NO_GVL(errno);
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
static VALUE _native_allocation_count(DDTRACE_UNUSED VALUE self) {
|
|
906
|
+
bool are_allocations_being_tracked = active_sampler_instance_state != NULL && active_sampler_instance_state->allocation_profiling_enabled;
|
|
907
|
+
|
|
908
|
+
return are_allocations_being_tracked ? ULL2NUM(allocation_count) : Qnil;
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
// Implements memory-related profiling events. This function is called by Ruby via the `object_allocation_tracepoint`
|
|
912
|
+
// when the RUBY_INTERNAL_EVENT_NEWOBJ event is triggered.
|
|
913
|
+
static void on_newobj_event(VALUE tracepoint_data, DDTRACE_UNUSED void *unused) {
|
|
914
|
+
// Update thread-local allocation count
|
|
915
|
+
if (RB_UNLIKELY(allocation_count == UINT64_MAX)) {
|
|
916
|
+
allocation_count = 0;
|
|
917
|
+
} else {
|
|
918
|
+
allocation_count++;
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
struct cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
|
|
922
|
+
|
|
923
|
+
// This should not happen in a normal situation because the tracepoint is always enabled after the instance is set
|
|
924
|
+
// and disabled before it is cleared, but just in case...
|
|
925
|
+
if (state == NULL) return;
|
|
926
|
+
|
|
927
|
+
// In a few cases, we may actually be allocating an object as part of profiler sampling. We don't want to recursively
|
|
928
|
+
// sample, so we just return early
|
|
929
|
+
if (state->during_sample) {
|
|
930
|
+
state->stats.allocations_during_sample++;
|
|
931
|
+
return;
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
// @ivoanjo: Strictly speaking, this is not needed because Ruby should not call the same tracepoint while a previous
|
|
935
|
+
// invocation is still pending, (e.g. it wouldn't call `on_newobj_event` while it's already running), but I decided
|
|
936
|
+
// to keep this here for consistency -- every call to the thread context (other than the special gc calls which are
|
|
937
|
+
// defined as not being able to allocate) sets this.
|
|
938
|
+
state->during_sample = true;
|
|
939
|
+
|
|
940
|
+
// TODO: This is a placeholder sampling decision strategy. We plan to replace it with a better one soon (e.g. before
|
|
941
|
+
// beta), and having something here allows us to test the rest of feature, sampling decision aside.
|
|
942
|
+
if (allocation_count % state->allocation_sample_every == 0) {
|
|
943
|
+
// Rescue against any exceptions that happen during sampling
|
|
944
|
+
safely_call(rescued_sample_allocation, tracepoint_data, state->self_instance);
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
state->during_sample = false;
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
static void disable_tracepoints(struct cpu_and_wall_time_worker_state *state) {
|
|
951
|
+
rb_tracepoint_disable(state->gc_tracepoint);
|
|
952
|
+
rb_tracepoint_disable(state->object_allocation_tracepoint);
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
static VALUE _native_with_blocked_sigprof(DDTRACE_UNUSED VALUE self) {
|
|
956
|
+
block_sigprof_signal_handler_from_running_in_current_thread();
|
|
957
|
+
int exception_state;
|
|
958
|
+
VALUE result = rb_protect(rb_yield, Qundef, &exception_state);
|
|
959
|
+
unblock_sigprof_signal_handler_from_running_in_current_thread();
|
|
960
|
+
|
|
961
|
+
if (exception_state) {
|
|
962
|
+
rb_jump_tag(exception_state);
|
|
963
|
+
} else {
|
|
964
|
+
return result;
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
static VALUE rescued_sample_allocation(VALUE tracepoint_data) {
|
|
969
|
+
struct cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
|
|
970
|
+
|
|
971
|
+
// This should not happen in a normal situation because on_newobj_event already checked for this, but just in case...
|
|
972
|
+
if (state == NULL) return Qnil;
|
|
973
|
+
|
|
974
|
+
rb_trace_arg_t *data = rb_tracearg_from_tracepoint(tracepoint_data);
|
|
975
|
+
VALUE new_object = rb_tracearg_object(data);
|
|
976
|
+
|
|
977
|
+
thread_context_collector_sample_allocation(state->thread_context_collector_instance, state->allocation_sample_every, new_object);
|
|
978
|
+
|
|
979
|
+
// Return a dummy VALUE because we're called from rb_rescue2 which requires it
|
|
980
|
+
return Qnil;
|
|
981
|
+
}
|