ddtrace 0.45.0 → 0.52.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/.editorconfig +22 -0
- data/.gitignore +7 -1
- data/CHANGELOG.md +406 -1
- data/CONTRIBUTING.md +1 -5
- data/LICENSE-3rdparty.csv +2 -0
- data/bin/ddtracerb +15 -0
- data/ddtrace.gemspec +19 -38
- data/docs/DevelopmentGuide.md +43 -0
- data/docs/GettingStarted.md +164 -76
- data/docs/ProfilingDevelopment.md +107 -0
- data/ext/ddtrace_profiling_native_extension/extconf.rb +28 -0
- data/ext/ddtrace_profiling_native_extension/profiling.c +17 -0
- data/lib/datadog/ci/configuration/components.rb +31 -0
- data/lib/datadog/ci/configuration/settings.rb +37 -0
- data/lib/datadog/ci/context_flush.rb +29 -0
- data/lib/datadog/ci/contrib/cucumber/configuration/settings.rb +31 -0
- data/lib/datadog/ci/contrib/cucumber/ext.rb +20 -0
- data/lib/datadog/ci/contrib/cucumber/formatter.rb +98 -0
- data/lib/datadog/ci/contrib/cucumber/instrumentation.rb +27 -0
- data/lib/datadog/ci/contrib/cucumber/integration.rb +48 -0
- data/lib/datadog/ci/contrib/cucumber/patcher.rb +26 -0
- data/lib/datadog/ci/contrib/rspec/configuration/settings.rb +31 -0
- data/lib/datadog/ci/contrib/rspec/example.rb +74 -0
- data/lib/datadog/ci/contrib/rspec/ext.rb +19 -0
- data/lib/datadog/ci/contrib/rspec/integration.rb +49 -0
- data/lib/datadog/ci/contrib/rspec/patcher.rb +26 -0
- data/lib/datadog/ci/ext/app_types.rb +10 -0
- data/lib/datadog/ci/ext/environment.rb +443 -0
- data/lib/datadog/ci/ext/settings.rb +11 -0
- data/lib/datadog/ci/ext/test.rb +35 -0
- data/lib/datadog/ci/extensions.rb +18 -0
- data/lib/datadog/ci/test.rb +77 -0
- data/lib/datadog/ci.rb +17 -0
- data/lib/datadog/contrib.rb +69 -0
- data/lib/datadog/core/environment/cgroup.rb +52 -0
- data/lib/datadog/core/environment/class_count.rb +20 -0
- data/lib/datadog/core/environment/container.rb +91 -0
- data/lib/datadog/core/environment/ext.rb +27 -0
- data/lib/datadog/core/environment/gc.rb +19 -0
- data/lib/datadog/core/environment/identity.rb +51 -0
- data/lib/datadog/core/environment/socket.rb +17 -0
- data/lib/datadog/core/environment/thread_count.rb +19 -0
- data/lib/datadog/core/environment/variable_helpers.rb +42 -0
- data/lib/ddtrace/analytics.rb +3 -0
- data/lib/ddtrace/auto_instrument.rb +2 -0
- data/lib/ddtrace/auto_instrument_base.rb +1 -0
- data/lib/ddtrace/buffer.rb +10 -8
- data/lib/ddtrace/chunker.rb +1 -0
- data/lib/ddtrace/configuration/agent_settings_resolver.rb +231 -0
- data/lib/ddtrace/configuration/base.rb +9 -11
- data/lib/ddtrace/configuration/components.rb +167 -26
- data/lib/ddtrace/configuration/dependency_resolver.rb +1 -0
- data/lib/ddtrace/configuration/option.rb +1 -0
- data/lib/ddtrace/configuration/option_definition.rb +2 -3
- data/lib/ddtrace/configuration/option_definition_set.rb +1 -0
- data/lib/ddtrace/configuration/option_set.rb +1 -0
- data/lib/ddtrace/configuration/options.rb +7 -9
- data/lib/ddtrace/configuration/pin_setup.rb +1 -0
- data/lib/ddtrace/configuration/settings.rb +128 -10
- data/lib/ddtrace/configuration.rb +118 -26
- data/lib/ddtrace/context.rb +23 -20
- data/lib/ddtrace/context_flush.rb +15 -2
- data/lib/ddtrace/context_provider.rb +1 -1
- data/lib/ddtrace/contrib/action_cable/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/action_cable/event.rb +6 -4
- data/lib/ddtrace/contrib/action_cable/events/broadcast.rb +1 -0
- data/lib/ddtrace/contrib/action_cable/events/perform_action.rb +1 -0
- data/lib/ddtrace/contrib/action_cable/events/transmit.rb +1 -0
- data/lib/ddtrace/contrib/action_cable/events.rb +1 -0
- data/lib/ddtrace/contrib/action_cable/ext.rb +1 -0
- data/lib/ddtrace/contrib/action_cable/instrumentation.rb +1 -0
- data/lib/ddtrace/contrib/action_cable/integration.rb +1 -0
- data/lib/ddtrace/contrib/action_cable/patcher.rb +1 -0
- data/lib/ddtrace/contrib/action_pack/action_controller/instrumentation.rb +22 -13
- data/lib/ddtrace/contrib/action_pack/action_controller/patcher.rb +2 -1
- data/lib/ddtrace/contrib/action_pack/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/action_pack/ext.rb +1 -0
- data/lib/ddtrace/contrib/action_pack/integration.rb +1 -0
- data/lib/ddtrace/contrib/action_pack/patcher.rb +1 -0
- data/lib/ddtrace/contrib/action_pack/utils.rb +2 -1
- data/lib/ddtrace/contrib/action_view/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/action_view/event.rb +4 -3
- data/lib/ddtrace/contrib/action_view/events/render_partial.rb +1 -0
- data/lib/ddtrace/contrib/action_view/events/render_template.rb +1 -0
- data/lib/ddtrace/contrib/action_view/events.rb +1 -0
- data/lib/ddtrace/contrib/action_view/ext.rb +1 -0
- data/lib/ddtrace/contrib/action_view/instrumentation/partial_renderer.rb +1 -0
- data/lib/ddtrace/contrib/action_view/instrumentation/template_renderer.rb +1 -0
- data/lib/ddtrace/contrib/action_view/integration.rb +1 -0
- data/lib/ddtrace/contrib/action_view/patcher.rb +5 -4
- data/lib/ddtrace/contrib/action_view/utils.rb +2 -1
- data/lib/ddtrace/contrib/active_model_serializers/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/active_model_serializers/event.rb +3 -2
- data/lib/ddtrace/contrib/active_model_serializers/events/render.rb +1 -0
- data/lib/ddtrace/contrib/active_model_serializers/events/serialize.rb +1 -0
- data/lib/ddtrace/contrib/active_model_serializers/events.rb +1 -0
- data/lib/ddtrace/contrib/active_model_serializers/ext.rb +1 -0
- data/lib/ddtrace/contrib/active_model_serializers/integration.rb +1 -0
- data/lib/ddtrace/contrib/active_model_serializers/patcher.rb +1 -0
- data/lib/ddtrace/contrib/active_record/configuration/makara_resolver.rb +31 -0
- data/lib/ddtrace/contrib/active_record/configuration/resolver.rb +108 -18
- data/lib/ddtrace/contrib/active_record/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/active_record/event.rb +3 -2
- data/lib/ddtrace/contrib/active_record/events/instantiation.rb +1 -0
- data/lib/ddtrace/contrib/active_record/events/sql.rb +1 -0
- data/lib/ddtrace/contrib/active_record/events.rb +1 -0
- data/lib/ddtrace/contrib/active_record/ext.rb +1 -0
- data/lib/ddtrace/contrib/active_record/integration.rb +1 -0
- data/lib/ddtrace/contrib/active_record/patcher.rb +1 -0
- data/lib/ddtrace/contrib/active_record/utils.rb +5 -3
- data/lib/ddtrace/contrib/active_support/cache/instrumentation.rb +1 -0
- data/lib/ddtrace/contrib/active_support/cache/patcher.rb +8 -7
- data/lib/ddtrace/contrib/active_support/cache/redis.rb +2 -5
- data/lib/ddtrace/contrib/active_support/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/active_support/ext.rb +1 -0
- data/lib/ddtrace/contrib/active_support/integration.rb +1 -0
- data/lib/ddtrace/contrib/active_support/notifications/event.rb +5 -3
- data/lib/ddtrace/contrib/active_support/notifications/subscriber.rb +3 -1
- data/lib/ddtrace/contrib/active_support/notifications/subscription.rb +10 -5
- data/lib/ddtrace/contrib/active_support/patcher.rb +1 -0
- data/lib/ddtrace/contrib/analytics.rb +1 -0
- data/lib/ddtrace/contrib/auto_instrument.rb +4 -3
- data/lib/ddtrace/contrib/aws/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/aws/ext.rb +1 -0
- data/lib/ddtrace/contrib/aws/instrumentation.rb +30 -0
- data/lib/ddtrace/contrib/aws/integration.rb +1 -0
- data/lib/ddtrace/contrib/aws/parsed_context.rb +1 -0
- data/lib/ddtrace/contrib/aws/patcher.rb +6 -0
- data/lib/ddtrace/contrib/aws/services.rb +3 -0
- data/lib/ddtrace/contrib/concurrent_ruby/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/concurrent_ruby/context_composite_executor_service.rb +1 -0
- data/lib/ddtrace/contrib/concurrent_ruby/ext.rb +1 -0
- data/lib/ddtrace/contrib/concurrent_ruby/future_patch.rb +1 -0
- data/lib/ddtrace/contrib/concurrent_ruby/integration.rb +1 -0
- data/lib/ddtrace/contrib/concurrent_ruby/patcher.rb +3 -1
- data/lib/ddtrace/contrib/configurable.rb +65 -40
- data/lib/ddtrace/contrib/configuration/resolver.rb +71 -5
- data/lib/ddtrace/contrib/configuration/resolvers/pattern_resolver.rb +20 -20
- data/lib/ddtrace/contrib/configuration/settings.rb +8 -6
- data/lib/ddtrace/contrib/dalli/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/dalli/ext.rb +1 -0
- data/lib/ddtrace/contrib/dalli/instrumentation.rb +2 -1
- data/lib/ddtrace/contrib/dalli/integration.rb +1 -0
- data/lib/ddtrace/contrib/dalli/patcher.rb +2 -39
- data/lib/ddtrace/contrib/dalli/quantize.rb +1 -0
- data/lib/ddtrace/contrib/delayed_job/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/delayed_job/ext.rb +1 -0
- data/lib/ddtrace/contrib/delayed_job/integration.rb +1 -0
- data/lib/ddtrace/contrib/delayed_job/patcher.rb +1 -0
- data/lib/ddtrace/contrib/delayed_job/plugin.rb +1 -1
- data/lib/ddtrace/contrib/elasticsearch/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/elasticsearch/ext.rb +1 -0
- data/lib/ddtrace/contrib/elasticsearch/integration.rb +1 -0
- data/lib/ddtrace/contrib/elasticsearch/patcher.rb +2 -0
- data/lib/ddtrace/contrib/elasticsearch/quantize.rb +6 -2
- data/lib/ddtrace/contrib/ethon/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/ethon/easy_patch.rb +7 -6
- data/lib/ddtrace/contrib/ethon/ext.rb +1 -0
- data/lib/ddtrace/contrib/ethon/integration.rb +1 -0
- data/lib/ddtrace/contrib/ethon/multi_patch.rb +2 -1
- data/lib/ddtrace/contrib/ethon/patcher.rb +4 -2
- data/lib/ddtrace/contrib/excon/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/excon/ext.rb +1 -0
- data/lib/ddtrace/contrib/excon/integration.rb +1 -0
- data/lib/ddtrace/contrib/excon/middleware.rb +3 -6
- data/lib/ddtrace/contrib/excon/patcher.rb +1 -0
- data/lib/ddtrace/contrib/extensions.rb +64 -14
- data/lib/ddtrace/contrib/faraday/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/faraday/connection.rb +1 -0
- data/lib/ddtrace/contrib/faraday/ext.rb +1 -0
- data/lib/ddtrace/contrib/faraday/integration.rb +1 -0
- data/lib/ddtrace/contrib/faraday/middleware.rb +2 -3
- data/lib/ddtrace/contrib/faraday/patcher.rb +3 -38
- data/lib/ddtrace/contrib/faraday/rack_builder.rb +1 -0
- data/lib/ddtrace/contrib/grape/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/grape/endpoint.rb +34 -31
- data/lib/ddtrace/contrib/grape/ext.rb +1 -0
- data/lib/ddtrace/contrib/grape/instrumentation.rb +4 -3
- data/lib/ddtrace/contrib/grape/integration.rb +1 -0
- data/lib/ddtrace/contrib/grape/patcher.rb +2 -43
- data/lib/ddtrace/contrib/graphql/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/graphql/ext.rb +1 -0
- data/lib/ddtrace/contrib/graphql/integration.rb +1 -0
- data/lib/ddtrace/contrib/graphql/patcher.rb +1 -0
- data/lib/ddtrace/contrib/grpc/configuration/settings.rb +2 -0
- data/lib/ddtrace/contrib/grpc/datadog_interceptor/client.rb +1 -0
- data/lib/ddtrace/contrib/grpc/datadog_interceptor/server.rb +4 -4
- data/lib/ddtrace/contrib/grpc/datadog_interceptor.rb +13 -8
- data/lib/ddtrace/contrib/grpc/ext.rb +1 -0
- data/lib/ddtrace/contrib/grpc/integration.rb +1 -0
- data/lib/ddtrace/contrib/grpc/intercept_with_datadog.rb +1 -0
- data/lib/ddtrace/contrib/grpc/patcher.rb +3 -37
- data/lib/ddtrace/contrib/http/circuit_breaker.rb +2 -3
- data/lib/ddtrace/contrib/http/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/http/ext.rb +1 -0
- data/lib/ddtrace/contrib/http/instrumentation.rb +7 -6
- data/lib/ddtrace/contrib/http/integration.rb +1 -0
- data/lib/ddtrace/contrib/http/patcher.rb +2 -1
- data/lib/ddtrace/contrib/http_annotation_helper.rb +1 -0
- data/lib/ddtrace/contrib/httpclient/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/httpclient/ext.rb +1 -0
- data/lib/ddtrace/contrib/httpclient/instrumentation.rb +16 -20
- data/lib/ddtrace/contrib/httpclient/integration.rb +1 -0
- data/lib/ddtrace/contrib/httpclient/patcher.rb +8 -4
- data/lib/ddtrace/contrib/httprb/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/httprb/ext.rb +1 -0
- data/lib/ddtrace/contrib/httprb/instrumentation.rb +16 -21
- data/lib/ddtrace/contrib/httprb/integration.rb +1 -0
- data/lib/ddtrace/contrib/httprb/patcher.rb +8 -4
- data/lib/ddtrace/contrib/integration.rb +4 -3
- data/lib/ddtrace/contrib/kafka/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/kafka/consumer_event.rb +1 -0
- data/lib/ddtrace/contrib/kafka/consumer_group_event.rb +1 -0
- data/lib/ddtrace/contrib/kafka/event.rb +3 -2
- data/lib/ddtrace/contrib/kafka/events/connection/request.rb +1 -0
- data/lib/ddtrace/contrib/kafka/events/consumer/process_batch.rb +1 -0
- data/lib/ddtrace/contrib/kafka/events/consumer/process_message.rb +1 -0
- data/lib/ddtrace/contrib/kafka/events/consumer_group/heartbeat.rb +1 -0
- data/lib/ddtrace/contrib/kafka/events/consumer_group/join_group.rb +1 -0
- data/lib/ddtrace/contrib/kafka/events/consumer_group/leave_group.rb +1 -0
- data/lib/ddtrace/contrib/kafka/events/consumer_group/sync_group.rb +1 -0
- data/lib/ddtrace/contrib/kafka/events/produce_operation/send_messages.rb +1 -0
- data/lib/ddtrace/contrib/kafka/events/producer/deliver_messages.rb +1 -0
- data/lib/ddtrace/contrib/kafka/events.rb +1 -0
- data/lib/ddtrace/contrib/kafka/ext.rb +1 -0
- data/lib/ddtrace/contrib/kafka/integration.rb +1 -0
- data/lib/ddtrace/contrib/kafka/patcher.rb +1 -0
- data/lib/ddtrace/contrib/lograge/configuration/settings.rb +19 -0
- data/lib/ddtrace/contrib/lograge/ext.rb +11 -0
- data/lib/ddtrace/contrib/lograge/instrumentation.rb +39 -0
- data/lib/ddtrace/contrib/lograge/integration.rb +46 -0
- data/lib/ddtrace/contrib/{cucumber → lograge}/patcher.rb +7 -4
- data/lib/ddtrace/contrib/mongodb/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/mongodb/ext.rb +1 -0
- data/lib/ddtrace/contrib/mongodb/instrumentation.rb +5 -2
- data/lib/ddtrace/contrib/mongodb/integration.rb +1 -0
- data/lib/ddtrace/contrib/mongodb/parsers.rb +1 -0
- data/lib/ddtrace/contrib/mongodb/patcher.rb +3 -2
- data/lib/ddtrace/contrib/mongodb/subscribers.rb +3 -3
- data/lib/ddtrace/contrib/mysql2/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/mysql2/ext.rb +1 -0
- data/lib/ddtrace/contrib/mysql2/instrumentation.rb +2 -1
- data/lib/ddtrace/contrib/mysql2/integration.rb +1 -0
- data/lib/ddtrace/contrib/mysql2/patcher.rb +2 -1
- data/lib/ddtrace/contrib/patchable.rb +3 -2
- data/lib/ddtrace/contrib/patcher.rb +12 -8
- data/lib/ddtrace/contrib/presto/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/presto/ext.rb +1 -0
- data/lib/ddtrace/contrib/presto/instrumentation.rb +2 -1
- data/lib/ddtrace/contrib/presto/integration.rb +1 -0
- data/lib/ddtrace/contrib/presto/patcher.rb +7 -3
- data/lib/ddtrace/contrib/qless/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/qless/ext.rb +1 -0
- data/lib/ddtrace/contrib/qless/integration.rb +1 -0
- data/lib/ddtrace/contrib/qless/patcher.rb +5 -5
- data/lib/ddtrace/contrib/qless/qless_job.rb +2 -0
- data/lib/ddtrace/contrib/qless/tracer_cleaner.rb +2 -0
- data/lib/ddtrace/contrib/que/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/que/ext.rb +20 -19
- data/lib/ddtrace/contrib/que/integration.rb +1 -0
- data/lib/ddtrace/contrib/que/patcher.rb +1 -0
- data/lib/ddtrace/contrib/que/tracer.rb +2 -1
- data/lib/ddtrace/contrib/racecar/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/racecar/event.rb +4 -2
- data/lib/ddtrace/contrib/racecar/events/batch.rb +1 -0
- data/lib/ddtrace/contrib/racecar/events/consume.rb +1 -0
- data/lib/ddtrace/contrib/racecar/events/message.rb +1 -0
- data/lib/ddtrace/contrib/racecar/events.rb +1 -0
- data/lib/ddtrace/contrib/racecar/ext.rb +1 -0
- data/lib/ddtrace/contrib/racecar/integration.rb +1 -0
- data/lib/ddtrace/contrib/racecar/patcher.rb +1 -0
- data/lib/ddtrace/contrib/rack/configuration/settings.rb +4 -3
- data/lib/ddtrace/contrib/rack/ext.rb +1 -0
- data/lib/ddtrace/contrib/rack/integration.rb +1 -0
- data/lib/ddtrace/contrib/rack/middlewares.rb +7 -11
- data/lib/ddtrace/contrib/rack/patcher.rb +2 -3
- data/lib/ddtrace/contrib/rack/request_queue.rb +1 -0
- data/lib/ddtrace/contrib/rails/auto_instrument_railtie.rb +1 -0
- data/lib/ddtrace/contrib/rails/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/rails/ext.rb +1 -0
- data/lib/ddtrace/contrib/rails/framework.rb +26 -1
- data/lib/ddtrace/contrib/rails/integration.rb +1 -0
- data/lib/ddtrace/contrib/rails/log_injection.rb +1 -40
- data/lib/ddtrace/contrib/rails/middlewares.rb +1 -0
- data/lib/ddtrace/contrib/rails/patcher.rb +18 -11
- data/lib/ddtrace/contrib/rails/railtie.rb +1 -0
- data/lib/ddtrace/contrib/rails/utils.rb +1 -0
- data/lib/ddtrace/contrib/rake/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/rake/ext.rb +1 -0
- data/lib/ddtrace/contrib/rake/instrumentation.rb +6 -3
- data/lib/ddtrace/contrib/rake/integration.rb +1 -0
- data/lib/ddtrace/contrib/rake/patcher.rb +2 -1
- data/lib/ddtrace/contrib/redis/configuration/resolver.rb +12 -4
- data/lib/ddtrace/contrib/redis/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/redis/ext.rb +1 -0
- data/lib/ddtrace/contrib/redis/integration.rb +1 -0
- data/lib/ddtrace/contrib/redis/patcher.rb +1 -0
- data/lib/ddtrace/contrib/redis/quantize.rb +2 -0
- data/lib/ddtrace/contrib/redis/tags.rb +1 -0
- data/lib/ddtrace/contrib/redis/vendor/LICENSE +20 -0
- data/lib/ddtrace/contrib/redis/vendor/resolver.rb +7 -7
- data/lib/ddtrace/contrib/registerable.rb +5 -4
- data/lib/ddtrace/contrib/registry.rb +3 -2
- data/lib/ddtrace/contrib/resque/configuration/settings.rb +18 -1
- data/lib/ddtrace/contrib/resque/ext.rb +1 -0
- data/lib/ddtrace/contrib/resque/integration.rb +2 -1
- data/lib/ddtrace/contrib/resque/patcher.rb +5 -4
- data/lib/ddtrace/contrib/resque/resque_job.rb +25 -1
- data/lib/ddtrace/contrib/rest_client/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/rest_client/ext.rb +1 -0
- data/lib/ddtrace/contrib/rest_client/integration.rb +1 -0
- data/lib/ddtrace/contrib/rest_client/patcher.rb +3 -1
- data/lib/ddtrace/contrib/rest_client/request_patch.rb +3 -4
- data/lib/ddtrace/contrib/semantic_logger/configuration/settings.rb +19 -0
- data/lib/ddtrace/contrib/semantic_logger/ext.rb +11 -0
- data/lib/ddtrace/contrib/semantic_logger/instrumentation.rb +43 -0
- data/lib/ddtrace/contrib/semantic_logger/integration.rb +48 -0
- data/lib/ddtrace/contrib/semantic_logger/patcher.rb +26 -0
- data/lib/ddtrace/contrib/sequel/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/sequel/database.rb +2 -1
- data/lib/ddtrace/contrib/sequel/dataset.rb +2 -1
- data/lib/ddtrace/contrib/sequel/ext.rb +1 -0
- data/lib/ddtrace/contrib/sequel/integration.rb +1 -0
- data/lib/ddtrace/contrib/sequel/patcher.rb +3 -2
- data/lib/ddtrace/contrib/sequel/utils.rb +6 -6
- data/lib/ddtrace/contrib/shoryuken/configuration/settings.rb +2 -0
- data/lib/ddtrace/contrib/shoryuken/ext.rb +1 -0
- data/lib/ddtrace/contrib/shoryuken/integration.rb +1 -0
- data/lib/ddtrace/contrib/shoryuken/patcher.rb +1 -0
- data/lib/ddtrace/contrib/shoryuken/tracer.rb +8 -4
- data/lib/ddtrace/contrib/sidekiq/client_tracer.rb +1 -0
- data/lib/ddtrace/contrib/sidekiq/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/sidekiq/ext.rb +1 -0
- data/lib/ddtrace/contrib/sidekiq/integration.rb +1 -0
- data/lib/ddtrace/contrib/sidekiq/patcher.rb +1 -0
- data/lib/ddtrace/contrib/sidekiq/server_tracer.rb +3 -7
- data/lib/ddtrace/contrib/sidekiq/tracing.rb +1 -1
- data/lib/ddtrace/contrib/sinatra/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/sinatra/env.rb +2 -3
- data/lib/ddtrace/contrib/sinatra/ext.rb +1 -0
- data/lib/ddtrace/contrib/sinatra/headers.rb +2 -3
- data/lib/ddtrace/contrib/sinatra/integration.rb +1 -0
- data/lib/ddtrace/contrib/sinatra/patcher.rb +3 -1
- data/lib/ddtrace/contrib/sinatra/tracer.rb +14 -6
- data/lib/ddtrace/contrib/sinatra/tracer_middleware.rb +11 -4
- data/lib/ddtrace/contrib/sneakers/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/sneakers/ext.rb +12 -11
- data/lib/ddtrace/contrib/sneakers/integration.rb +1 -0
- data/lib/ddtrace/contrib/sneakers/patcher.rb +1 -0
- data/lib/ddtrace/contrib/sneakers/tracer.rb +3 -4
- data/lib/ddtrace/contrib/status_code_matcher.rb +6 -3
- data/lib/ddtrace/contrib/sucker_punch/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/sucker_punch/exception_handler.rb +5 -6
- data/lib/ddtrace/contrib/sucker_punch/ext.rb +1 -0
- data/lib/ddtrace/contrib/sucker_punch/instrumentation.rb +5 -0
- data/lib/ddtrace/contrib/sucker_punch/integration.rb +1 -0
- data/lib/ddtrace/contrib/sucker_punch/patcher.rb +2 -0
- data/lib/ddtrace/correlation.rb +3 -1
- data/lib/ddtrace/diagnostics/environment_logger.rb +9 -7
- data/lib/ddtrace/diagnostics/health.rb +1 -0
- data/lib/ddtrace/distributed_tracing/headers/b3.rb +1 -0
- data/lib/ddtrace/distributed_tracing/headers/b3_single.rb +1 -0
- data/lib/ddtrace/distributed_tracing/headers/datadog.rb +1 -0
- data/lib/ddtrace/distributed_tracing/headers/headers.rb +2 -0
- data/lib/ddtrace/distributed_tracing/headers/helpers.rb +2 -3
- data/lib/ddtrace/encoding.rb +3 -0
- data/lib/ddtrace/error.rb +78 -8
- data/lib/ddtrace/event.rb +1 -0
- data/lib/ddtrace/ext/analytics.rb +1 -0
- data/lib/ddtrace/ext/app_types.rb +1 -1
- data/lib/ddtrace/ext/correlation.rb +1 -0
- data/lib/ddtrace/ext/diagnostics.rb +1 -0
- data/lib/ddtrace/ext/distributed.rb +2 -1
- data/lib/ddtrace/ext/environment.rb +8 -0
- data/lib/ddtrace/ext/errors.rb +1 -0
- data/lib/ddtrace/ext/forced_tracing.rb +1 -0
- data/lib/ddtrace/ext/git.rb +10 -1
- data/lib/ddtrace/ext/http.rb +2 -1
- data/lib/ddtrace/ext/integration.rb +1 -0
- data/lib/ddtrace/ext/manual_tracing.rb +1 -0
- data/lib/ddtrace/ext/metrics.rb +1 -0
- data/lib/ddtrace/ext/net.rb +1 -0
- data/lib/ddtrace/ext/priority.rb +1 -0
- data/lib/ddtrace/ext/profiling.rb +56 -0
- data/lib/ddtrace/ext/runtime.rb +1 -7
- data/lib/ddtrace/ext/sampling.rb +1 -0
- data/lib/ddtrace/ext/sql.rb +1 -0
- data/lib/ddtrace/ext/test.rb +3 -18
- data/lib/ddtrace/ext/transport.rb +3 -0
- data/lib/ddtrace/forced_tracing.rb +3 -0
- data/lib/ddtrace/logger.rb +2 -1
- data/lib/ddtrace/metrics.rb +84 -24
- data/lib/ddtrace/opentelemetry/extensions.rb +2 -1
- data/lib/ddtrace/opentelemetry/span.rb +1 -0
- data/lib/ddtrace/opentracer/binary_propagator.rb +1 -0
- data/lib/ddtrace/opentracer/carrier.rb +1 -0
- data/lib/ddtrace/opentracer/distributed_headers.rb +4 -0
- data/lib/ddtrace/opentracer/global_tracer.rb +1 -0
- data/lib/ddtrace/opentracer/propagator.rb +1 -0
- data/lib/ddtrace/opentracer/rack_propagator.rb +1 -0
- data/lib/ddtrace/opentracer/scope.rb +1 -0
- data/lib/ddtrace/opentracer/scope_manager.rb +1 -0
- data/lib/ddtrace/opentracer/span.rb +3 -6
- data/lib/ddtrace/opentracer/span_context.rb +1 -0
- data/lib/ddtrace/opentracer/span_context_factory.rb +1 -0
- data/lib/ddtrace/opentracer/text_map_propagator.rb +1 -0
- data/lib/ddtrace/opentracer/thread_local_scope.rb +2 -0
- data/lib/ddtrace/opentracer/thread_local_scope_manager.rb +1 -0
- data/lib/ddtrace/opentracer/tracer.rb +1 -0
- data/lib/ddtrace/opentracer.rb +21 -39
- data/lib/ddtrace/patcher.rb +28 -6
- data/lib/ddtrace/pin.rb +9 -61
- data/lib/ddtrace/pipeline/span_filter.rb +2 -1
- data/lib/ddtrace/pipeline/span_processor.rb +1 -0
- data/lib/ddtrace/pipeline.rb +1 -0
- data/lib/ddtrace/profiling/backtrace_location.rb +33 -0
- data/lib/ddtrace/profiling/buffer.rb +42 -0
- data/lib/ddtrace/profiling/collectors/stack.rb +257 -0
- data/lib/ddtrace/profiling/encoding/profile.rb +38 -0
- data/lib/ddtrace/profiling/event.rb +14 -0
- data/lib/ddtrace/profiling/events/stack.rb +81 -0
- data/lib/ddtrace/profiling/exporter.rb +24 -0
- data/lib/ddtrace/profiling/ext/cpu.rb +67 -0
- data/lib/ddtrace/profiling/ext/cthread.rb +156 -0
- data/lib/ddtrace/profiling/ext/forking.rb +98 -0
- data/lib/ddtrace/profiling/flush.rb +44 -0
- data/lib/ddtrace/profiling/native_extension.rb +18 -0
- data/lib/ddtrace/profiling/pprof/builder.rb +120 -0
- data/lib/ddtrace/profiling/pprof/converter.rb +90 -0
- data/lib/ddtrace/profiling/pprof/message_set.rb +15 -0
- data/lib/ddtrace/profiling/pprof/payload.rb +19 -0
- data/lib/ddtrace/profiling/pprof/pprof.proto +212 -0
- data/lib/ddtrace/profiling/pprof/pprof_pb.rb +82 -0
- data/lib/ddtrace/profiling/pprof/stack_sample.rb +117 -0
- data/lib/ddtrace/profiling/pprof/string_table.rb +11 -0
- data/lib/ddtrace/profiling/pprof/template.rb +119 -0
- data/lib/ddtrace/profiling/preload.rb +4 -0
- data/lib/ddtrace/profiling/profiler.rb +31 -0
- data/lib/ddtrace/profiling/recorder.rb +96 -0
- data/lib/ddtrace/profiling/scheduler.rb +134 -0
- data/lib/ddtrace/profiling/tasks/setup.rb +82 -0
- data/lib/ddtrace/profiling/trace_identifiers/ddtrace.rb +41 -0
- data/lib/ddtrace/profiling/trace_identifiers/helper.rb +46 -0
- data/lib/ddtrace/profiling/transport/client.rb +15 -0
- data/lib/ddtrace/profiling/transport/http/api/endpoint.rb +101 -0
- data/lib/ddtrace/profiling/transport/http/api/instance.rb +37 -0
- data/lib/ddtrace/profiling/transport/http/api/spec.rb +41 -0
- data/lib/ddtrace/profiling/transport/http/api.rb +44 -0
- data/lib/ddtrace/profiling/transport/http/builder.rb +29 -0
- data/lib/ddtrace/profiling/transport/http/client.rb +34 -0
- data/lib/ddtrace/profiling/transport/http/response.rb +22 -0
- data/lib/ddtrace/profiling/transport/http.rb +120 -0
- data/lib/ddtrace/profiling/transport/io/client.rb +28 -0
- data/lib/ddtrace/profiling/transport/io/response.rb +17 -0
- data/lib/ddtrace/profiling/transport/io.rb +31 -0
- data/lib/ddtrace/profiling/transport/parcel.rb +18 -0
- data/lib/ddtrace/profiling/transport/request.rb +16 -0
- data/lib/ddtrace/profiling/transport/response.rb +9 -0
- data/lib/ddtrace/profiling.rb +151 -0
- data/lib/ddtrace/propagation/grpc_propagator.rb +2 -0
- data/lib/ddtrace/propagation/http_propagator.rb +3 -2
- data/lib/ddtrace/quantization/hash.rb +1 -0
- data/lib/ddtrace/quantization/http.rb +4 -0
- data/lib/ddtrace/runtime/metrics.rb +21 -14
- data/lib/ddtrace/sampler.rb +2 -1
- data/lib/ddtrace/sampling/matcher.rb +1 -0
- data/lib/ddtrace/sampling/rate_limiter.rb +1 -0
- data/lib/ddtrace/sampling/rule.rb +2 -1
- data/lib/ddtrace/sampling/rule_sampler.rb +6 -10
- data/lib/ddtrace/sampling.rb +1 -0
- data/lib/ddtrace/span.rb +44 -19
- data/lib/ddtrace/sync_writer.rb +17 -15
- data/lib/ddtrace/tasks/exec.rb +47 -0
- data/lib/ddtrace/tasks/help.rb +15 -0
- data/lib/ddtrace/tracer.rb +48 -50
- data/lib/ddtrace/transport/http/adapters/net.rb +28 -8
- data/lib/ddtrace/transport/http/adapters/registry.rb +2 -0
- data/lib/ddtrace/transport/http/adapters/test.rb +1 -0
- data/lib/ddtrace/transport/http/adapters/unix_socket.rb +3 -4
- data/lib/ddtrace/transport/http/api/endpoint.rb +1 -0
- data/lib/ddtrace/transport/http/api/fallbacks.rb +1 -0
- data/lib/ddtrace/transport/http/api/instance.rb +1 -0
- data/lib/ddtrace/transport/http/api/map.rb +1 -0
- data/lib/ddtrace/transport/http/api/spec.rb +1 -0
- data/lib/ddtrace/transport/http/api.rb +1 -0
- data/lib/ddtrace/transport/http/builder.rb +8 -1
- data/lib/ddtrace/transport/http/client.rb +3 -1
- data/lib/ddtrace/transport/http/env.rb +9 -0
- data/lib/ddtrace/transport/http/response.rb +1 -0
- data/lib/ddtrace/transport/http/statistics.rb +3 -2
- data/lib/ddtrace/transport/http/traces.rb +6 -6
- data/lib/ddtrace/transport/http.rb +51 -38
- data/lib/ddtrace/transport/io/client.rb +17 -9
- data/lib/ddtrace/transport/io/response.rb +2 -3
- data/lib/ddtrace/transport/io/traces.rb +10 -1
- data/lib/ddtrace/transport/io.rb +2 -1
- data/lib/ddtrace/transport/parcel.rb +7 -0
- data/lib/ddtrace/transport/request.rb +1 -0
- data/lib/ddtrace/transport/response.rb +1 -0
- data/lib/ddtrace/transport/statistics.rb +1 -0
- data/lib/ddtrace/transport/traces.rb +21 -3
- data/lib/ddtrace/utils/compression.rb +28 -0
- data/lib/ddtrace/utils/database.rb +1 -0
- data/lib/ddtrace/utils/forking.rb +2 -1
- data/lib/ddtrace/utils/object_set.rb +40 -0
- data/lib/ddtrace/utils/only_once.rb +41 -0
- data/lib/ddtrace/utils/sequence.rb +18 -0
- data/lib/ddtrace/utils/string_table.rb +46 -0
- data/lib/ddtrace/utils/time.rb +34 -2
- data/lib/ddtrace/utils.rb +14 -2
- data/lib/ddtrace/vendor/active_record/MIT-LICENSE +20 -0
- data/lib/ddtrace/vendor/active_record/connection_specification.rb +1 -0
- data/lib/ddtrace/vendor/multipart-post/LICENSE +11 -0
- data/lib/ddtrace/vendor/multipart-post/multipart/post/composite_read_io.rb +117 -0
- data/lib/ddtrace/vendor/multipart-post/multipart/post/multipartable.rb +58 -0
- data/lib/ddtrace/vendor/multipart-post/multipart/post/parts.rb +136 -0
- data/lib/ddtrace/vendor/multipart-post/multipart/post/version.rb +10 -0
- data/lib/ddtrace/vendor/multipart-post/multipart/post.rb +9 -0
- data/lib/ddtrace/vendor/multipart-post/multipart.rb +13 -0
- data/lib/ddtrace/vendor/multipart-post/net/http/post/multipart.rb +33 -0
- data/lib/ddtrace/version.rb +15 -2
- data/lib/ddtrace/worker.rb +1 -0
- data/lib/ddtrace/workers/async.rb +15 -5
- data/lib/ddtrace/workers/loop.rb +32 -5
- data/lib/ddtrace/workers/polling.rb +13 -5
- data/lib/ddtrace/workers/queue.rb +3 -1
- data/lib/ddtrace/workers/runtime_metrics.rb +15 -1
- data/lib/ddtrace/workers/trace_writer.rb +14 -16
- data/lib/ddtrace/workers.rb +8 -2
- data/lib/ddtrace/writer.rb +14 -7
- data/lib/ddtrace.rb +20 -56
- metadata +130 -446
- data/.circleci/config.yml +0 -566
- data/.circleci/images/primary/Dockerfile-2.0.0 +0 -73
- data/.circleci/images/primary/Dockerfile-2.1.10 +0 -73
- data/.circleci/images/primary/Dockerfile-2.2.10 +0 -73
- data/.circleci/images/primary/Dockerfile-2.3.8 +0 -75
- data/.circleci/images/primary/Dockerfile-2.4.6 +0 -73
- data/.circleci/images/primary/Dockerfile-2.5.6 +0 -73
- data/.circleci/images/primary/Dockerfile-2.6.4 +0 -73
- data/.circleci/images/primary/Dockerfile-2.7.0 +0 -73
- data/.circleci/images/primary/Dockerfile-3.0.0 +0 -73
- data/.circleci/images/primary/Dockerfile-jruby-9.2 +0 -77
- data/.dockerignore +0 -1
- data/.env +0 -26
- data/.github/CODEOWNERS +0 -1
- data/.github/workflows/add-milestone-to-pull-requests.yml +0 -42
- data/.github/workflows/create-next-milestone.yml +0 -20
- data/.gitlab-ci.yml +0 -27
- data/.rspec +0 -1
- data/.rubocop.yml +0 -85
- data/.simplecov +0 -41
- data/Appraisals +0 -1350
- data/Gemfile +0 -9
- data/Rakefile +0 -993
- data/benchmarks/postgres_database.yml +0 -9
- data/benchmarks/sidekiq_test.rb +0 -154
- data/docker-compose.yml +0 -400
- data/lib/ddtrace/augmentation/method_wrapper.rb +0 -20
- data/lib/ddtrace/augmentation/method_wrapping.rb +0 -38
- data/lib/ddtrace/augmentation/shim.rb +0 -102
- data/lib/ddtrace/augmentation.rb +0 -13
- data/lib/ddtrace/contrib/cucumber/configuration/settings.rb +0 -38
- data/lib/ddtrace/contrib/cucumber/ext.rb +0 -19
- data/lib/ddtrace/contrib/cucumber/formatter.rb +0 -104
- data/lib/ddtrace/contrib/cucumber/instrumentation.rb +0 -24
- data/lib/ddtrace/contrib/cucumber/integration.rb +0 -45
- data/lib/ddtrace/contrib/rspec/configuration/settings.rb +0 -38
- data/lib/ddtrace/contrib/rspec/example.rb +0 -61
- data/lib/ddtrace/contrib/rspec/example_group.rb +0 -61
- data/lib/ddtrace/contrib/rspec/ext.rb +0 -19
- data/lib/ddtrace/contrib/rspec/integration.rb +0 -46
- data/lib/ddtrace/contrib/rspec/patcher.rb +0 -25
- data/lib/ddtrace/environment.rb +0 -41
- data/lib/ddtrace/ext/ci.rb +0 -297
- data/lib/ddtrace/monkey.rb +0 -58
- data/lib/ddtrace/runtime/cgroup.rb +0 -44
- data/lib/ddtrace/runtime/class_count.rb +0 -17
- data/lib/ddtrace/runtime/container.rb +0 -73
- data/lib/ddtrace/runtime/gc.rb +0 -16
- data/lib/ddtrace/runtime/identity.rb +0 -40
- data/lib/ddtrace/runtime/object_space.rb +0 -19
- data/lib/ddtrace/runtime/socket.rb +0 -14
- data/lib/ddtrace/runtime/thread_count.rb +0 -16
- data/tasks/release_gem.rake +0 -28
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
require 'ddtrace/profiling/backtrace_location'
|
|
3
|
+
require 'ddtrace/profiling/events/stack'
|
|
4
|
+
require 'ddtrace/utils/only_once'
|
|
5
|
+
require 'ddtrace/utils/time'
|
|
6
|
+
require 'ddtrace/worker'
|
|
7
|
+
require 'ddtrace/workers/polling'
|
|
8
|
+
|
|
9
|
+
module Datadog
|
|
10
|
+
module Profiling
|
|
11
|
+
module Collectors
|
|
12
|
+
# Collects stack trace samples from Ruby threads for both CPU-time (if available) and wall-clock.
|
|
13
|
+
# Runs on its own background thread.
|
|
14
|
+
#
|
|
15
|
+
class Stack < Worker # rubocop:disable Metrics/ClassLength
|
|
16
|
+
include Workers::Polling
|
|
17
|
+
|
|
18
|
+
DEFAULT_MAX_TIME_USAGE_PCT = 2.0
|
|
19
|
+
MIN_INTERVAL = 0.01
|
|
20
|
+
THREAD_LAST_CPU_TIME_KEY = :datadog_profiler_last_cpu_time
|
|
21
|
+
|
|
22
|
+
attr_reader \
|
|
23
|
+
:recorder,
|
|
24
|
+
:max_frames,
|
|
25
|
+
:trace_identifiers_helper,
|
|
26
|
+
:ignore_thread,
|
|
27
|
+
:max_time_usage_pct,
|
|
28
|
+
:thread_api
|
|
29
|
+
|
|
30
|
+
def initialize(
|
|
31
|
+
recorder,
|
|
32
|
+
max_frames:,
|
|
33
|
+
trace_identifiers_helper:, # Usually an instance of Datadog::Profiling::TraceIdentifiers::Helper
|
|
34
|
+
ignore_thread: nil,
|
|
35
|
+
max_time_usage_pct: DEFAULT_MAX_TIME_USAGE_PCT,
|
|
36
|
+
thread_api: Thread,
|
|
37
|
+
fork_policy: Workers::Async::Thread::FORK_POLICY_RESTART, # Restart in forks by default
|
|
38
|
+
interval: MIN_INTERVAL,
|
|
39
|
+
enabled: true
|
|
40
|
+
)
|
|
41
|
+
@recorder = recorder
|
|
42
|
+
@max_frames = max_frames
|
|
43
|
+
@trace_identifiers_helper = trace_identifiers_helper
|
|
44
|
+
@ignore_thread = ignore_thread
|
|
45
|
+
@max_time_usage_pct = max_time_usage_pct
|
|
46
|
+
@thread_api = thread_api
|
|
47
|
+
|
|
48
|
+
# Workers::Async::Thread settings
|
|
49
|
+
self.fork_policy = fork_policy
|
|
50
|
+
|
|
51
|
+
# Workers::IntervalLoop settings
|
|
52
|
+
self.loop_base_interval = interval
|
|
53
|
+
|
|
54
|
+
# Workers::Polling settings
|
|
55
|
+
self.enabled = enabled
|
|
56
|
+
|
|
57
|
+
@warn_about_missing_cpu_time_instrumentation_only_once = Datadog::Utils::OnlyOnce.new
|
|
58
|
+
|
|
59
|
+
# Cache this proc, since it's pretty expensive to keep recreating it
|
|
60
|
+
@build_backtrace_location = method(:build_backtrace_location).to_proc
|
|
61
|
+
# Cache this buffer, since it's pretty expensive to keep accessing it
|
|
62
|
+
@stack_sample_event_recorder = recorder[Events::StackSample]
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def start
|
|
66
|
+
@last_wall_time = Datadog::Utils::Time.get_time
|
|
67
|
+
reset_cpu_time_tracking
|
|
68
|
+
perform
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def perform
|
|
72
|
+
collect_and_wait
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def loop_back_off?
|
|
76
|
+
false
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def collect_and_wait
|
|
80
|
+
run_time = Datadog::Utils::Time.measure do
|
|
81
|
+
collect_events
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Update wait time to throttle profiling
|
|
85
|
+
self.loop_wait_time = compute_wait_time(run_time)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def collect_events
|
|
89
|
+
events = []
|
|
90
|
+
|
|
91
|
+
# Compute wall time interval
|
|
92
|
+
current_wall_time = Datadog::Utils::Time.get_time
|
|
93
|
+
last_wall_time = if instance_variable_defined?(:@last_wall_time)
|
|
94
|
+
@last_wall_time
|
|
95
|
+
else
|
|
96
|
+
current_wall_time
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
wall_time_interval_ns = ((current_wall_time - last_wall_time).round(9) * 1e9).to_i
|
|
100
|
+
@last_wall_time = current_wall_time
|
|
101
|
+
|
|
102
|
+
# Collect backtraces from each thread
|
|
103
|
+
thread_api.list.each do |thread|
|
|
104
|
+
next unless thread.alive?
|
|
105
|
+
next if ignore_thread.is_a?(Proc) && ignore_thread.call(thread)
|
|
106
|
+
|
|
107
|
+
event = collect_thread_event(thread, wall_time_interval_ns)
|
|
108
|
+
events << event unless event.nil?
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Send events to recorder
|
|
112
|
+
recorder.push(events) unless events.empty?
|
|
113
|
+
|
|
114
|
+
events
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def collect_thread_event(thread, wall_time_interval_ns)
|
|
118
|
+
locations = thread.backtrace_locations
|
|
119
|
+
return if locations.nil?
|
|
120
|
+
|
|
121
|
+
# Get actual stack size then trim the stack
|
|
122
|
+
stack_size = locations.length
|
|
123
|
+
locations = locations[0..(max_frames - 1)]
|
|
124
|
+
|
|
125
|
+
# Convert backtrace locations into structs
|
|
126
|
+
locations = convert_backtrace_locations(locations)
|
|
127
|
+
|
|
128
|
+
thread_id = thread.respond_to?(:pthread_thread_id) ? thread.pthread_thread_id : thread.object_id
|
|
129
|
+
trace_id, span_id, trace_resource_container = trace_identifiers_helper.trace_identifiers_for(thread)
|
|
130
|
+
cpu_time = get_cpu_time_interval!(thread)
|
|
131
|
+
|
|
132
|
+
Events::StackSample.new(
|
|
133
|
+
nil,
|
|
134
|
+
locations,
|
|
135
|
+
stack_size,
|
|
136
|
+
thread_id,
|
|
137
|
+
trace_id,
|
|
138
|
+
span_id,
|
|
139
|
+
trace_resource_container,
|
|
140
|
+
cpu_time,
|
|
141
|
+
wall_time_interval_ns
|
|
142
|
+
)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def get_cpu_time_interval!(thread)
|
|
146
|
+
# Return if we can't get the current CPU time
|
|
147
|
+
unless thread.respond_to?(:cpu_time_instrumentation_installed?) && thread.cpu_time_instrumentation_installed?
|
|
148
|
+
warn_about_missing_cpu_time_instrumentation(thread)
|
|
149
|
+
return
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
current_cpu_time_ns = thread.cpu_time(:nanosecond)
|
|
153
|
+
|
|
154
|
+
# NOTE: This can still be nil even when all of the checks above passed because of a race: there's a bit of
|
|
155
|
+
# initialization that needs to be done by the thread itself, and it's possible for us to try to sample
|
|
156
|
+
# *before* the thread had time to finish the initialization
|
|
157
|
+
return unless current_cpu_time_ns
|
|
158
|
+
|
|
159
|
+
last_cpu_time_ns = (thread.thread_variable_get(THREAD_LAST_CPU_TIME_KEY) || current_cpu_time_ns)
|
|
160
|
+
interval = current_cpu_time_ns - last_cpu_time_ns
|
|
161
|
+
|
|
162
|
+
# Update CPU time for thread
|
|
163
|
+
thread.thread_variable_set(THREAD_LAST_CPU_TIME_KEY, current_cpu_time_ns)
|
|
164
|
+
|
|
165
|
+
# Return interval
|
|
166
|
+
interval
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def compute_wait_time(used_time)
|
|
170
|
+
# We took used_time to get the last sample.
|
|
171
|
+
#
|
|
172
|
+
# What we're computing here is -- if used_time corresponds to max_time_usage_pct of the time we should
|
|
173
|
+
# spend working, how much is (100% - max_time_usage_pct) of the time?
|
|
174
|
+
#
|
|
175
|
+
# For instance, if we took 10ms to sample, and max_time_usage_pct is 1%, then the other 99% is 990ms, which
|
|
176
|
+
# means we need to sleep for 990ms to guarantee that we don't spend more than 1% of the time working.
|
|
177
|
+
used_time_ns = used_time * 1e9
|
|
178
|
+
interval = (used_time_ns / (max_time_usage_pct / 100.0)) - used_time_ns
|
|
179
|
+
[interval / 1e9, MIN_INTERVAL].max
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Convert backtrace locations into structs
|
|
183
|
+
# Re-use old backtrace location objects if they already exist in the buffer
|
|
184
|
+
def convert_backtrace_locations(locations)
|
|
185
|
+
locations.collect do |location|
|
|
186
|
+
# Re-use existing BacktraceLocation if identical copy, otherwise build a new one.
|
|
187
|
+
@stack_sample_event_recorder.cache(:backtrace_locations).fetch(
|
|
188
|
+
# Function name
|
|
189
|
+
location.base_label,
|
|
190
|
+
# Line number
|
|
191
|
+
location.lineno,
|
|
192
|
+
# Filename
|
|
193
|
+
location.path,
|
|
194
|
+
# Build function
|
|
195
|
+
&@build_backtrace_location
|
|
196
|
+
)
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def build_backtrace_location(_id, base_label, lineno, path)
|
|
201
|
+
string_table = @stack_sample_event_recorder.string_table
|
|
202
|
+
|
|
203
|
+
Profiling::BacktraceLocation.new(
|
|
204
|
+
string_table.fetch_string(base_label),
|
|
205
|
+
lineno,
|
|
206
|
+
string_table.fetch_string(path)
|
|
207
|
+
)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
private
|
|
211
|
+
|
|
212
|
+
def warn_about_missing_cpu_time_instrumentation(thread)
|
|
213
|
+
@warn_about_missing_cpu_time_instrumentation_only_once.run do
|
|
214
|
+
# Is the profiler thread instrumented? If it is, then we know instrumentation is available, but seems to be
|
|
215
|
+
# missing on this thread we just found.
|
|
216
|
+
#
|
|
217
|
+
# As far as we know, it can be missing due to one the following:
|
|
218
|
+
#
|
|
219
|
+
# a) The thread was started before we installed our instrumentation.
|
|
220
|
+
# In this case, the fix is to make sure ddtrace gets loaded before any other parts of the application.
|
|
221
|
+
#
|
|
222
|
+
# b) The thread was started using the Ruby native APIs (e.g. from a C extension such as ffi).
|
|
223
|
+
# Known cases right now that trigger this are the ethon/typhoeus gems.
|
|
224
|
+
# We currently have no solution for this case; these threads will always be missing our CPU instrumentation.
|
|
225
|
+
#
|
|
226
|
+
# c) The thread was started with `Thread.start`/`Thread.fork` and hasn't yet enabled the instrumentation.
|
|
227
|
+
# When threads are started using these APIs, there's a small time window during which the thread has started
|
|
228
|
+
# but our code to apply the instrumentation hasn't run yet; in these cases it's just a matter of allowing
|
|
229
|
+
# it to run and our instrumentation to be applied.
|
|
230
|
+
#
|
|
231
|
+
if thread_api.current.respond_to?(:cpu_time) && thread_api.current.cpu_time
|
|
232
|
+
Datadog.logger.debug(
|
|
233
|
+
"Thread ('#{thread}') is missing profiling instrumentation; other threads should be unaffected"
|
|
234
|
+
)
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# If the profiler is started for a while, stopped and then restarted OR whenever the process forks, we need to
|
|
240
|
+
# clean up any leftover per-thread cpu time counters, so that the first sample after starting doesn't end up with:
|
|
241
|
+
#
|
|
242
|
+
# a) negative time: At least on my test docker container, and on the reliability environment, after the process
|
|
243
|
+
# forks, the clock reference changes and (old cpu time - new cpu time) can be < 0
|
|
244
|
+
#
|
|
245
|
+
# b) large amount of time: if the profiler was started, then stopped for some amount of time, and then
|
|
246
|
+
# restarted, we don't want the first sample to be "blamed" for multiple minutes of CPU time
|
|
247
|
+
#
|
|
248
|
+
# By resetting the last cpu time seen, we start with a clean slate every time we start the stack collector.
|
|
249
|
+
def reset_cpu_time_tracking
|
|
250
|
+
thread_api.list.each do |thread|
|
|
251
|
+
thread.thread_variable_set(THREAD_LAST_CPU_TIME_KEY, nil)
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
require 'set'
|
|
3
|
+
require 'time'
|
|
4
|
+
|
|
5
|
+
require 'ddtrace/profiling/flush'
|
|
6
|
+
require 'ddtrace/profiling/pprof/template'
|
|
7
|
+
|
|
8
|
+
module Datadog
|
|
9
|
+
module Profiling
|
|
10
|
+
module Encoding
|
|
11
|
+
module Profile
|
|
12
|
+
# Encodes gathered data into the pprof format
|
|
13
|
+
module Protobuf
|
|
14
|
+
module_function
|
|
15
|
+
|
|
16
|
+
def encode(flush)
|
|
17
|
+
return unless flush
|
|
18
|
+
|
|
19
|
+
# Create a pprof template from the list of event types
|
|
20
|
+
event_classes = flush.event_groups.collect(&:event_class).uniq
|
|
21
|
+
template = Pprof::Template.for_event_classes(event_classes)
|
|
22
|
+
|
|
23
|
+
# Add all events to the pprof
|
|
24
|
+
flush.event_groups.each { |event_group| template.add_events!(event_group.event_class, event_group.events) }
|
|
25
|
+
|
|
26
|
+
Datadog.logger.debug do
|
|
27
|
+
"Encoding profile covering #{flush.start.iso8601} to #{flush.finish.iso8601}, " \
|
|
28
|
+
"events: #{flush.event_count} (#{template.debug_statistics})"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Build the profile and encode it
|
|
32
|
+
template.to_pprof
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
module Datadog
|
|
3
|
+
module Profiling
|
|
4
|
+
# Describes a sample of some data obtained from the runtime.
|
|
5
|
+
class Event
|
|
6
|
+
attr_reader \
|
|
7
|
+
:timestamp
|
|
8
|
+
|
|
9
|
+
def initialize(timestamp = nil)
|
|
10
|
+
@timestamp = timestamp || Time.now.utc.to_f
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
require 'ddtrace/profiling/event'
|
|
3
|
+
|
|
4
|
+
module Datadog
|
|
5
|
+
module Profiling
|
|
6
|
+
module Events
|
|
7
|
+
# Describes a stack profiling event
|
|
8
|
+
class Stack < Event
|
|
9
|
+
attr_reader \
|
|
10
|
+
:hash,
|
|
11
|
+
:frames,
|
|
12
|
+
:total_frame_count,
|
|
13
|
+
:thread_id,
|
|
14
|
+
:trace_id,
|
|
15
|
+
:span_id,
|
|
16
|
+
:trace_resource_container
|
|
17
|
+
|
|
18
|
+
def initialize(
|
|
19
|
+
timestamp,
|
|
20
|
+
frames,
|
|
21
|
+
total_frame_count,
|
|
22
|
+
thread_id,
|
|
23
|
+
trace_id,
|
|
24
|
+
span_id,
|
|
25
|
+
trace_resource_container
|
|
26
|
+
)
|
|
27
|
+
super(timestamp)
|
|
28
|
+
|
|
29
|
+
@frames = frames
|
|
30
|
+
@total_frame_count = total_frame_count
|
|
31
|
+
@thread_id = thread_id
|
|
32
|
+
@trace_id = trace_id
|
|
33
|
+
@span_id = span_id
|
|
34
|
+
@trace_resource_container = trace_resource_container
|
|
35
|
+
|
|
36
|
+
@hash = [
|
|
37
|
+
thread_id,
|
|
38
|
+
trace_id,
|
|
39
|
+
span_id,
|
|
40
|
+
# trace_resource_container is deliberately not included -- events that share the same (trace_id, span_id)
|
|
41
|
+
# pair should also have the same trace_resource_container
|
|
42
|
+
frames.collect(&:hash),
|
|
43
|
+
total_frame_count
|
|
44
|
+
].hash
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Describes a stack sample
|
|
49
|
+
class StackSample < Stack
|
|
50
|
+
attr_reader \
|
|
51
|
+
:cpu_time_interval_ns,
|
|
52
|
+
:wall_time_interval_ns
|
|
53
|
+
|
|
54
|
+
def initialize(
|
|
55
|
+
timestamp,
|
|
56
|
+
frames,
|
|
57
|
+
total_frame_count,
|
|
58
|
+
thread_id,
|
|
59
|
+
trace_id,
|
|
60
|
+
span_id,
|
|
61
|
+
trace_resource_container,
|
|
62
|
+
cpu_time_interval_ns,
|
|
63
|
+
wall_time_interval_ns
|
|
64
|
+
)
|
|
65
|
+
super(
|
|
66
|
+
timestamp,
|
|
67
|
+
frames,
|
|
68
|
+
total_frame_count,
|
|
69
|
+
thread_id,
|
|
70
|
+
trace_id,
|
|
71
|
+
span_id,
|
|
72
|
+
trace_resource_container
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
@cpu_time_interval_ns = cpu_time_interval_ns
|
|
76
|
+
@wall_time_interval_ns = wall_time_interval_ns
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
require 'ddtrace/profiling/transport/io/client'
|
|
3
|
+
|
|
4
|
+
module Datadog
|
|
5
|
+
module Profiling
|
|
6
|
+
# Writes profiling data to a given transport
|
|
7
|
+
class Exporter
|
|
8
|
+
attr_reader \
|
|
9
|
+
:transport
|
|
10
|
+
|
|
11
|
+
def initialize(transport)
|
|
12
|
+
unless transport.is_a?(Profiling::Transport::Client)
|
|
13
|
+
raise ArgumentError, 'Unsupported transport for profiling exporter.'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
@transport = transport
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def export(flush)
|
|
20
|
+
transport.send_profiling_flush(flush)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
module Datadog
|
|
3
|
+
module Profiling
|
|
4
|
+
module Ext
|
|
5
|
+
# Monkey patches Ruby's `Thread` with our `Ext::CThread` to enable CPU-time profiling
|
|
6
|
+
module CPU
|
|
7
|
+
# We cannot apply our CPU extension if a broken rollbar is around because that can cause customer apps to fail
|
|
8
|
+
# with a SystemStackError: stack level too deep.
|
|
9
|
+
#
|
|
10
|
+
# This occurs whenever our extensions to Thread are applied BEFORE rollbar applies its own. This happens
|
|
11
|
+
# because a loop forms: our extension tries to call Thread#initialize, but it's intercepted by rollbar, which
|
|
12
|
+
# then tries to call the original Thread#initialize as well, but instead alls our extension, leading to stack
|
|
13
|
+
# exhaustion.
|
|
14
|
+
#
|
|
15
|
+
# See https://github.com/rollbar/rollbar-gem/pull/1018 for more details on the issue
|
|
16
|
+
ROLLBAR_INCOMPATIBLE_VERSIONS = Gem::Requirement.new('<= 3.1.1')
|
|
17
|
+
|
|
18
|
+
def self.supported?
|
|
19
|
+
unsupported_reason.nil?
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.apply!
|
|
23
|
+
return false unless supported?
|
|
24
|
+
|
|
25
|
+
# Applying CThread to Thread will ensure any new threads
|
|
26
|
+
# will provide a thread/clock ID for CPU timing.
|
|
27
|
+
require 'ddtrace/profiling/ext/cthread'
|
|
28
|
+
::Thread.prepend(Profiling::Ext::CThread)
|
|
29
|
+
::Thread.singleton_class.prepend(Datadog::Profiling::Ext::WrapThreadStartFork)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.unsupported_reason
|
|
33
|
+
# NOTE: Only the first matching reason is returned, so try to keep a nice order on reasons -- e.g. tell users
|
|
34
|
+
# first that they can't use this on macOS before telling them that they have the wrong ffi version
|
|
35
|
+
|
|
36
|
+
if RUBY_ENGINE == 'jruby'
|
|
37
|
+
'JRuby is not supported'
|
|
38
|
+
elsif RUBY_PLATFORM.include?('darwin')
|
|
39
|
+
'Feature requires Linux; macOS is not supported'
|
|
40
|
+
elsif RUBY_PLATFORM =~ /(mswin|mingw)/
|
|
41
|
+
'Feature requires Linux; Windows is not supported'
|
|
42
|
+
elsif !RUBY_PLATFORM.include?('linux')
|
|
43
|
+
"Feature requires Linux; #{RUBY_PLATFORM} is not supported"
|
|
44
|
+
elsif Gem::Specification.find_all_by_name('rollbar', ROLLBAR_INCOMPATIBLE_VERSIONS).any?
|
|
45
|
+
'You have an incompatible rollbar gem version installed; ensure that you have rollbar >= 3.1.2 by ' \
|
|
46
|
+
"adding `gem 'rollbar', '>= 3.1.2'` to your Gemfile or gems.rb file. " \
|
|
47
|
+
'See https://github.com/rollbar/rollbar-gem/pull/1018 for details'
|
|
48
|
+
elsif Gem::Specification.find_all_by_name('logging').any? && logging_inherit_context_enabled?
|
|
49
|
+
'The `logging` gem is installed and its thread inherit context feature is enabled. ' \
|
|
50
|
+
"Please add LOGGING_INHERIT_CONTEXT=false to your application's environment variables to disable the " \
|
|
51
|
+
'conflicting `logging` gem feature. ' \
|
|
52
|
+
'See https://github.com/TwP/logging/pull/230 for details'
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private_class_method def self.logging_inherit_context_enabled?
|
|
57
|
+
# The logging gem provides a mechanism to disable the conflicting behavior, see
|
|
58
|
+
# https://github.com/TwP/logging/blob/ae9872d093833b2a5a34cbe1faa4e895a81f6845/lib/logging/diagnostic_context.rb#L418
|
|
59
|
+
# Here we check if the behavior is enabled
|
|
60
|
+
inherit_context_configuration = ENV['LOGGING_INHERIT_CONTEXT']
|
|
61
|
+
|
|
62
|
+
inherit_context_configuration.nil? || !%w[false no 0].include?(inherit_context_configuration.downcase)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# typed: false
|
|
2
|
+
require 'ffi'
|
|
3
|
+
|
|
4
|
+
module Datadog
|
|
5
|
+
module Profiling
|
|
6
|
+
module Ext
|
|
7
|
+
# C-struct for retrieving clock ID from pthread
|
|
8
|
+
class CClockId < FFI::Struct
|
|
9
|
+
layout :value, :int
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Enables interfacing with pthread via FFI
|
|
13
|
+
module NativePthread
|
|
14
|
+
extend FFI::Library
|
|
15
|
+
ffi_lib ['pthread', 'libpthread.so.0']
|
|
16
|
+
attach_function :pthread_self, [], :ulong
|
|
17
|
+
attach_function :pthread_getcpuclockid, [:ulong, CClockId], :int
|
|
18
|
+
|
|
19
|
+
# NOTE: Only returns thread ID for thread that evaluates this call.
|
|
20
|
+
# a.k.a. evaluating `get_pthread_thread_id(thread_a)` from within
|
|
21
|
+
# `thread_b` will return `thread_b`'s thread ID, not `thread_a`'s.
|
|
22
|
+
def self.get_pthread_thread_id(thread)
|
|
23
|
+
return unless ::Thread.current == thread
|
|
24
|
+
|
|
25
|
+
pthread_self
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.get_clock_id(thread, pthread_id)
|
|
29
|
+
return unless ::Thread.current == thread && pthread_id
|
|
30
|
+
|
|
31
|
+
clock = CClockId.new
|
|
32
|
+
clock[:value] = 0
|
|
33
|
+
pthread_getcpuclockid(pthread_id, clock).zero? ? clock[:value] : nil
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Extension used to enable CPU-time profiling via use of pthread's `getcpuclockid`.
|
|
38
|
+
module CThread
|
|
39
|
+
def self.prepended(base)
|
|
40
|
+
# Threads that have already been created, will not have resolved
|
|
41
|
+
# a thread/clock ID. This is because these IDs can only be resolved
|
|
42
|
+
# from within the thread's execution context, which we do not control.
|
|
43
|
+
#
|
|
44
|
+
# We can mitigate this for the current thread via #update_native_ids,
|
|
45
|
+
# since we are currently running within its execution context. We cannot
|
|
46
|
+
# do this for any other threads that may have been created already.
|
|
47
|
+
# (This is why it's important that CThread is applied before anything else runs.)
|
|
48
|
+
base.current.send(:update_native_ids) if base.current.is_a?(CThread)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Process::Waiter crash workaround:
|
|
52
|
+
#
|
|
53
|
+
# This is a workaround for a Ruby VM segfault (usually something like
|
|
54
|
+
# "[BUG] Segmentation fault at 0x0000000000000008") in the affected Ruby versions.
|
|
55
|
+
# See https://bugs.ruby-lang.org/issues/17807 and the regression tests added to this module's specs for details.
|
|
56
|
+
#
|
|
57
|
+
# In those Ruby versions, there's a very special subclass of `Thread` called `Process::Waiter` that causes VM
|
|
58
|
+
# crashes whenever something tries to read its instance variables. This subclass of thread only shows up when
|
|
59
|
+
# the `Process.detach` API gets used.
|
|
60
|
+
# In this module's specs you can find crash regression tests that include a way of reproducing it.
|
|
61
|
+
#
|
|
62
|
+
# The workaround is to use `defined?` to check first if the instance variable exists. This seems to be fine
|
|
63
|
+
# with Ruby.
|
|
64
|
+
# Note that this crash doesn't affect `@foo ||=` nor instance variable writes (after the first write ever of any
|
|
65
|
+
# instance variable on a `Process::Waiter`, then further reads and writes to that or any other instance are OK;
|
|
66
|
+
# it looks like there's some lazily-created structure that is missing and did not get created).
|
|
67
|
+
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.3') &&
|
|
68
|
+
Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.7')
|
|
69
|
+
attr_reader :pthread_thread_id
|
|
70
|
+
else
|
|
71
|
+
def pthread_thread_id
|
|
72
|
+
defined?(@pthread_thread_id) && @pthread_thread_id
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def initialize(*args)
|
|
77
|
+
@pid = ::Process.pid
|
|
78
|
+
@pthread_thread_id = nil
|
|
79
|
+
@clock_id = nil
|
|
80
|
+
|
|
81
|
+
# Wrap the work block with our own
|
|
82
|
+
# so we can retrieve the native thread ID within the thread's context.
|
|
83
|
+
wrapped_block = proc do |*t_args|
|
|
84
|
+
# Set native thread ID & clock ID
|
|
85
|
+
update_native_ids
|
|
86
|
+
yield(*t_args)
|
|
87
|
+
end
|
|
88
|
+
wrapped_block.ruby2_keywords if wrapped_block.respond_to?(:ruby2_keywords, true)
|
|
89
|
+
|
|
90
|
+
super(*args, &wrapped_block)
|
|
91
|
+
end
|
|
92
|
+
ruby2_keywords :initialize if respond_to?(:ruby2_keywords, true)
|
|
93
|
+
|
|
94
|
+
def cpu_time(unit = :float_second)
|
|
95
|
+
::Process.clock_gettime(clock_id, unit) if clock_id
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def cpu_time_instrumentation_installed?
|
|
99
|
+
# If this thread was started before this module was added to Thread OR if something caused the initialize
|
|
100
|
+
# method above not to be properly called on new threads, this instance variable is never defined (never set to
|
|
101
|
+
# any value at all, including nil).
|
|
102
|
+
#
|
|
103
|
+
# Thus, we can use @clock_id as a canary to detect a thread that has missing instrumentation, because we
|
|
104
|
+
# know that in initialize above we always set this variable to nil.
|
|
105
|
+
defined?(@clock_id) != nil
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
private
|
|
109
|
+
|
|
110
|
+
def clock_id
|
|
111
|
+
update_native_ids if forked?
|
|
112
|
+
defined?(@clock_id) && @clock_id
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def forked?
|
|
116
|
+
::Process.pid != (@pid ||= nil)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def update_native_ids
|
|
120
|
+
# Can only resolve if invoked from same thread
|
|
121
|
+
return unless ::Thread.current == self
|
|
122
|
+
|
|
123
|
+
@pid = ::Process.pid
|
|
124
|
+
@pthread_thread_id = NativePthread.get_pthread_thread_id(self)
|
|
125
|
+
@clock_id = NativePthread.get_clock_id(self, @pthread_thread_id)
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Threads in Ruby can be started by creating a new instance of `Thread` (or a subclass) OR by calling
|
|
130
|
+
# `start`/`fork` on `Thread` (or a subclass).
|
|
131
|
+
#
|
|
132
|
+
# This module intercepts calls to `start`/`fork`, ensuring that the `update_native_ids` operation is correctly
|
|
133
|
+
# called once the new thread starts.
|
|
134
|
+
#
|
|
135
|
+
# Note that unlike CThread above, this module should be prepended to the `Thread`'s singleton class, not to
|
|
136
|
+
# the class.
|
|
137
|
+
module WrapThreadStartFork
|
|
138
|
+
def start(*args)
|
|
139
|
+
# Wrap the work block with our own
|
|
140
|
+
# so we can retrieve the native thread ID within the thread's context.
|
|
141
|
+
wrapped_block = proc do |*t_args|
|
|
142
|
+
# Set native thread ID & clock ID
|
|
143
|
+
::Thread.current.send(:update_native_ids)
|
|
144
|
+
yield(*t_args)
|
|
145
|
+
end
|
|
146
|
+
wrapped_block.ruby2_keywords if wrapped_block.respond_to?(:ruby2_keywords, true)
|
|
147
|
+
|
|
148
|
+
super(*args, &wrapped_block)
|
|
149
|
+
end
|
|
150
|
+
ruby2_keywords :start if respond_to?(:ruby2_keywords, true)
|
|
151
|
+
|
|
152
|
+
alias fork start
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|