datadog 2.47.0 → 2.48.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 +30 -1
- data/LICENSE-3rdparty.csv +1 -0
- data/ext/datadog_profiling_native_extension/collectors_stack.c +141 -101
- data/ext/datadog_profiling_native_extension/collectors_stack.h +9 -1
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +6 -1
- data/ext/datadog_profiling_native_extension/extconf.rb +7 -13
- data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +3 -3
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +66 -13
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +5 -1
- data/ext/datadog_profiling_native_extension/profiling.c +1 -1
- data/ext/libdatadog_api/extconf.rb +9 -7
- data/ext/libdatadog_api/trace_exporter.c +34 -7
- data/ext/libdatadog_extconf_helpers.rb +1 -1
- data/lib/datadog/ai_guard/component.rb +1 -1
- data/lib/datadog/ai_guard/contrib/rack/request_middleware.rb +1 -9
- data/lib/datadog/ai_guard/contrib/rails/patcher.rb +1 -1
- data/lib/datadog/ai_guard/contrib/ruby_llm/message_adapter.rb +1 -1
- data/lib/datadog/ai_guard/contrib/ruby_llm/redaction_change_set.rb +3 -3
- data/lib/datadog/ai_guard/evaluation/client.rb +3 -3
- data/lib/datadog/ai_guard/evaluation.rb +2 -2
- data/lib/datadog/ai_guard/http_client.rb +3 -2
- data/lib/datadog/ai_guard/redaction.rb +1 -1
- data/lib/datadog/appsec/api_security/endpoint_collection/rails_collector.rb +1 -1
- data/lib/datadog/appsec/assets/waf_rules/README.md +3 -3
- data/lib/datadog/appsec/assets/waf_rules/recommended.json +5366 -1517
- data/lib/datadog/appsec/assets/waf_rules/strict.json +2 -2
- data/lib/datadog/appsec/autoload.rb +1 -1
- data/lib/datadog/appsec/component.rb +1 -1
- data/lib/datadog/appsec/compressed_json.rb +1 -1
- data/lib/datadog/appsec/configuration.rb +3 -3
- data/lib/datadog/appsec/context.rb +1 -1
- data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +11 -1
- data/lib/datadog/appsec/contrib/active_record/patcher.rb +12 -4
- data/lib/datadog/appsec/contrib/aws_lambda/gateway/watcher.rb +2 -2
- data/lib/datadog/appsec/contrib/aws_lambda/waf_addresses.rb +1 -1
- data/lib/datadog/appsec/contrib/devise/configuration.rb +1 -1
- data/lib/datadog/appsec/contrib/devise/patches/signin_tracking_patch.rb +1 -1
- data/lib/datadog/appsec/contrib/devise/patches/signup_tracking_patch.rb +1 -1
- data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +1 -1
- data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +1 -1
- data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +1 -1
- data/lib/datadog/appsec/contrib/graphql/gateway/multiplex.rb +7 -7
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +1 -1
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +3 -3
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +5 -5
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +2 -2
- data/lib/datadog/appsec/contrib/rails/patcher.rb +2 -2
- data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +1 -1
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +3 -3
- data/lib/datadog/appsec/contrib/sinatra/patcher.rb +1 -1
- data/lib/datadog/appsec/metrics/collector.rb +5 -5
- data/lib/datadog/appsec/metrics/telemetry_exporter.rb +3 -3
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +2 -2
- data/lib/datadog/appsec/processor/rule_loader.rb +1 -1
- data/lib/datadog/appsec/response.rb +1 -1
- data/lib/datadog/appsec/security_engine/engine.rb +6 -6
- data/lib/datadog/appsec/security_engine/runner.rb +2 -2
- data/lib/datadog/appsec/trace_keeper.rb +1 -1
- data/lib/datadog/appsec.rb +1 -1
- data/lib/datadog/core/configuration/agent_settings_resolver.rb +14 -13
- data/lib/datadog/core/configuration/agentless_settings_resolver.rb +2 -2
- data/lib/datadog/core/configuration/components.rb +1 -1
- data/lib/datadog/core/configuration/settings.rb +5 -2
- data/lib/datadog/core/configuration/supported_configurations.rb +1 -0
- data/lib/datadog/core/configuration.rb +2 -2
- data/lib/datadog/core/crashtracking/component.rb +1 -1
- data/lib/datadog/core/diagnostics/environment_logger.rb +1 -1
- data/lib/datadog/core/environment/cgroup.rb +2 -2
- data/lib/datadog/core/environment/container.rb +3 -3
- data/lib/datadog/core/metrics/client.rb +6 -6
- data/lib/datadog/core/process_discovery.rb +1 -1
- data/lib/datadog/core/remote/tie/tracing.rb +4 -3
- data/lib/datadog/core/remote/transport/http.rb +2 -2
- data/lib/datadog/core/runtime/metrics.rb +14 -14
- data/lib/datadog/core/semaphore.rb +3 -1
- data/lib/datadog/core/telemetry/event/app_started.rb +9 -9
- data/lib/datadog/core/telemetry/logger.rb +1 -1
- data/lib/datadog/core/telemetry/logging.rb +1 -1
- data/lib/datadog/core/telemetry/request.rb +9 -3
- data/lib/datadog/core/telemetry/transport/http.rb +2 -2
- data/lib/datadog/core/telemetry/worker.rb +1 -1
- data/lib/datadog/core/transport/http/adapters/net.rb +1 -1
- data/lib/datadog/core/transport/http/adapters/unix_socket.rb +1 -1
- data/lib/datadog/core/transport/http/builder.rb +1 -1
- data/lib/datadog/core/transport/http.rb +3 -3
- data/lib/datadog/core/utils/at_fork_monkey_patch.rb +2 -2
- data/lib/datadog/core/workers/async.rb +1 -1
- data/lib/datadog/core/workers/runtime_metrics.rb +1 -1
- data/lib/datadog/data_streams/pathway_context.rb +1 -1
- data/lib/datadog/data_streams/processor.rb +48 -27
- data/lib/datadog/data_streams/transport/http.rb +1 -1
- data/lib/datadog/data_streams.rb +16 -0
- data/lib/datadog/di/capture_expression_evaluator.rb +48 -11
- data/lib/datadog/di/component.rb +3 -2
- data/lib/datadog/di/configuration.rb +19 -0
- data/lib/datadog/di/contrib/active_record.rb +1 -1
- data/lib/datadog/di/el/compiler.rb +4 -4
- data/lib/datadog/di/el/evaluator.rb +247 -43
- data/lib/datadog/di/el/expression.rb +36 -6
- data/lib/datadog/di/error.rb +16 -0
- data/lib/datadog/di/guardrails_telemetry/reason.rb +3 -2
- data/lib/datadog/di/instrumenter.rb +39 -10
- data/lib/datadog/di/probe_notification_builder.rb +58 -10
- data/lib/datadog/di/probe_notifier_worker.rb +1 -1
- data/lib/datadog/di/serializer.rb +20 -2
- data/lib/datadog/di.rb +27 -0
- data/lib/datadog/error_tracking/component.rb +1 -1
- data/lib/datadog/error_tracking/configuration.rb +1 -1
- data/lib/datadog/kit/appsec/events/v2.rb +6 -6
- data/lib/datadog/kit/appsec/events.rb +1 -1
- data/lib/datadog/kit/enable_core_dumps.rb +1 -1
- data/lib/datadog/kit/identity.rb +1 -1
- data/lib/datadog/open_feature/activation.rb +26 -1
- data/lib/datadog/open_feature/agentless/configuration_source.rb +94 -15
- data/lib/datadog/open_feature/component.rb +22 -2
- data/lib/datadog/open_feature/configuration/agentless_endpoint.rb +6 -0
- data/lib/datadog/open_feature/configuration.rb +4 -4
- data/lib/datadog/open_feature/evaluation_engine.rb +62 -4
- data/lib/datadog/open_feature/exposures/buffer.rb +4 -0
- data/lib/datadog/open_feature/exposures/reporter.rb +17 -4
- data/lib/datadog/open_feature/exposures/worker.rb +37 -6
- data/lib/datadog/open_feature/flag_evaluation/aggregator.rb +5 -5
- data/lib/datadog/open_feature/flag_evaluation/writer.rb +1 -1
- data/lib/datadog/open_feature/hooks/debug_logging_hook.rb +56 -0
- data/lib/datadog/open_feature/hooks/span_enrichment_hook.rb +2 -2
- data/lib/datadog/open_feature/metrics/flag_eval_metrics.rb +1 -1
- data/lib/datadog/open_feature/native_evaluator.rb +1 -1
- data/lib/datadog/open_feature/noop_evaluator.rb +1 -1
- data/lib/datadog/open_feature/provider.rb +50 -12
- data/lib/datadog/open_feature/remote.rb +8 -1
- data/lib/datadog/open_feature/resolution_details.rb +2 -2
- data/lib/datadog/open_feature/transport.rb +6 -6
- data/lib/datadog/opentelemetry/api/context.rb +3 -3
- data/lib/datadog/opentelemetry/logs.rb +5 -5
- data/lib/datadog/opentelemetry/metrics.rb +3 -3
- data/lib/datadog/opentelemetry/sdk/propagator.rb +3 -3
- data/lib/datadog/opentelemetry/sdk/span_processor.rb +2 -2
- data/lib/datadog/opentelemetry/sdk/trace/span.rb +1 -1
- data/lib/datadog/profiling/collectors/code_provenance.rb +3 -3
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +4 -4
- data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -1
- data/lib/datadog/profiling/collectors/thread_context.rb +1 -1
- data/lib/datadog/profiling/component.rb +19 -19
- data/lib/datadog/profiling/exporter.rb +1 -1
- data/lib/datadog/profiling/http_transport.rb +3 -3
- data/lib/datadog/profiling/profiler.rb +2 -2
- data/lib/datadog/profiling/scheduler.rb +2 -2
- data/lib/datadog/profiling/tag_builder.rb +1 -1
- data/lib/datadog/symbol_database/extractor.rb +8 -8
- data/lib/datadog/symbol_database/uploader.rb +1 -1
- data/lib/datadog/tracing/buffer.rb +3 -3
- data/lib/datadog/tracing/client_ip.rb +1 -1
- data/lib/datadog/tracing/component.rb +8 -8
- data/lib/datadog/tracing/configuration/dynamic/option.rb +2 -2
- data/lib/datadog/tracing/configuration/settings.rb +3 -3
- data/lib/datadog/tracing/context.rb +1 -1
- data/lib/datadog/tracing/contrib/action_cable/instrumentation.rb +2 -2
- data/lib/datadog/tracing/contrib/active_job/data_streams.rb +27 -2
- data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +2 -2
- data/lib/datadog/tracing/contrib/active_record/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/utils.rb +1 -1
- data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +1 -1
- data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/active_support/notifications/subscriber.rb +2 -2
- data/lib/datadog/tracing/contrib/active_support/notifications/subscription.rb +2 -2
- data/lib/datadog/tracing/contrib/aws/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/aws/instrumentation.rb +1 -1
- data/lib/datadog/tracing/contrib/dalli/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/dalli/instrumentation.rb +1 -1
- data/lib/datadog/tracing/contrib/delayed_job/plugin.rb +2 -2
- data/lib/datadog/tracing/contrib/elasticsearch/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/ethon/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +8 -8
- data/lib/datadog/tracing/contrib/ethon/multi_patch.rb +1 -1
- data/lib/datadog/tracing/contrib/excon/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/excon/middleware.rb +7 -7
- data/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/faraday/middleware.rb +5 -5
- data/lib/datadog/tracing/contrib/grape/endpoint.rb +4 -4
- data/lib/datadog/tracing/contrib/graphql/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +3 -3
- data/lib/datadog/tracing/contrib/grpc/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +2 -2
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +1 -1
- data/lib/datadog/tracing/contrib/grpc.rb +1 -1
- data/lib/datadog/tracing/contrib/hanami/action_tracer.rb +1 -1
- data/lib/datadog/tracing/contrib/hanami/plugin.rb +1 -1
- data/lib/datadog/tracing/contrib/hanami/renderer_policy_tracing.rb +1 -1
- data/lib/datadog/tracing/contrib/hanami/router_tracing.rb +1 -1
- data/lib/datadog/tracing/contrib/http/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/http/instrumentation.rb +6 -6
- data/lib/datadog/tracing/contrib/http.rb +1 -1
- data/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +7 -7
- data/lib/datadog/tracing/contrib/httprb/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +5 -5
- data/lib/datadog/tracing/contrib/kafka/instrumentation/consumer.rb +2 -2
- data/lib/datadog/tracing/contrib/kafka/instrumentation/producer.rb +2 -2
- data/lib/datadog/tracing/contrib/karafka/monitor.rb +1 -1
- data/lib/datadog/tracing/contrib/karafka/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/karafka.rb +1 -1
- data/lib/datadog/tracing/contrib/lograge/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/mongodb/parsers.rb +1 -1
- data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +1 -1
- data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +3 -3
- data/lib/datadog/tracing/contrib/opensearch/configuration/settings.rb +2 -2
- data/lib/datadog/tracing/contrib/opensearch/patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/pg/instrumentation.rb +4 -4
- data/lib/datadog/tracing/contrib/presto/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/presto/instrumentation.rb +4 -4
- data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +1 -1
- data/lib/datadog/tracing/contrib/que/tracer.rb +1 -1
- data/lib/datadog/tracing/contrib/racecar/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/racecar/events/batch.rb +1 -1
- data/lib/datadog/tracing/contrib/racecar/events/message.rb +1 -1
- data/lib/datadog/tracing/contrib/rack/middlewares.rb +3 -3
- data/lib/datadog/tracing/contrib/rack/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/rails/framework.rb +7 -7
- data/lib/datadog/tracing/contrib/rails/log_injection.rb +1 -1
- data/lib/datadog/tracing/contrib/rails/runner.rb +4 -4
- data/lib/datadog/tracing/contrib/redis/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/redis/quantize.rb +1 -1
- data/lib/datadog/tracing/contrib/redis/tags.rb +1 -1
- data/lib/datadog/tracing/contrib/rest_client/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +8 -8
- data/lib/datadog/tracing/contrib/sequel/database.rb +1 -1
- data/lib/datadog/tracing/contrib/sequel/dataset.rb +1 -1
- data/lib/datadog/tracing/contrib/shoryuken/tracer.rb +1 -1
- data/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +2 -2
- data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +2 -2
- data/lib/datadog/tracing/contrib/sidekiq.rb +1 -1
- data/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb +1 -1
- data/lib/datadog/tracing/contrib/status_range_env_parser.rb +1 -1
- data/lib/datadog/tracing/contrib/sucker_punch/instrumentation.rb +1 -1
- data/lib/datadog/tracing/contrib/trilogy/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/trilogy/instrumentation.rb +3 -3
- data/lib/datadog/tracing/contrib/waterdrop/middleware.rb +2 -2
- data/lib/datadog/tracing/contrib/waterdrop.rb +1 -1
- data/lib/datadog/tracing/diagnostics/environment_logger.rb +1 -1
- data/lib/datadog/tracing/distributed/b3_multi.rb +1 -1
- data/lib/datadog/tracing/distributed/b3_single.rb +1 -1
- data/lib/datadog/tracing/distributed/baggage.rb +3 -3
- data/lib/datadog/tracing/distributed/datadog.rb +3 -3
- data/lib/datadog/tracing/distributed/propagation.rb +7 -7
- data/lib/datadog/tracing/distributed/trace_context.rb +1 -1
- data/lib/datadog/tracing/distributed/trace_state/open_telemetry.rb +1 -1
- data/lib/datadog/tracing/otel_thread_context.rb +3 -3
- data/lib/datadog/tracing/pipeline.rb +1 -1
- data/lib/datadog/tracing/sampling/priority_sampler.rb +1 -1
- data/lib/datadog/tracing/sampling/rule.rb +1 -1
- data/lib/datadog/tracing/sampling/rule_sampler.rb +1 -1
- data/lib/datadog/tracing/sampling/span/rule_parser.rb +2 -2
- data/lib/datadog/tracing/span_operation.rb +1 -1
- data/lib/datadog/tracing/trace_digest.rb +1 -1
- data/lib/datadog/tracing/trace_operation.rb +6 -6
- data/lib/datadog/tracing/tracer.rb +6 -6
- data/lib/datadog/tracing/transport/http/telemetry.rb +1 -1
- data/lib/datadog/tracing/transport/http.rb +2 -2
- data/lib/datadog/tracing/transport/io.rb +1 -1
- data/lib/datadog/tracing/transport/native.rb +3 -3
- data/lib/datadog/tracing/transport/statistics.rb +2 -2
- data/lib/datadog/tracing/transport/telemetry.rb +3 -1
- data/lib/datadog/tracing/transport/trace_formatter.rb +12 -12
- data/lib/datadog/tracing/transport/traces.rb +1 -1
- data/lib/datadog/tracing/utils.rb +1 -1
- data/lib/datadog/tracing/workers.rb +1 -1
- data/lib/datadog/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ac4a0fce689b8c65bbe4c00847dbaf3e84bf7eda13ea48fc40cab57d5332a04f
|
|
4
|
+
data.tar.gz: dbf9526b321135b7e9e014578a5abe92a89e339a4ba2d9f7997718194e76a302
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dbbbc2ca84a95852a6614ba6cbc21c0fc68c4badef35c34dc29059ef6feffb0307ac0d19ffc955d8b7ac3f807007d4ea9577490dee99e0bb9f98f4d158ac8093
|
|
7
|
+
data.tar.gz: 3ec630b843cd8e57b14a227afe815c1e07f8a5c5bcbbffd62a41a19c57c5f204e8302059dd9bce0c7d89d1667f7a93ae6219686ec55aef5961ee23082ff56f26
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [2.48.0] - 2026-11-03
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
* Dynamic Instrumentation: Limit condition, capture-expression, and template evaluation CPU time with `DD_DYNAMIC_INSTRUMENTATION_EVALUATION_TIMEOUT_MS` (default `50`); over-budget evaluation is reported as an evaluation error. ([#6223][])
|
|
10
|
+
* Open Feature: Add onboarding diagnostics for configuration delivery, provider readiness, flag evaluations, and exposures with `DD_TRACE_DEBUG=true`. Evaluation logs include raw data that may contain personal or sensitive information. ([#6519][])
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
* Core: Require C11 (`-std=gnu11`) support to build native extensions on Linux. ([#6596][])
|
|
15
|
+
* Profiling: Show class and module names in profiler stack frames by default, e.g. `Foo::Bar#baz` instead of `baz`, making methods easier to identify. ([#6537][])
|
|
16
|
+
* Dynamic Instrumentation: Lower the per-call limit of the `matches` expression operator from 500 ms to 50 ms of wall time; a slow regular expression in a probe now delays the instrumented method by at most 50 ms per call and reports an evaluation error. ([#6223][])
|
|
17
|
+
* Data Streams: Start a new pathway when a consume and the produce that follows it run on different threads; to keep one pathway across the hand-off, pass the context with `set_produce_checkpoint` and `set_consume_checkpoint`. ([#6532][])
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
* Tracing: Fix the `_dd.rc.client_id` span tag occasionally carrying the client id of a different remote-configuration connection during component reconnection. ([#6601][])
|
|
22
|
+
* AppSec: Fix missing SQL injection detection in applications using `ActiveRecord` 8.0 and later. ([#6581][])
|
|
23
|
+
* AI Guard: Fix a rare crash when building the AI Guard client endpoint while the Datadog site setting changes concurrently. ([#6601][])
|
|
24
|
+
* Data Streams: Fix full-pathway latency inflated by minutes, and messages linked to the wrong pathway, in multi-threaded or forking apps such as `Karafka` consumers and `ActiveJob` workers. ([#6532][])
|
|
25
|
+
|
|
5
26
|
## [2.47.0] - 2026-10-26
|
|
6
27
|
|
|
7
28
|
### Added
|
|
@@ -3869,7 +3890,8 @@ Release notes: https://github.com/DataDog/dd-trace-rb/releases/tag/v0.3.1
|
|
|
3869
3890
|
Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
|
3870
3891
|
|
|
3871
3892
|
|
|
3872
|
-
[Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v2.
|
|
3893
|
+
[Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v2.48.0...master
|
|
3894
|
+
[2.48.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.47.0...v2.48.0
|
|
3873
3895
|
[2.47.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.46.0...v2.47.0
|
|
3874
3896
|
[2.46.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.45.0...v2.46.0
|
|
3875
3897
|
[2.45.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.44.0...v2.45.0
|
|
@@ -5706,6 +5728,7 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
|
|
5706
5728
|
[#6213]: https://github.com/DataDog/dd-trace-rb/issues/6213
|
|
5707
5729
|
[#6219]: https://github.com/DataDog/dd-trace-rb/issues/6219
|
|
5708
5730
|
[#6220]: https://github.com/DataDog/dd-trace-rb/issues/6220
|
|
5731
|
+
[#6223]: https://github.com/DataDog/dd-trace-rb/issues/6223
|
|
5709
5732
|
[#6232]: https://github.com/DataDog/dd-trace-rb/issues/6232
|
|
5710
5733
|
[#6234]: https://github.com/DataDog/dd-trace-rb/issues/6234
|
|
5711
5734
|
[#6242]: https://github.com/DataDog/dd-trace-rb/issues/6242
|
|
@@ -5744,9 +5767,15 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
|
|
5744
5767
|
[#6486]: https://github.com/DataDog/dd-trace-rb/issues/6486
|
|
5745
5768
|
[#6488]: https://github.com/DataDog/dd-trace-rb/issues/6488
|
|
5746
5769
|
[#6500]: https://github.com/DataDog/dd-trace-rb/issues/6500
|
|
5770
|
+
[#6519]: https://github.com/DataDog/dd-trace-rb/issues/6519
|
|
5771
|
+
[#6532]: https://github.com/DataDog/dd-trace-rb/issues/6532
|
|
5772
|
+
[#6537]: https://github.com/DataDog/dd-trace-rb/issues/6537
|
|
5747
5773
|
[#6543]: https://github.com/DataDog/dd-trace-rb/issues/6543
|
|
5748
5774
|
[#6547]: https://github.com/DataDog/dd-trace-rb/issues/6547
|
|
5749
5775
|
[#6548]: https://github.com/DataDog/dd-trace-rb/issues/6548
|
|
5776
|
+
[#6581]: https://github.com/DataDog/dd-trace-rb/issues/6581
|
|
5777
|
+
[#6596]: https://github.com/DataDog/dd-trace-rb/issues/6596
|
|
5778
|
+
[#6601]: https://github.com/DataDog/dd-trace-rb/issues/6601
|
|
5750
5779
|
[@AdrianLC]: https://github.com/AdrianLC
|
|
5751
5780
|
[@Azure7111]: https://github.com/Azure7111
|
|
5752
5781
|
[@BabyGroot]: https://github.com/BabyGroot
|
data/LICENSE-3rdparty.csv
CHANGED
|
@@ -5,3 +5,4 @@
|
|
|
5
5
|
"lib/datadog/tracing/contrib/active_record/vendor","https://github.com/rails/rails/","MIT","Copyright (c) 2005-2018 David Heinemeier Hansson"
|
|
6
6
|
"lib/datadog/tracing/contrib/utils/quantization/http.rb","https://github.com/ruby/uri","BSD-2-Clause","Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved."
|
|
7
7
|
"msgpack","https://rubygems.org/gems/msgpack","Apache-2.0","Copyright (c) 2008-2015 Sadayuki Furuhashi"
|
|
8
|
+
"rubocop/custom_cops/trailing_comma_in_arguments_cop.rb","https://github.com/rubocop/rubocop","MIT","Copyright (c) 2012-25 Bozhidar Batsov"
|
|
@@ -41,7 +41,7 @@ static const char *get_or_compute_native_filename(void *function, st_table *nati
|
|
|
41
41
|
static void initialize_static_ruby_actual_filename(VALUE profiling_module);
|
|
42
42
|
static void add_truncated_frames_placeholder(ddog_prof_Location *locations);
|
|
43
43
|
static void record_placeholder_stack_in_native_code(VALUE recorder_instance, sample_values values, sample_labels labels);
|
|
44
|
-
static void maybe_trim_template_random_ids(ddog_CharSlice *frame_name, ddog_CharSlice
|
|
44
|
+
static void maybe_trim_template_random_ids(ddog_CharSlice *frame_name, ddog_CharSlice filename, bool frame_name_in_scratch_buffer);
|
|
45
45
|
|
|
46
46
|
// NULL if we weren't able to get the native filename for the Ruby VM.
|
|
47
47
|
// On a static Ruby without libruby.so, `get_or_compute_native_filename` returns `ruby_native_filename` but
|
|
@@ -180,7 +180,7 @@ static VALUE _native_sample(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self) {
|
|
|
180
180
|
sample_locations locations;
|
|
181
181
|
sample_locations_initialize(&locations, max_frames_requested, show_classes == Qtrue);
|
|
182
182
|
sampling_buffer buffer;
|
|
183
|
-
sampling_buffer_initialize(&buffer, max_frames_requested);
|
|
183
|
+
sampling_buffer_initialize(&buffer, max_frames_requested, show_classes == Qtrue);
|
|
184
184
|
|
|
185
185
|
ddog_prof_Slice_Label slice_labels = {.ptr = labels, .len = labels_count};
|
|
186
186
|
|
|
@@ -239,6 +239,83 @@ static VALUE native_sample_ensure(VALUE args) {
|
|
|
239
239
|
|
|
240
240
|
#define CHARSLICE_EQUALS(must_be_a_literal, charslice) (strlen("" must_be_a_literal) == charslice.len && strncmp(must_be_a_literal, charslice.ptr, charslice.len) == 0)
|
|
241
241
|
|
|
242
|
+
// The method name on its own, without any class/module name
|
|
243
|
+
static inline ddog_CharSlice unqualified_name(const rb_callable_method_entry_t *cme, const rb_iseq_t *iseq) {
|
|
244
|
+
VALUE name = ddtrace_location_base_label(cme, iseq);
|
|
245
|
+
return (name == Qfalse) ? DDOG_CHARSLICE_C("") : char_slice_from_ruby_string(name);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// When there's only wall-time in a sample, this means that the thread was not active in the sampled period, so we try
|
|
249
|
+
// to tell what it was doing instead.
|
|
250
|
+
//
|
|
251
|
+
// TODO: `method` is the unqualified method name
|
|
252
|
+
// because we don't always use qualified method names yet,
|
|
253
|
+
// and the checks below need something stable to compare to until we always do.
|
|
254
|
+
static void categorize_sample_state(
|
|
255
|
+
sample_labels labels,
|
|
256
|
+
frame_info frame,
|
|
257
|
+
ddog_CharSlice method,
|
|
258
|
+
DDTRACE_UNUSED ddog_CharSlice filename
|
|
259
|
+
) {
|
|
260
|
+
ddog_prof_Label *state_label = labels.state_label;
|
|
261
|
+
|
|
262
|
+
// Did the caller already provide the state?
|
|
263
|
+
if (labels.is_gvl_waiting_state) {
|
|
264
|
+
state_label->str = DDOG_CHARSLICE_C("waiting for gvl");
|
|
265
|
+
|
|
266
|
+
// Otherwise, we try to categorize what the thread was doing based on what we observe at the top of the stack. This is a very rough
|
|
267
|
+
// approximation, and in the future we hope to replace this with a more accurate approach (such as using the
|
|
268
|
+
// GVL instrumentation API.)
|
|
269
|
+
} else if (!frame.is_ruby_frame) {
|
|
270
|
+
// We know that known versions of Ruby implement these using native code; thus if we find a method with the
|
|
271
|
+
// same name that is not native code, we ignore it, as it's probably a user method that coincidentally
|
|
272
|
+
// has the same name. Thus, even though "matching just by method name" is kinda weak,
|
|
273
|
+
// "matching by method name" + is native code seems actually to be good enough for a lot of cases.
|
|
274
|
+
|
|
275
|
+
if (CHARSLICE_EQUALS("sleep", method)) { // Expected to be Kernel.sleep
|
|
276
|
+
state_label->str = DDOG_CHARSLICE_C("sleeping");
|
|
277
|
+
} else if (CHARSLICE_EQUALS("select", method)) { // Expected to be Kernel.select
|
|
278
|
+
state_label->str = DDOG_CHARSLICE_C("waiting");
|
|
279
|
+
} else if (
|
|
280
|
+
CHARSLICE_EQUALS("synchronize", method) || // Expected to be Monitor/Mutex#synchronize on Ruby 2 & 3, and Monitor#synchronize on 4 (Mutex becomes <internal:thread_sync>)
|
|
281
|
+
#ifdef NO_PRIMITIVE_MUTEX_AND_CONDITION_VARIABLE // Ruby < 4
|
|
282
|
+
CHARSLICE_EQUALS("lock", method) || // Expected to be Mutex#lock
|
|
283
|
+
#endif
|
|
284
|
+
CHARSLICE_EQUALS("join", method) // Expected to be Thread#join
|
|
285
|
+
) {
|
|
286
|
+
state_label->str = DDOG_CHARSLICE_C("blocked");
|
|
287
|
+
} else if (CHARSLICE_EQUALS("wait_readable", method)) { // Expected to be IO#wait_readable
|
|
288
|
+
state_label->str = DDOG_CHARSLICE_C("network");
|
|
289
|
+
} else if (CHARSLICE_EQUALS("_native_idle_sampling_loop", method)) { // Expected to be Datadog::Profiler::Collectors::IdleSamplingHelper#_native_idle_sampling_loop
|
|
290
|
+
state_label->str = DDOG_CHARSLICE_C("waiting");
|
|
291
|
+
} else if (CHARSLICE_EQUALS("_native_sampling_loop", method)) { // Expected to be Datadog::Profiler::Collectors::CpuAndWallTimeWorker#_native_sampling_loop
|
|
292
|
+
state_label->str = DDOG_CHARSLICE_C("sleeping");
|
|
293
|
+
}
|
|
294
|
+
#ifdef NO_PRIMITIVE_POP // Ruby < 3.2
|
|
295
|
+
else if (CHARSLICE_EQUALS("pop", method)) { // Expected to be Queue/SizedQueue#pop
|
|
296
|
+
state_label->str = DDOG_CHARSLICE_C("waiting");
|
|
297
|
+
}
|
|
298
|
+
#endif
|
|
299
|
+
} else {
|
|
300
|
+
#ifndef NO_PRIMITIVE_POP // Ruby >= 3.2
|
|
301
|
+
if (CHARSLICE_EQUALS("<internal:thread_sync>", filename)) {
|
|
302
|
+
if (CHARSLICE_EQUALS("pop", method)) { // Expected to be Queue/SizedQueue#pop
|
|
303
|
+
state_label->str = DDOG_CHARSLICE_C("waiting");
|
|
304
|
+
}
|
|
305
|
+
#ifndef NO_PRIMITIVE_MUTEX_AND_CONDITION_VARIABLE // Ruby >= 4
|
|
306
|
+
else if (CHARSLICE_EQUALS("synchronize", method) || CHARSLICE_EQUALS("lock", method)) { // Expected to be Mutex#lock/synchronize
|
|
307
|
+
state_label->str = DDOG_CHARSLICE_C("blocked");
|
|
308
|
+
} else if (CHARSLICE_EQUALS("sleep", method)) { // Expected to be Mutex#sleep
|
|
309
|
+
state_label->str = DDOG_CHARSLICE_C("sleeping");
|
|
310
|
+
} else if (CHARSLICE_EQUALS("wait", method)) { // Expected to be ConditionVariable#wait
|
|
311
|
+
state_label->str = DDOG_CHARSLICE_C("waiting");
|
|
312
|
+
}
|
|
313
|
+
#endif
|
|
314
|
+
}
|
|
315
|
+
#endif
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
242
319
|
// Idea: Should we release the global vm lock (GVL) after we get the data from `rb_profile_frames`? That way other Ruby threads
|
|
243
320
|
// could continue making progress while the sample was ingested into the profile.
|
|
244
321
|
//
|
|
@@ -354,91 +431,45 @@ void sample_thread(
|
|
|
354
431
|
);
|
|
355
432
|
}
|
|
356
433
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
//
|
|
360
|
-
|
|
361
|
-
ddog_CharSlice name_slice = (name == Qfalse) ? DDOG_CHARSLICE_C("") : char_slice_from_ruby_string(name);
|
|
434
|
+
// This frame kept the name we composed for it in an earlier sample, so there's nothing to compose or trim again
|
|
435
|
+
char *cached_name = buffer->cached_names == NULL ? NULL : buffer->cached_names + (i * MAX_CACHED_FRAME_NAME);
|
|
436
|
+
// The length is only ever set together with the name it describes, and frames start out zeroed
|
|
437
|
+
bool name_is_cached = frame.cached_name_len > 0;
|
|
362
438
|
|
|
363
|
-
ddog_CharSlice
|
|
364
|
-
|
|
439
|
+
ddog_CharSlice frame_name;
|
|
440
|
+
// We only keep a name we managed to compose: ddtrace_location_label() also fails when this stack used up the
|
|
441
|
+
// scratch buffer, and keeping the unqualified name it falls back to would stick to the frame even once there's
|
|
442
|
+
// room for it again.
|
|
443
|
+
bool name_is_cacheable = false;
|
|
444
|
+
if (name_is_cached) {
|
|
445
|
+
frame_name = (ddog_CharSlice) {.ptr = cached_name, .len = frame.cached_name_len};
|
|
446
|
+
} else if (show_classes) {
|
|
365
447
|
ssize_t written = ddtrace_location_label(cme, iseq, qualified_name_buf, qualified_name_buf_size);
|
|
366
448
|
if (written > 0) {
|
|
367
|
-
|
|
449
|
+
frame_name = (ddog_CharSlice) {.ptr = qualified_name_buf, .len = written};
|
|
368
450
|
qualified_name_buf += written;
|
|
369
451
|
qualified_name_buf_size -= written;
|
|
452
|
+
name_is_cacheable = true;
|
|
370
453
|
} else {
|
|
371
|
-
|
|
454
|
+
frame_name = unqualified_name(cme, iseq); // just the method name
|
|
372
455
|
}
|
|
456
|
+
} else {
|
|
457
|
+
frame_name = unqualified_name(cme, iseq);
|
|
373
458
|
}
|
|
374
459
|
|
|
375
|
-
// When there's only wall-time in a sample, this means that the thread was not active in the sampled period.
|
|
376
460
|
if (top_of_the_stack && only_wall_time) {
|
|
377
|
-
|
|
378
|
-
if (labels.is_gvl_waiting_state) {
|
|
379
|
-
state_label->str = DDOG_CHARSLICE_C("waiting for gvl");
|
|
380
|
-
|
|
381
|
-
// Otherwise, we try to categorize what the thread was doing based on what we observe at the top of the stack. This is a very rough
|
|
382
|
-
// approximation, and in the future we hope to replace this with a more accurate approach (such as using the
|
|
383
|
-
// GVL instrumentation API.)
|
|
384
|
-
} else if (!frame.is_ruby_frame) {
|
|
385
|
-
// We know that known versions of Ruby implement these using native code; thus if we find a method with the
|
|
386
|
-
// same name that is not native code, we ignore it, as it's probably a user method that coincidentally
|
|
387
|
-
// has the same name. Thus, even though "matching just by method name" is kinda weak,
|
|
388
|
-
// "matching by method name" + is native code seems actually to be good enough for a lot of cases.
|
|
389
|
-
|
|
390
|
-
if (CHARSLICE_EQUALS("sleep", name_slice)) { // Expected to be Kernel.sleep
|
|
391
|
-
state_label->str = DDOG_CHARSLICE_C("sleeping");
|
|
392
|
-
} else if (CHARSLICE_EQUALS("select", name_slice)) { // Expected to be Kernel.select
|
|
393
|
-
state_label->str = DDOG_CHARSLICE_C("waiting");
|
|
394
|
-
} else if (
|
|
395
|
-
CHARSLICE_EQUALS("synchronize", name_slice) || // Expected to be Monitor/Mutex#synchronize on Ruby 2 & 3, and Monitor#synchronize on 4 (Mutex becomes <internal:thread_sync>)
|
|
396
|
-
#ifdef NO_PRIMITIVE_MUTEX_AND_CONDITION_VARIABLE // Ruby < 4
|
|
397
|
-
CHARSLICE_EQUALS("lock", name_slice) || // Expected to be Mutex#lock
|
|
398
|
-
#endif
|
|
399
|
-
CHARSLICE_EQUALS("join", name_slice) // Expected to be Thread#join
|
|
400
|
-
) {
|
|
401
|
-
state_label->str = DDOG_CHARSLICE_C("blocked");
|
|
402
|
-
} else if (CHARSLICE_EQUALS("wait_readable", name_slice)) { // Expected to be IO#wait_readable
|
|
403
|
-
state_label->str = DDOG_CHARSLICE_C("network");
|
|
404
|
-
} else if (CHARSLICE_EQUALS("_native_idle_sampling_loop", name_slice)) { // Expected to be Datadog::Profiler::Collectors::IdleSamplingHelper#_native_idle_sampling_loop
|
|
405
|
-
state_label->str = DDOG_CHARSLICE_C("waiting");
|
|
406
|
-
} else if (CHARSLICE_EQUALS("_native_sampling_loop", name_slice)) { // Expected to be Datadog::Profiler::Collectors::CpuAndWallTimeWorker#_native_sampling_loop
|
|
407
|
-
state_label->str = DDOG_CHARSLICE_C("sleeping");
|
|
408
|
-
}
|
|
409
|
-
#ifdef NO_PRIMITIVE_POP // Ruby < 3.2
|
|
410
|
-
else if (CHARSLICE_EQUALS("pop", name_slice)) { // Expected to be Queue/SizedQueue#pop
|
|
411
|
-
state_label->str = DDOG_CHARSLICE_C("waiting");
|
|
412
|
-
}
|
|
413
|
-
#endif
|
|
414
|
-
} else {
|
|
415
|
-
#ifndef NO_PRIMITIVE_POP // Ruby >= 3.2
|
|
416
|
-
if (CHARSLICE_EQUALS("<internal:thread_sync>", filename_slice)) {
|
|
417
|
-
if (CHARSLICE_EQUALS("pop", name_slice)) { // Expected to be Queue/SizedQueue#pop
|
|
418
|
-
state_label->str = DDOG_CHARSLICE_C("waiting");
|
|
419
|
-
}
|
|
420
|
-
#ifndef NO_PRIMITIVE_MUTEX_AND_CONDITION_VARIABLE // Ruby >= 4
|
|
421
|
-
else if (CHARSLICE_EQUALS("synchronize", name_slice) || CHARSLICE_EQUALS("lock", name_slice)) { // Expected to be Mutex#lock/synchronize
|
|
422
|
-
state_label->str = DDOG_CHARSLICE_C("blocked");
|
|
423
|
-
} else if (CHARSLICE_EQUALS("sleep", name_slice)) { // Expected to be Mutex#sleep
|
|
424
|
-
state_label->str = DDOG_CHARSLICE_C("sleeping");
|
|
425
|
-
} else if (CHARSLICE_EQUALS("wait", name_slice)) { // Expected to be ConditionVariable#wait
|
|
426
|
-
state_label->str = DDOG_CHARSLICE_C("waiting");
|
|
427
|
-
}
|
|
428
|
-
#endif
|
|
429
|
-
}
|
|
430
|
-
#endif
|
|
431
|
-
}
|
|
461
|
+
categorize_sample_state(labels, frame, unqualified_name(cme, iseq), filename_slice);
|
|
432
462
|
}
|
|
433
463
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
frame_name = qualified_name;
|
|
437
|
-
} else {
|
|
438
|
-
frame_name = name_slice;
|
|
439
|
-
}
|
|
464
|
+
if (!name_is_cached) {
|
|
465
|
+
maybe_trim_template_random_ids(&frame_name, filename_slice, name_is_cacheable);
|
|
440
466
|
|
|
441
|
-
|
|
467
|
+
// Keep this name for as long as the frame stays in the buffer
|
|
468
|
+
if (cached_name != NULL && name_is_cacheable && frame_name.len <= MAX_CACHED_FRAME_NAME) {
|
|
469
|
+
memcpy(cached_name, frame_name.ptr, frame_name.len);
|
|
470
|
+
buffer->stack_buffer[i].cached_name_len = frame_name.len;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
442
473
|
|
|
443
474
|
int libdatadog_stores_stacks_flipped_from_rb_profile_frames_index = top_of_stack_position - i;
|
|
444
475
|
|
|
@@ -549,49 +580,55 @@ static const char *get_or_compute_native_filename(void *function, st_table *nati
|
|
|
549
580
|
//
|
|
550
581
|
// This method trims these suffixes, so that we keep less data + the names correctly aggregate together.
|
|
551
582
|
//
|
|
552
|
-
//
|
|
553
|
-
//
|
|
554
|
-
//
|
|
555
|
-
|
|
556
|
-
|
|
583
|
+
// The ids end `frame_name`, or sit right before DDTRACE_BLOCK_SUFFIX
|
|
584
|
+
// ("Foo#_app_views_articles_index_html_erb__123_456 (block)"); in that case we move the suffix left over the ids.
|
|
585
|
+
// That write needs a name we composed ourselves, which is what `frame_name_in_scratch_buffer` tells us.
|
|
586
|
+
static void maybe_trim_template_random_ids(
|
|
587
|
+
ddog_CharSlice *frame_name,
|
|
588
|
+
ddog_CharSlice filename,
|
|
589
|
+
bool frame_name_in_scratch_buffer
|
|
590
|
+
) {
|
|
557
591
|
// Check filename doesn't end with ".rb"; templates are usually along the lines of .html.erb/.html.haml/...
|
|
558
592
|
if (filename.len < 3 || memcmp(filename.ptr + filename.len - 3, ".rb", 3) == 0) return;
|
|
559
593
|
|
|
560
|
-
if (
|
|
561
|
-
if (
|
|
594
|
+
if (frame_name->len > 1024) return;
|
|
595
|
+
if (frame_name->len == 0) return;
|
|
596
|
+
|
|
597
|
+
static const char block_suffix[] = DDTRACE_BLOCK_SUFFIX;
|
|
598
|
+
size_t block_suffix_len = sizeof(block_suffix) - 1;
|
|
599
|
+
|
|
600
|
+
size_t len = frame_name->len;
|
|
601
|
+
bool has_block_suffix =
|
|
602
|
+
frame_name_in_scratch_buffer &&
|
|
603
|
+
len > block_suffix_len &&
|
|
604
|
+
memcmp(frame_name->ptr + len - block_suffix_len, block_suffix, block_suffix_len) == 0;
|
|
605
|
+
if (has_block_suffix) len -= block_suffix_len;
|
|
562
606
|
|
|
563
|
-
int pos = ((int)
|
|
607
|
+
int pos = ((int) len) - 1;
|
|
564
608
|
|
|
565
609
|
// Let's match on something__number_number:
|
|
566
610
|
// Find start of id suffix from the end...
|
|
567
|
-
if (
|
|
611
|
+
if (frame_name->ptr[pos] < '0' || frame_name->ptr[pos] > '9') return;
|
|
568
612
|
|
|
569
613
|
// ...now match a bunch of numbers and interspersed underscores
|
|
570
614
|
for (int underscores = 0; pos >= 0 && underscores < 2; pos--) {
|
|
571
|
-
if (
|
|
572
|
-
else if (
|
|
615
|
+
if (frame_name->ptr[pos] == '_') underscores++;
|
|
616
|
+
else if (frame_name->ptr[pos] < '0' || frame_name->ptr[pos] > '9') return;
|
|
573
617
|
}
|
|
574
618
|
|
|
575
619
|
// Make sure there's something left before the underscores (hence the <= instead of <) + match the last underscore
|
|
576
|
-
if (pos <= 0 ||
|
|
620
|
+
if (pos <= 0 || frame_name->ptr[pos] != '_') return;
|
|
577
621
|
|
|
578
622
|
// Does it have the optional third underscore? If so, remove it as well
|
|
579
|
-
if (pos > 1 &&
|
|
623
|
+
if (pos > 1 && frame_name->ptr[pos-1] == '_') pos--;
|
|
580
624
|
|
|
581
|
-
// If we got here, we matched on our pattern. Let's
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
if (
|
|
588
|
-
frame_name->len >= random_ids_len + block_suffix_len &&
|
|
589
|
-
memcmp(frame_name->ptr + frame_name->len - block_suffix_len, block_suffix, block_suffix_len) == 0
|
|
590
|
-
) {
|
|
591
|
-
memcpy((char *) frame_name->ptr + frame_name->len - block_suffix_len - random_ids_len, block_suffix, block_suffix_len);
|
|
625
|
+
// If we got here, we matched on our pattern. Let's slice the length of the string to exclude it.
|
|
626
|
+
if (has_block_suffix) {
|
|
627
|
+
memcpy((char *) frame_name->ptr + pos, block_suffix, block_suffix_len);
|
|
628
|
+
frame_name->len = pos + block_suffix_len;
|
|
629
|
+
} else {
|
|
630
|
+
frame_name->len = pos;
|
|
592
631
|
}
|
|
593
|
-
|
|
594
|
-
frame_name->len -= random_ids_len;
|
|
595
632
|
}
|
|
596
633
|
|
|
597
634
|
static void add_truncated_frames_placeholder(ddog_prof_Location *locations) {
|
|
@@ -697,7 +734,7 @@ uint16_t sampling_buffer_check_max_frames(int max_frames) {
|
|
|
697
734
|
return max_frames;
|
|
698
735
|
}
|
|
699
736
|
|
|
700
|
-
void sampling_buffer_initialize(sampling_buffer *buffer, uint16_t max_frames) {
|
|
737
|
+
void sampling_buffer_initialize(sampling_buffer *buffer, uint16_t max_frames, bool cache_names) {
|
|
701
738
|
sampling_buffer_check_max_frames(max_frames);
|
|
702
739
|
|
|
703
740
|
buffer->max_frames = max_frames;
|
|
@@ -705,16 +742,19 @@ void sampling_buffer_initialize(sampling_buffer *buffer, uint16_t max_frames) {
|
|
|
705
742
|
buffer->pending_sample = false;
|
|
706
743
|
buffer->is_marking = false;
|
|
707
744
|
buffer->pending_sample_result = 0;
|
|
745
|
+
buffer->cached_names = cache_names ? ruby_xcalloc(max_frames, MAX_CACHED_FRAME_NAME) : NULL;
|
|
708
746
|
}
|
|
709
747
|
|
|
710
748
|
void sampling_buffer_free(sampling_buffer *buffer) {
|
|
711
749
|
ruby_xfree(buffer->stack_buffer);
|
|
750
|
+
ruby_xfree(buffer->cached_names);
|
|
712
751
|
|
|
713
752
|
buffer->max_frames = 0;
|
|
714
753
|
buffer->stack_buffer = NULL;
|
|
715
754
|
buffer->pending_sample = false;
|
|
716
755
|
buffer->is_marking = false;
|
|
717
756
|
buffer->pending_sample_result = 0;
|
|
757
|
+
buffer->cached_names = NULL;
|
|
718
758
|
}
|
|
719
759
|
|
|
720
760
|
void sampling_buffer_mark(sampling_buffer *buffer) {
|
|
@@ -8,6 +8,10 @@
|
|
|
8
8
|
#define MAX_FRAMES_LIMIT 3000
|
|
9
9
|
#define MAX_FRAMES_LIMIT_AS_STRING "3000"
|
|
10
10
|
|
|
11
|
+
// Longest qualified frame name we keep per frame in `sampling_buffer`. Longer names are still reported, they just get
|
|
12
|
+
// composed again on every sample; this bounds the per-thread memory the cache costs (max_frames * this).
|
|
13
|
+
#define MAX_CACHED_FRAME_NAME 96
|
|
14
|
+
|
|
11
15
|
// Per thread, where we store the stack sample
|
|
12
16
|
typedef struct {
|
|
13
17
|
uint16_t max_frames;
|
|
@@ -15,6 +19,10 @@ typedef struct {
|
|
|
15
19
|
bool pending_sample;
|
|
16
20
|
bool is_marking; // Used to avoid recording a sample when marking (marking can happen outside of GC as well)
|
|
17
21
|
int pending_sample_result;
|
|
22
|
+
// Qualified frame names from the last sample, MAX_CACHED_FRAME_NAME bytes per frame (NULL when not qualifying names).
|
|
23
|
+
// A frame keeps its name for as long as it stays in `stack_buffer`, which is most of the time: between two samples
|
|
24
|
+
// of a thread, usually only the frames close to the top of the stack change.
|
|
25
|
+
char *cached_names;
|
|
18
26
|
} sampling_buffer;
|
|
19
27
|
|
|
20
28
|
// 1 per ThreadContext so effectively global.
|
|
@@ -55,7 +63,7 @@ void sample_locations_initialize(sample_locations *locations, uint16_t max_frame
|
|
|
55
63
|
void sample_locations_free(sample_locations *locations);
|
|
56
64
|
|
|
57
65
|
uint16_t sampling_buffer_check_max_frames(int max_frames);
|
|
58
|
-
void sampling_buffer_initialize(sampling_buffer *buffer, uint16_t max_frames);
|
|
66
|
+
void sampling_buffer_initialize(sampling_buffer *buffer, uint16_t max_frames, bool cache_names);
|
|
59
67
|
void sampling_buffer_free(sampling_buffer *buffer);
|
|
60
68
|
void sampling_buffer_mark(sampling_buffer *buffer);
|
|
61
69
|
static inline bool sampling_buffer_needs_marking(sampling_buffer *buffer) {
|
|
@@ -122,6 +122,10 @@ static ID otel_fiber_context_storage_id; // id of :@opentelemetry_context in Rub
|
|
|
122
122
|
// in settings.rb. See `initialize_context` for details on why this is needed/used.
|
|
123
123
|
static uint16_t latest_max_frames = 400;
|
|
124
124
|
|
|
125
|
+
// Same as `latest_max_frames`, for deciding whether new sampling buffers need room to cache qualified frame names.
|
|
126
|
+
// Should be kept in sync with the default for DD_PROFILING_EXPERIMENTAL_SHOW_CLASSES_ENABLED in settings.rb.
|
|
127
|
+
static bool latest_show_classes = true;
|
|
128
|
+
|
|
125
129
|
// Global tracepoint for RUBY_EVENT_THREAD_BEGIN. Created and enabled once when the first ThreadContext collector is initialized.
|
|
126
130
|
static VALUE thread_begin_tracepoint = Qnil;
|
|
127
131
|
|
|
@@ -1265,7 +1269,7 @@ static void initialize_context(VALUE thread, per_thread_context *thread_context,
|
|
|
1265
1269
|
// We always create per_thread_context's with latest_max_frames; that value is kept in sync with the
|
|
1266
1270
|
// active profiler's max_frames by the global reset that runs when profiling starts
|
|
1267
1271
|
// so we expect to always see here the latest correct value to be used.
|
|
1268
|
-
sampling_buffer_initialize(&thread_context->sampling_buffer, latest_max_frames);
|
|
1272
|
+
sampling_buffer_initialize(&thread_context->sampling_buffer, latest_max_frames, latest_show_classes);
|
|
1269
1273
|
|
|
1270
1274
|
snprintf(thread_context->thread_id, THREAD_ID_LIMIT_CHARS, "%"PRIu64" (%lu)", native_thread_id_for(thread), (unsigned long) thread_id_for(thread));
|
|
1271
1275
|
thread_context->thread_id_char_slice = (ddog_CharSlice) {.ptr = thread_context->thread_id, .len = strlen(thread_context->thread_id)};
|
|
@@ -1327,6 +1331,7 @@ void thread_context_collector_reset_all_per_thread_contexts(VALUE self_instance)
|
|
|
1327
1331
|
}
|
|
1328
1332
|
|
|
1329
1333
|
latest_max_frames = state->locations.len;
|
|
1334
|
+
latest_show_classes = state->show_classes;
|
|
1330
1335
|
|
|
1331
1336
|
long current_monotonic_wall_time_ns = monotonic_wall_time_now_ns();
|
|
1332
1337
|
|
|
@@ -20,7 +20,7 @@ def skip_building_extension!(reason)
|
|
|
20
20
|
Datadog::Profiling::NativeExtensionHelpers::Supported.failure_banner_for(
|
|
21
21
|
**reason,
|
|
22
22
|
fail_install: fail_install_if_missing_extension,
|
|
23
|
-
)
|
|
23
|
+
),
|
|
24
24
|
)
|
|
25
25
|
|
|
26
26
|
File.write(
|
|
@@ -32,7 +32,7 @@ def skip_building_extension!(reason)
|
|
|
32
32
|
require "mkmf"
|
|
33
33
|
Logging.message(
|
|
34
34
|
"[datadog] Failure cause: " \
|
|
35
|
-
"#{Datadog::Profiling::NativeExtensionHelpers::Supported.render_skipped_reason_file(**reason)}\n"
|
|
35
|
+
"#{Datadog::Profiling::NativeExtensionHelpers::Supported.render_skipped_reason_file(**reason)}\n",
|
|
36
36
|
)
|
|
37
37
|
else
|
|
38
38
|
File.write("Makefile", "all install clean: # dummy makefile that does nothing")
|
|
@@ -63,7 +63,7 @@ $stderr.puts(
|
|
|
63
63
|
| Thanks for using datadog! You rock! |
|
|
64
64
|
+------------------------------------------------------------------------------+
|
|
65
65
|
|
|
66
|
-
)
|
|
66
|
+
),
|
|
67
67
|
)
|
|
68
68
|
|
|
69
69
|
# NOTE: we MUST NOT require 'mkmf' before we check the #skip_building_extension? because the require triggers checks
|
|
@@ -89,12 +89,10 @@ append_cflags "-Werror" if ENV["DATADOG_GEM_CI"] == "true"
|
|
|
89
89
|
# header lands upstream in libdatadog/libdatadog-rb. Remove this once that ships.
|
|
90
90
|
append_cflags "-Wno-error=typedef-redefinition" if ENV["DATADOG_GEM_CI"] == "true"
|
|
91
91
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
# @ivoanjo: We could probably start using C11/gnu11 for non macOS-too but it's somewhat hard to validate so I chickened out for now
|
|
97
|
-
append_cflags RUBY_PLATFORM.include?("darwin") ? "-std=gnu11" : "-std=gnu99"
|
|
92
|
+
unless try_cflags("-std=gnu11") && have_type("atomic_int", ["stdatomic.h"])
|
|
93
|
+
skip_building_extension!(Datadog::Profiling::NativeExtensionHelpers::Supported::COMPILER_C11_MISSING)
|
|
94
|
+
end
|
|
95
|
+
$CFLAGS += " -std=gnu11"
|
|
98
96
|
|
|
99
97
|
# Gets really noisy when we include the private VM headers, let's omit it (TODO: Use #pragma GCC diagnostic instead?)
|
|
100
98
|
append_cflags "-Wno-unused-function"
|
|
@@ -225,10 +223,6 @@ end
|
|
|
225
223
|
|
|
226
224
|
Datadog::LibdatadogExtconfHelpers.add_libdatadog_version_define
|
|
227
225
|
|
|
228
|
-
unless have_type("atomic_int", ["stdatomic.h"])
|
|
229
|
-
skip_building_extension!(Datadog::Profiling::NativeExtensionHelpers::Supported::COMPILER_ATOMIC_MISSING)
|
|
230
|
-
end
|
|
231
|
-
|
|
232
226
|
# Tag the native extension library with the Ruby version and Ruby platform.
|
|
233
227
|
# This makes it easier for development (avoids "oops I forgot to rebuild when I switched my Ruby") and ensures that
|
|
234
228
|
# the wrong library is never loaded.
|
|
@@ -94,9 +94,9 @@ module Datadog
|
|
|
94
94
|
)
|
|
95
95
|
|
|
96
96
|
# Validation for this check is done in extconf.rb because it relies on mkmf
|
|
97
|
-
|
|
98
|
-
"your C compiler
|
|
99
|
-
"This issue can
|
|
97
|
+
COMPILER_C11_MISSING = explain_issue(
|
|
98
|
+
"your C compiler does not support C11 (-std=gnu11).",
|
|
99
|
+
"This issue can be fixed by upgrading to a later version of your",
|
|
100
100
|
"operating system image or compiler.",
|
|
101
101
|
suggested: CONTACT_SUPPORT,
|
|
102
102
|
)
|