ls-trace 0.1.1
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 +7 -0
- data/.circleci/config.yml +673 -0
- data/.circleci/images/primary/Dockerfile-2.0.0 +73 -0
- data/.circleci/images/primary/Dockerfile-2.1.10 +73 -0
- data/.circleci/images/primary/Dockerfile-2.2.10 +73 -0
- data/.circleci/images/primary/Dockerfile-2.3.8 +75 -0
- data/.circleci/images/primary/Dockerfile-2.4.6 +73 -0
- data/.circleci/images/primary/Dockerfile-2.5.6 +73 -0
- data/.circleci/images/primary/Dockerfile-2.6.4 +73 -0
- data/.dockerignore +1 -0
- data/.env +24 -0
- data/.github/CODEOWNERS +1 -0
- data/.gitignore +59 -0
- data/.rspec +1 -0
- data/.rubocop.yml +77 -0
- data/.yardopts +5 -0
- data/Appraisals +820 -0
- data/CHANGELOG.md +1051 -0
- data/CONTRIBUTING.md +85 -0
- data/Gemfile +7 -0
- data/LICENSE +24 -0
- data/README.md +108 -0
- data/Rakefile +635 -0
- data/benchmarks/postgres_database.yml +9 -0
- data/benchmarks/sidekiq_test.rb +154 -0
- data/ddtrace.gemspec +63 -0
- data/docker-compose.yml +276 -0
- data/docs/DevelopmentGuide.md +195 -0
- data/docs/GettingStarted.md +1981 -0
- data/lib/ddtrace.rb +63 -0
- data/lib/ddtrace/analytics.rb +29 -0
- data/lib/ddtrace/augmentation.rb +13 -0
- data/lib/ddtrace/augmentation/method_wrapper.rb +20 -0
- data/lib/ddtrace/augmentation/method_wrapping.rb +38 -0
- data/lib/ddtrace/augmentation/shim.rb +102 -0
- data/lib/ddtrace/buffer.rb +119 -0
- data/lib/ddtrace/configuration.rb +30 -0
- data/lib/ddtrace/configuration/base.rb +82 -0
- data/lib/ddtrace/configuration/dependency_resolver.rb +24 -0
- data/lib/ddtrace/configuration/option.rb +55 -0
- data/lib/ddtrace/configuration/option_definition.rb +127 -0
- data/lib/ddtrace/configuration/option_definition_set.rb +18 -0
- data/lib/ddtrace/configuration/option_set.rb +6 -0
- data/lib/ddtrace/configuration/options.rb +107 -0
- data/lib/ddtrace/configuration/pin_setup.rb +30 -0
- data/lib/ddtrace/configuration/settings.rb +105 -0
- data/lib/ddtrace/context.rb +284 -0
- data/lib/ddtrace/context_flush.rb +132 -0
- data/lib/ddtrace/contrib/action_pack/action_controller/instrumentation.rb +144 -0
- data/lib/ddtrace/contrib/action_pack/action_controller/patcher.rb +37 -0
- data/lib/ddtrace/contrib/action_pack/configuration/settings.rb +27 -0
- data/lib/ddtrace/contrib/action_pack/ext.rb +16 -0
- data/lib/ddtrace/contrib/action_pack/integration.rb +36 -0
- data/lib/ddtrace/contrib/action_pack/patcher.rb +29 -0
- data/lib/ddtrace/contrib/action_pack/utils.rb +36 -0
- data/lib/ddtrace/contrib/action_view/configuration/settings.rb +26 -0
- data/lib/ddtrace/contrib/action_view/ext.rb +17 -0
- data/lib/ddtrace/contrib/action_view/instrumentation/partial_renderer.rb +78 -0
- data/lib/ddtrace/contrib/action_view/instrumentation/template_renderer.rb +167 -0
- data/lib/ddtrace/contrib/action_view/integration.rb +43 -0
- data/lib/ddtrace/contrib/action_view/patcher.rb +53 -0
- data/lib/ddtrace/contrib/action_view/utils.rb +32 -0
- data/lib/ddtrace/contrib/active_model_serializers/configuration/settings.rb +25 -0
- data/lib/ddtrace/contrib/active_model_serializers/event.rb +65 -0
- data/lib/ddtrace/contrib/active_model_serializers/events.rb +30 -0
- data/lib/ddtrace/contrib/active_model_serializers/events/render.rb +32 -0
- data/lib/ddtrace/contrib/active_model_serializers/events/serialize.rb +35 -0
- data/lib/ddtrace/contrib/active_model_serializers/ext.rb +17 -0
- data/lib/ddtrace/contrib/active_model_serializers/integration.rb +39 -0
- data/lib/ddtrace/contrib/active_model_serializers/patcher.rb +36 -0
- data/lib/ddtrace/contrib/active_record/configuration/resolver.rb +46 -0
- data/lib/ddtrace/contrib/active_record/configuration/settings.rb +30 -0
- data/lib/ddtrace/contrib/active_record/event.rb +30 -0
- data/lib/ddtrace/contrib/active_record/events.rb +30 -0
- data/lib/ddtrace/contrib/active_record/events/instantiation.rb +57 -0
- data/lib/ddtrace/contrib/active_record/events/sql.rb +64 -0
- data/lib/ddtrace/contrib/active_record/ext.rb +21 -0
- data/lib/ddtrace/contrib/active_record/integration.rb +44 -0
- data/lib/ddtrace/contrib/active_record/patcher.rb +29 -0
- data/lib/ddtrace/contrib/active_record/utils.rb +76 -0
- data/lib/ddtrace/contrib/active_support/cache/instrumentation.rb +157 -0
- data/lib/ddtrace/contrib/active_support/cache/patcher.rb +62 -0
- data/lib/ddtrace/contrib/active_support/cache/redis.rb +47 -0
- data/lib/ddtrace/contrib/active_support/configuration/settings.rb +25 -0
- data/lib/ddtrace/contrib/active_support/ext.rb +21 -0
- data/lib/ddtrace/contrib/active_support/integration.rb +38 -0
- data/lib/ddtrace/contrib/active_support/notifications/event.rb +62 -0
- data/lib/ddtrace/contrib/active_support/notifications/subscriber.rb +66 -0
- data/lib/ddtrace/contrib/active_support/notifications/subscription.rb +159 -0
- data/lib/ddtrace/contrib/active_support/patcher.rb +29 -0
- data/lib/ddtrace/contrib/analytics.rb +20 -0
- data/lib/ddtrace/contrib/aws/configuration/settings.rb +25 -0
- data/lib/ddtrace/contrib/aws/ext.rb +20 -0
- data/lib/ddtrace/contrib/aws/instrumentation.rb +56 -0
- data/lib/ddtrace/contrib/aws/integration.rb +36 -0
- data/lib/ddtrace/contrib/aws/parsed_context.rb +56 -0
- data/lib/ddtrace/contrib/aws/patcher.rb +49 -0
- data/lib/ddtrace/contrib/aws/services.rb +115 -0
- data/lib/ddtrace/contrib/concurrent_ruby/configuration/settings.rb +15 -0
- data/lib/ddtrace/contrib/concurrent_ruby/context_composite_executor_service.rb +35 -0
- data/lib/ddtrace/contrib/concurrent_ruby/ext.rb +11 -0
- data/lib/ddtrace/contrib/concurrent_ruby/future_patch.rb +23 -0
- data/lib/ddtrace/contrib/concurrent_ruby/integration.rb +32 -0
- data/lib/ddtrace/contrib/concurrent_ruby/patcher.rb +35 -0
- data/lib/ddtrace/contrib/configurable.rb +59 -0
- data/lib/ddtrace/contrib/configuration/resolver.rb +12 -0
- data/lib/ddtrace/contrib/configuration/settings.rb +35 -0
- data/lib/ddtrace/contrib/dalli/configuration/settings.rb +25 -0
- data/lib/ddtrace/contrib/dalli/ext.rb +17 -0
- data/lib/ddtrace/contrib/dalli/instrumentation.rb +50 -0
- data/lib/ddtrace/contrib/dalli/integration.rb +36 -0
- data/lib/ddtrace/contrib/dalli/patcher.rb +73 -0
- data/lib/ddtrace/contrib/dalli/quantize.rb +22 -0
- data/lib/ddtrace/contrib/delayed_job/configuration/settings.rb +25 -0
- data/lib/ddtrace/contrib/delayed_job/ext.rb +18 -0
- data/lib/ddtrace/contrib/delayed_job/integration.rb +32 -0
- data/lib/ddtrace/contrib/delayed_job/patcher.rb +34 -0
- data/lib/ddtrace/contrib/delayed_job/plugin.rb +57 -0
- data/lib/ddtrace/contrib/elasticsearch/configuration/settings.rb +26 -0
- data/lib/ddtrace/contrib/elasticsearch/ext.rb +19 -0
- data/lib/ddtrace/contrib/elasticsearch/integration.rb +37 -0
- data/lib/ddtrace/contrib/elasticsearch/patcher.rb +124 -0
- data/lib/ddtrace/contrib/elasticsearch/quantize.rb +80 -0
- data/lib/ddtrace/contrib/ethon/configuration/settings.rb +26 -0
- data/lib/ddtrace/contrib/ethon/easy_patch.rb +139 -0
- data/lib/ddtrace/contrib/ethon/ext.rb +15 -0
- data/lib/ddtrace/contrib/ethon/integration.rb +31 -0
- data/lib/ddtrace/contrib/ethon/multi_patch.rb +80 -0
- data/lib/ddtrace/contrib/ethon/patcher.rb +27 -0
- data/lib/ddtrace/contrib/excon/configuration/settings.rb +28 -0
- data/lib/ddtrace/contrib/excon/ext.rb +14 -0
- data/lib/ddtrace/contrib/excon/integration.rb +32 -0
- data/lib/ddtrace/contrib/excon/middleware.rb +154 -0
- data/lib/ddtrace/contrib/excon/patcher.rb +34 -0
- data/lib/ddtrace/contrib/extensions.rb +59 -0
- data/lib/ddtrace/contrib/faraday/configuration/settings.rb +33 -0
- data/lib/ddtrace/contrib/faraday/ext.rb +14 -0
- data/lib/ddtrace/contrib/faraday/integration.rb +36 -0
- data/lib/ddtrace/contrib/faraday/middleware.rb +93 -0
- data/lib/ddtrace/contrib/faraday/patcher.rb +82 -0
- data/lib/ddtrace/contrib/faraday/rack_builder.rb +18 -0
- data/lib/ddtrace/contrib/grape/configuration/settings.rb +27 -0
- data/lib/ddtrace/contrib/grape/endpoint.rb +199 -0
- data/lib/ddtrace/contrib/grape/ext.rb +19 -0
- data/lib/ddtrace/contrib/grape/instrumentation.rb +33 -0
- data/lib/ddtrace/contrib/grape/integration.rb +36 -0
- data/lib/ddtrace/contrib/grape/patcher.rb +79 -0
- data/lib/ddtrace/contrib/graphql/configuration/settings.rb +27 -0
- data/lib/ddtrace/contrib/graphql/ext.rb +13 -0
- data/lib/ddtrace/contrib/graphql/integration.rb +38 -0
- data/lib/ddtrace/contrib/graphql/patcher.rb +63 -0
- data/lib/ddtrace/contrib/grpc/configuration/settings.rb +25 -0
- data/lib/ddtrace/contrib/grpc/datadog_interceptor.rb +74 -0
- data/lib/ddtrace/contrib/grpc/datadog_interceptor/client.rb +56 -0
- data/lib/ddtrace/contrib/grpc/datadog_interceptor/server.rb +73 -0
- data/lib/ddtrace/contrib/grpc/ext.rb +15 -0
- data/lib/ddtrace/contrib/grpc/integration.rb +36 -0
- data/lib/ddtrace/contrib/grpc/intercept_with_datadog.rb +49 -0
- data/lib/ddtrace/contrib/grpc/patcher.rb +78 -0
- data/lib/ddtrace/contrib/http/circuit_breaker.rb +63 -0
- data/lib/ddtrace/contrib/http/configuration/settings.rb +26 -0
- data/lib/ddtrace/contrib/http/ext.rb +14 -0
- data/lib/ddtrace/contrib/http/instrumentation.rb +114 -0
- data/lib/ddtrace/contrib/http/integration.rb +32 -0
- data/lib/ddtrace/contrib/http/patcher.rb +32 -0
- data/lib/ddtrace/contrib/integration.rb +16 -0
- data/lib/ddtrace/contrib/mongodb/configuration/settings.rb +28 -0
- data/lib/ddtrace/contrib/mongodb/ext.rb +20 -0
- data/lib/ddtrace/contrib/mongodb/instrumentation.rb +68 -0
- data/lib/ddtrace/contrib/mongodb/integration.rb +36 -0
- data/lib/ddtrace/contrib/mongodb/parsers.rb +68 -0
- data/lib/ddtrace/contrib/mongodb/patcher.rb +37 -0
- data/lib/ddtrace/contrib/mongodb/subscribers.rb +108 -0
- data/lib/ddtrace/contrib/mysql2/configuration/settings.rb +25 -0
- data/lib/ddtrace/contrib/mysql2/ext.rb +15 -0
- data/lib/ddtrace/contrib/mysql2/instrumentation.rb +60 -0
- data/lib/ddtrace/contrib/mysql2/integration.rb +32 -0
- data/lib/ddtrace/contrib/mysql2/patcher.rb +33 -0
- data/lib/ddtrace/contrib/patchable.rb +42 -0
- data/lib/ddtrace/contrib/patcher.rb +28 -0
- data/lib/ddtrace/contrib/racecar/configuration/settings.rb +25 -0
- data/lib/ddtrace/contrib/racecar/event.rb +67 -0
- data/lib/ddtrace/contrib/racecar/events.rb +30 -0
- data/lib/ddtrace/contrib/racecar/events/batch.rb +27 -0
- data/lib/ddtrace/contrib/racecar/events/message.rb +27 -0
- data/lib/ddtrace/contrib/racecar/ext.rb +21 -0
- data/lib/ddtrace/contrib/racecar/integration.rb +36 -0
- data/lib/ddtrace/contrib/racecar/patcher.rb +32 -0
- data/lib/ddtrace/contrib/rack/configuration/settings.rb +41 -0
- data/lib/ddtrace/contrib/rack/ext.rb +18 -0
- data/lib/ddtrace/contrib/rack/integration.rb +32 -0
- data/lib/ddtrace/contrib/rack/middlewares.rb +283 -0
- data/lib/ddtrace/contrib/rack/patcher.rb +72 -0
- data/lib/ddtrace/contrib/rack/request_queue.rb +39 -0
- data/lib/ddtrace/contrib/rails/configuration/settings.rb +80 -0
- data/lib/ddtrace/contrib/rails/ext.rb +12 -0
- data/lib/ddtrace/contrib/rails/framework.rb +100 -0
- data/lib/ddtrace/contrib/rails/integration.rb +37 -0
- data/lib/ddtrace/contrib/rails/middlewares.rb +38 -0
- data/lib/ddtrace/contrib/rails/patcher.rb +78 -0
- data/lib/ddtrace/contrib/rails/railtie.rb +17 -0
- data/lib/ddtrace/contrib/rails/utils.rb +20 -0
- data/lib/ddtrace/contrib/rake/configuration/settings.rb +27 -0
- data/lib/ddtrace/contrib/rake/ext.rb +18 -0
- data/lib/ddtrace/contrib/rake/instrumentation.rb +84 -0
- data/lib/ddtrace/contrib/rake/integration.rb +32 -0
- data/lib/ddtrace/contrib/rake/patcher.rb +36 -0
- data/lib/ddtrace/contrib/redis/configuration/settings.rb +25 -0
- data/lib/ddtrace/contrib/redis/ext.rb +18 -0
- data/lib/ddtrace/contrib/redis/integration.rb +36 -0
- data/lib/ddtrace/contrib/redis/patcher.rb +94 -0
- data/lib/ddtrace/contrib/redis/quantize.rb +47 -0
- data/lib/ddtrace/contrib/redis/tags.rb +38 -0
- data/lib/ddtrace/contrib/registerable.rb +33 -0
- data/lib/ddtrace/contrib/registry.rb +42 -0
- data/lib/ddtrace/contrib/resque/configuration/settings.rb +26 -0
- data/lib/ddtrace/contrib/resque/ext.rb +14 -0
- data/lib/ddtrace/contrib/resque/integration.rb +37 -0
- data/lib/ddtrace/contrib/resque/patcher.rb +35 -0
- data/lib/ddtrace/contrib/resque/resque_job.rb +76 -0
- data/lib/ddtrace/contrib/rest_client/configuration/settings.rb +26 -0
- data/lib/ddtrace/contrib/rest_client/ext.rb +14 -0
- data/lib/ddtrace/contrib/rest_client/integration.rb +31 -0
- data/lib/ddtrace/contrib/rest_client/patcher.rb +25 -0
- data/lib/ddtrace/contrib/rest_client/request_patch.rb +89 -0
- data/lib/ddtrace/contrib/sequel/configuration/settings.rb +23 -0
- data/lib/ddtrace/contrib/sequel/database.rb +61 -0
- data/lib/ddtrace/contrib/sequel/dataset.rb +62 -0
- data/lib/ddtrace/contrib/sequel/ext.rb +15 -0
- data/lib/ddtrace/contrib/sequel/integration.rb +32 -0
- data/lib/ddtrace/contrib/sequel/patcher.rb +39 -0
- data/lib/ddtrace/contrib/sequel/utils.rb +46 -0
- data/lib/ddtrace/contrib/shoryuken/configuration/settings.rb +24 -0
- data/lib/ddtrace/contrib/shoryuken/ext.rb +18 -0
- data/lib/ddtrace/contrib/shoryuken/integration.rb +35 -0
- data/lib/ddtrace/contrib/shoryuken/patcher.rb +30 -0
- data/lib/ddtrace/contrib/shoryuken/tracer.rb +45 -0
- data/lib/ddtrace/contrib/sidekiq/client_tracer.rb +43 -0
- data/lib/ddtrace/contrib/sidekiq/configuration/settings.rb +26 -0
- data/lib/ddtrace/contrib/sidekiq/ext.rb +21 -0
- data/lib/ddtrace/contrib/sidekiq/integration.rb +36 -0
- data/lib/ddtrace/contrib/sidekiq/patcher.rb +40 -0
- data/lib/ddtrace/contrib/sidekiq/server_tracer.rb +58 -0
- data/lib/ddtrace/contrib/sidekiq/tracing.rb +28 -0
- data/lib/ddtrace/contrib/sinatra/configuration/settings.rb +34 -0
- data/lib/ddtrace/contrib/sinatra/env.rb +38 -0
- data/lib/ddtrace/contrib/sinatra/ext.rb +18 -0
- data/lib/ddtrace/contrib/sinatra/headers.rb +31 -0
- data/lib/ddtrace/contrib/sinatra/integration.rb +36 -0
- data/lib/ddtrace/contrib/sinatra/patcher.rb +33 -0
- data/lib/ddtrace/contrib/sinatra/tracer.rb +84 -0
- data/lib/ddtrace/contrib/sinatra/tracer_middleware.rb +72 -0
- data/lib/ddtrace/contrib/sucker_punch/configuration/settings.rb +25 -0
- data/lib/ddtrace/contrib/sucker_punch/exception_handler.rb +26 -0
- data/lib/ddtrace/contrib/sucker_punch/ext.rb +18 -0
- data/lib/ddtrace/contrib/sucker_punch/instrumentation.rb +70 -0
- data/lib/ddtrace/contrib/sucker_punch/integration.rb +36 -0
- data/lib/ddtrace/contrib/sucker_punch/patcher.rb +48 -0
- data/lib/ddtrace/correlation.rb +28 -0
- data/lib/ddtrace/diagnostics/health.rb +30 -0
- data/lib/ddtrace/distributed_tracing/headers/b3.rb +44 -0
- data/lib/ddtrace/distributed_tracing/headers/b3_single.rb +56 -0
- data/lib/ddtrace/distributed_tracing/headers/datadog.rb +42 -0
- data/lib/ddtrace/distributed_tracing/headers/headers.rb +70 -0
- data/lib/ddtrace/distributed_tracing/headers/helpers.rb +45 -0
- data/lib/ddtrace/encoding.rb +65 -0
- data/lib/ddtrace/environment.rb +23 -0
- data/lib/ddtrace/error.rb +27 -0
- data/lib/ddtrace/ext/analytics.rb +11 -0
- data/lib/ddtrace/ext/app_types.rb +11 -0
- data/lib/ddtrace/ext/diagnostics.rb +25 -0
- data/lib/ddtrace/ext/distributed.rb +33 -0
- data/lib/ddtrace/ext/errors.rb +10 -0
- data/lib/ddtrace/ext/forced_tracing.rb +25 -0
- data/lib/ddtrace/ext/http.rb +46 -0
- data/lib/ddtrace/ext/manual_tracing.rb +9 -0
- data/lib/ddtrace/ext/metrics.rb +15 -0
- data/lib/ddtrace/ext/net.rb +10 -0
- data/lib/ddtrace/ext/priority.rb +16 -0
- data/lib/ddtrace/ext/runtime.rb +26 -0
- data/lib/ddtrace/ext/sql.rb +8 -0
- data/lib/ddtrace/ext/transport.rb +17 -0
- data/lib/ddtrace/forced_tracing.rb +36 -0
- data/lib/ddtrace/logger.rb +39 -0
- data/lib/ddtrace/metrics.rb +215 -0
- data/lib/ddtrace/monkey.rb +58 -0
- data/lib/ddtrace/opentracer.rb +40 -0
- data/lib/ddtrace/opentracer/binary_propagator.rb +24 -0
- data/lib/ddtrace/opentracer/carrier.rb +6 -0
- data/lib/ddtrace/opentracer/distributed_headers.rb +52 -0
- data/lib/ddtrace/opentracer/global_tracer.rb +15 -0
- data/lib/ddtrace/opentracer/propagator.rb +22 -0
- data/lib/ddtrace/opentracer/rack_propagator.rb +60 -0
- data/lib/ddtrace/opentracer/scope.rb +15 -0
- data/lib/ddtrace/opentracer/scope_manager.rb +6 -0
- data/lib/ddtrace/opentracer/span.rb +98 -0
- data/lib/ddtrace/opentracer/span_context.rb +14 -0
- data/lib/ddtrace/opentracer/span_context_factory.rb +23 -0
- data/lib/ddtrace/opentracer/text_map_propagator.rb +75 -0
- data/lib/ddtrace/opentracer/thread_local_scope.rb +30 -0
- data/lib/ddtrace/opentracer/thread_local_scope_manager.rb +40 -0
- data/lib/ddtrace/opentracer/tracer.rb +208 -0
- data/lib/ddtrace/patcher.rb +47 -0
- data/lib/ddtrace/pin.rb +114 -0
- data/lib/ddtrace/pipeline.rb +46 -0
- data/lib/ddtrace/pipeline/span_filter.rb +38 -0
- data/lib/ddtrace/pipeline/span_processor.rb +20 -0
- data/lib/ddtrace/propagation/grpc_propagator.rb +61 -0
- data/lib/ddtrace/propagation/http_propagator.rb +75 -0
- data/lib/ddtrace/provider.rb +21 -0
- data/lib/ddtrace/quantization/hash.rb +103 -0
- data/lib/ddtrace/quantization/http.rb +86 -0
- data/lib/ddtrace/runtime/cgroup.rb +44 -0
- data/lib/ddtrace/runtime/class_count.rb +17 -0
- data/lib/ddtrace/runtime/container.rb +73 -0
- data/lib/ddtrace/runtime/gc.rb +16 -0
- data/lib/ddtrace/runtime/identity.rb +41 -0
- data/lib/ddtrace/runtime/metrics.rb +93 -0
- data/lib/ddtrace/runtime/object_space.rb +19 -0
- data/lib/ddtrace/runtime/socket.rb +14 -0
- data/lib/ddtrace/runtime/thread_count.rb +16 -0
- data/lib/ddtrace/sampler.rb +195 -0
- data/lib/ddtrace/span.rb +260 -0
- data/lib/ddtrace/sync_writer.rb +62 -0
- data/lib/ddtrace/tracer.rb +459 -0
- data/lib/ddtrace/transport/http.rb +91 -0
- data/lib/ddtrace/transport/http/adapters/net.rb +112 -0
- data/lib/ddtrace/transport/http/adapters/registry.rb +24 -0
- data/lib/ddtrace/transport/http/adapters/test.rb +77 -0
- data/lib/ddtrace/transport/http/adapters/unix_socket.rb +64 -0
- data/lib/ddtrace/transport/http/api.rb +46 -0
- data/lib/ddtrace/transport/http/api/endpoint.rb +27 -0
- data/lib/ddtrace/transport/http/api/fallbacks.rb +22 -0
- data/lib/ddtrace/transport/http/api/instance.rb +29 -0
- data/lib/ddtrace/transport/http/api/map.rb +14 -0
- data/lib/ddtrace/transport/http/api/spec.rb +15 -0
- data/lib/ddtrace/transport/http/builder.rb +165 -0
- data/lib/ddtrace/transport/http/client.rb +107 -0
- data/lib/ddtrace/transport/http/env.rb +48 -0
- data/lib/ddtrace/transport/http/response.rb +26 -0
- data/lib/ddtrace/transport/http/statistics.rb +30 -0
- data/lib/ddtrace/transport/http/traces.rb +140 -0
- data/lib/ddtrace/transport/parcel.rb +13 -0
- data/lib/ddtrace/transport/request.rb +13 -0
- data/lib/ddtrace/transport/response.rb +49 -0
- data/lib/ddtrace/transport/statistics.rb +72 -0
- data/lib/ddtrace/transport/traces.rb +33 -0
- data/lib/ddtrace/utils.rb +65 -0
- data/lib/ddtrace/utils/database.rb +25 -0
- data/lib/ddtrace/utils/time.rb +14 -0
- data/lib/ddtrace/vendor/active_record/connection_specification.rb +301 -0
- data/lib/ddtrace/version.rb +12 -0
- data/lib/ddtrace/workers.rb +125 -0
- data/lib/ddtrace/writer.rb +157 -0
- data/tasks/release_gem.rake +28 -0
- metadata +682 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
require 'ddtrace/transport/traces'
|
|
4
|
+
require 'ddtrace/transport/http/response'
|
|
5
|
+
require 'ddtrace/transport/http/api/endpoint'
|
|
6
|
+
|
|
7
|
+
module Datadog
|
|
8
|
+
module Transport
|
|
9
|
+
module HTTP
|
|
10
|
+
# HTTP transport behavior for traces
|
|
11
|
+
module Traces
|
|
12
|
+
# Response from HTTP transport for traces
|
|
13
|
+
class Response
|
|
14
|
+
include HTTP::Response
|
|
15
|
+
include Transport::Traces::Response
|
|
16
|
+
|
|
17
|
+
def initialize(http_response, options = {})
|
|
18
|
+
super(http_response)
|
|
19
|
+
@service_rates = options.fetch(:service_rates, nil)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Extensions for HTTP client
|
|
24
|
+
module Client
|
|
25
|
+
def send_traces(traces)
|
|
26
|
+
request = Transport::Traces::Request.new(traces)
|
|
27
|
+
|
|
28
|
+
send_request(request) do |api, env|
|
|
29
|
+
api.send_traces(env)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
module API
|
|
35
|
+
# Extensions for HTTP API Spec
|
|
36
|
+
module Spec
|
|
37
|
+
attr_reader :traces
|
|
38
|
+
|
|
39
|
+
def traces=(endpoint)
|
|
40
|
+
@traces = endpoint
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def send_traces(env, &block)
|
|
44
|
+
raise NoTraceEndpointDefinedError, self if traces.nil?
|
|
45
|
+
traces.call(env, &block)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Raised when traces sent but no traces endpoint is defined
|
|
49
|
+
class NoTraceEndpointDefinedError < StandardError
|
|
50
|
+
attr_reader :spec
|
|
51
|
+
|
|
52
|
+
def initialize(spec)
|
|
53
|
+
@spec = spec
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def message
|
|
57
|
+
'No trace endpoint is defined for API specification!'
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Extensions for HTTP API Instance
|
|
63
|
+
module Instance
|
|
64
|
+
def send_traces(env)
|
|
65
|
+
raise TracesNotSupportedError, spec unless spec.is_a?(Traces::API::Spec)
|
|
66
|
+
|
|
67
|
+
spec.send_traces(env) do |request_env|
|
|
68
|
+
call(request_env)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Raised when traces sent to API that does not support traces
|
|
73
|
+
class TracesNotSupportedError < StandardError
|
|
74
|
+
attr_reader :spec
|
|
75
|
+
|
|
76
|
+
def initialize(spec)
|
|
77
|
+
@spec = spec
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def message
|
|
81
|
+
'Traces not supported for this API!'
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Endpoint for submitting trace data
|
|
87
|
+
class Endpoint < HTTP::API::Endpoint
|
|
88
|
+
HEADER_CONTENT_TYPE = 'Content-Type'.freeze
|
|
89
|
+
HEADER_TRACE_COUNT = 'X-Datadog-Trace-Count'.freeze
|
|
90
|
+
SERVICE_RATE_KEY = 'rate_by_service'.freeze
|
|
91
|
+
|
|
92
|
+
attr_reader \
|
|
93
|
+
:encoder
|
|
94
|
+
|
|
95
|
+
def initialize(path, encoder, options = {})
|
|
96
|
+
super(:post, path)
|
|
97
|
+
@encoder = encoder
|
|
98
|
+
@service_rates = options.fetch(:service_rates, false)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def service_rates?
|
|
102
|
+
@service_rates == true
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def call(env, &block)
|
|
106
|
+
# Add trace count header
|
|
107
|
+
env.headers[HEADER_TRACE_COUNT] = env.request.parcel.count.to_s
|
|
108
|
+
|
|
109
|
+
# Encode body & type
|
|
110
|
+
env.headers[HEADER_CONTENT_TYPE] = encoder.content_type
|
|
111
|
+
env.body = env.request.parcel.encode_with(encoder)
|
|
112
|
+
|
|
113
|
+
# Query for response
|
|
114
|
+
http_response = super(env, &block)
|
|
115
|
+
|
|
116
|
+
# Process the response
|
|
117
|
+
response_options = {}.tap do |options|
|
|
118
|
+
# Parse service rates, if configured to do so.
|
|
119
|
+
if service_rates? && !http_response.payload.to_s.empty?
|
|
120
|
+
body = JSON.parse(http_response.payload)
|
|
121
|
+
if body.is_a?(Hash) && body.key?(SERVICE_RATE_KEY)
|
|
122
|
+
options[:service_rates] = body[SERVICE_RATE_KEY]
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Build and return a trace response
|
|
128
|
+
Traces::Response.new(http_response, response_options)
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Add traces behavior to transport components
|
|
134
|
+
HTTP::Client.send(:include, Traces::Client)
|
|
135
|
+
HTTP::API::Spec.send(:include, Traces::API::Spec)
|
|
136
|
+
HTTP::API::Instance.send(:include, Traces::API::Instance)
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
module Datadog
|
|
2
|
+
module Transport
|
|
3
|
+
# Defines abstract response for transport operations
|
|
4
|
+
module Response
|
|
5
|
+
def payload
|
|
6
|
+
nil
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def ok?
|
|
10
|
+
nil
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def unsupported?
|
|
14
|
+
nil
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def not_found?
|
|
18
|
+
nil
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def client_error?
|
|
22
|
+
nil
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def server_error?
|
|
26
|
+
nil
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def internal_error?
|
|
30
|
+
nil
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# A generic error response for internal errors
|
|
35
|
+
class InternalErrorResponse
|
|
36
|
+
include Response
|
|
37
|
+
|
|
38
|
+
attr_reader :error
|
|
39
|
+
|
|
40
|
+
def initialize(error)
|
|
41
|
+
@error = error
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def internal_error?
|
|
45
|
+
true
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
require 'ddtrace/diagnostics/health'
|
|
2
|
+
|
|
3
|
+
module Datadog
|
|
4
|
+
module Transport
|
|
5
|
+
# Tracks statistics for transports
|
|
6
|
+
module Statistics
|
|
7
|
+
def stats
|
|
8
|
+
@stats ||= Counts.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def update_stats_from_response!(response)
|
|
12
|
+
if response.ok?
|
|
13
|
+
stats.success += 1
|
|
14
|
+
stats.consecutive_errors = 0
|
|
15
|
+
else
|
|
16
|
+
stats.client_error += 1 if response.client_error?
|
|
17
|
+
stats.server_error += 1 if response.server_error?
|
|
18
|
+
stats.internal_error += 1 if response.internal_error?
|
|
19
|
+
stats.consecutive_errors += 1
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Send health metrics
|
|
23
|
+
Diagnostics::Health.metrics.send_metrics(
|
|
24
|
+
metrics_for_response(response).values
|
|
25
|
+
)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def metrics_for_response(response)
|
|
29
|
+
{}.tap do |metrics|
|
|
30
|
+
metrics[:api_errors] = Metrics::Metric.new(:api_errors, nil, 1) if response.internal_error?
|
|
31
|
+
metrics[:api_responses] = Metrics::Metric.new(:api_responses, nil, 1) unless response.internal_error?
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def update_stats_from_exception!(exception)
|
|
36
|
+
stats.internal_error += 1
|
|
37
|
+
stats.consecutive_errors += 1
|
|
38
|
+
|
|
39
|
+
# Send health metrics
|
|
40
|
+
Diagnostics::Health.metrics.send_metrics(
|
|
41
|
+
metrics_for_exception(exception).values
|
|
42
|
+
)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def metrics_for_exception(_exception)
|
|
46
|
+
{ api_errors: Metrics::Metric.new(:api_errors, nil, 1) }
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Stat counts
|
|
50
|
+
class Counts
|
|
51
|
+
attr_accessor \
|
|
52
|
+
:success,
|
|
53
|
+
:client_error,
|
|
54
|
+
:server_error,
|
|
55
|
+
:internal_error,
|
|
56
|
+
:consecutive_errors
|
|
57
|
+
|
|
58
|
+
def initialize
|
|
59
|
+
reset!
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def reset!
|
|
63
|
+
@success = 0
|
|
64
|
+
@client_error = 0
|
|
65
|
+
@server_error = 0
|
|
66
|
+
@internal_error = 0
|
|
67
|
+
@consecutive_errors = 0
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require 'ddtrace/transport/parcel'
|
|
2
|
+
require 'ddtrace/transport/request'
|
|
3
|
+
|
|
4
|
+
module Datadog
|
|
5
|
+
module Transport
|
|
6
|
+
module Traces
|
|
7
|
+
# Data transfer object for trace data
|
|
8
|
+
class Parcel
|
|
9
|
+
include Transport::Parcel
|
|
10
|
+
|
|
11
|
+
def count
|
|
12
|
+
data.length
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def encode_with(encoder)
|
|
16
|
+
encoder.encode_traces(data)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Traces request
|
|
21
|
+
class Request < Transport::Request
|
|
22
|
+
def initialize(traces)
|
|
23
|
+
super(Parcel.new(traces))
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Traces response
|
|
28
|
+
module Response
|
|
29
|
+
attr_reader :service_rates
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
require 'ddtrace/utils/database'
|
|
2
|
+
|
|
3
|
+
module Datadog
|
|
4
|
+
# Utils contains low-level utilities, typically to provide pseudo-random trace IDs.
|
|
5
|
+
module Utils
|
|
6
|
+
STRING_PLACEHOLDER = ''.encode(::Encoding::UTF_8).freeze
|
|
7
|
+
# We use a custom random number generator because we want no interference
|
|
8
|
+
# with the default one. Using the default prng, we could break code that
|
|
9
|
+
# would rely on srand/rand sequences.
|
|
10
|
+
|
|
11
|
+
# Return a span id
|
|
12
|
+
def self.next_id
|
|
13
|
+
reset! if was_forked?
|
|
14
|
+
|
|
15
|
+
@rnd.rand(Datadog::Span::MAX_ID)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.reset!
|
|
19
|
+
@pid = Process.pid
|
|
20
|
+
@rnd = Random.new
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def self.was_forked?
|
|
24
|
+
Process.pid != @pid
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private_class_method :reset!, :was_forked?
|
|
28
|
+
|
|
29
|
+
reset!
|
|
30
|
+
|
|
31
|
+
def self.truncate(value, size, omission = '...'.freeze)
|
|
32
|
+
string = value.to_s
|
|
33
|
+
|
|
34
|
+
return string if string.size <= size
|
|
35
|
+
|
|
36
|
+
string = string.slice(0, size - 1)
|
|
37
|
+
|
|
38
|
+
if size < omission.size
|
|
39
|
+
string[0, size] = omission
|
|
40
|
+
else
|
|
41
|
+
string[size - omission.size, size] = omission
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
string
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def self.utf8_encode(str, options = {})
|
|
48
|
+
str = str.to_s
|
|
49
|
+
|
|
50
|
+
if options[:binary]
|
|
51
|
+
# This option is useful for "gracefully" displaying binary data that
|
|
52
|
+
# often contains text such as marshalled objects
|
|
53
|
+
str.encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
|
|
54
|
+
elsif str.encoding == ::Encoding::UTF_8
|
|
55
|
+
str
|
|
56
|
+
else
|
|
57
|
+
str.encode(::Encoding::UTF_8)
|
|
58
|
+
end
|
|
59
|
+
rescue => e
|
|
60
|
+
Tracer.log.debug("Error encoding string in UTF-8: #{e}")
|
|
61
|
+
|
|
62
|
+
options.fetch(:placeholder, STRING_PLACEHOLDER)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Datadog
|
|
2
|
+
module Utils
|
|
3
|
+
# Common database-related utility functions.
|
|
4
|
+
module Database
|
|
5
|
+
VENDOR_DEFAULT = 'defaultdb'.freeze
|
|
6
|
+
VENDOR_POSTGRES = 'postgres'.freeze
|
|
7
|
+
VENDOR_SQLITE = 'sqlite'.freeze
|
|
8
|
+
|
|
9
|
+
module_function
|
|
10
|
+
|
|
11
|
+
def normalize_vendor(vendor)
|
|
12
|
+
case vendor
|
|
13
|
+
when nil
|
|
14
|
+
VENDOR_DEFAULT
|
|
15
|
+
when 'postgresql'
|
|
16
|
+
VENDOR_POSTGRES
|
|
17
|
+
when 'sqlite3'
|
|
18
|
+
VENDOR_SQLITE
|
|
19
|
+
else
|
|
20
|
+
vendor
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module Datadog
|
|
2
|
+
module Utils
|
|
3
|
+
# Common database-related utility functions.
|
|
4
|
+
module Time
|
|
5
|
+
PROCESS_TIME_SUPPORTED = Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.1.0')
|
|
6
|
+
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
def get_time
|
|
10
|
+
PROCESS_TIME_SUPPORTED ? Process.clock_gettime(Process::CLOCK_MONOTONIC) : ::Time.now.to_f
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
require 'uri'
|
|
2
|
+
|
|
3
|
+
# NOTE: This code is copied directly from ActiveRecord.
|
|
4
|
+
# Its purpose is to resolve connection information.
|
|
5
|
+
# It exists here only because it doesn't exist in Rails 3.2.
|
|
6
|
+
# When support for Rails 3.2 is dropped, this can be removed.
|
|
7
|
+
module Datadog
|
|
8
|
+
module Vendor
|
|
9
|
+
module ActiveRecord
|
|
10
|
+
# Copy/paste from:
|
|
11
|
+
# https://github.com/rails/rails/blob/5-2-stable/activerecord/lib/active_record/connection_handling.rb
|
|
12
|
+
module ConnectionHandling
|
|
13
|
+
RAILS_ENV = -> { (Rails.env if defined?(Rails) && defined?(Rails.env)) || ENV["RAILS_ENV"].presence || ENV["RACK_ENV"].presence }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Copy/paste from:
|
|
17
|
+
# https://github.com/rails/rails/blob/5-2-stable/activerecord/lib/active_record/connection_adapters/connection_specification.rb
|
|
18
|
+
module ConnectionAdapters
|
|
19
|
+
class ConnectionSpecification
|
|
20
|
+
attr_reader :name, :config, :adapter_method
|
|
21
|
+
|
|
22
|
+
def initialize(name, config, adapter_method)
|
|
23
|
+
@name, @config, @adapter_method = name, config, adapter_method
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def initialize_dup(original)
|
|
27
|
+
@config = original.config.dup
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def to_hash
|
|
31
|
+
@config.merge(name: @name)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Expands a connection string into a hash.
|
|
35
|
+
class ConnectionUrlResolver # :nodoc:
|
|
36
|
+
# == Example
|
|
37
|
+
#
|
|
38
|
+
# url = "postgresql://foo:bar@localhost:9000/foo_test?pool=5&timeout=3000"
|
|
39
|
+
# ConnectionUrlResolver.new(url).to_hash
|
|
40
|
+
# # => {
|
|
41
|
+
# "adapter" => "postgresql",
|
|
42
|
+
# "host" => "localhost",
|
|
43
|
+
# "port" => 9000,
|
|
44
|
+
# "database" => "foo_test",
|
|
45
|
+
# "username" => "foo",
|
|
46
|
+
# "password" => "bar",
|
|
47
|
+
# "pool" => "5",
|
|
48
|
+
# "timeout" => "3000"
|
|
49
|
+
# }
|
|
50
|
+
def initialize(url)
|
|
51
|
+
raise "Database URL cannot be empty" if url.blank?
|
|
52
|
+
@uri = uri_parser.parse(url)
|
|
53
|
+
@adapter = @uri.scheme && @uri.scheme.tr("-", "_")
|
|
54
|
+
@adapter = "postgresql" if @adapter == "postgres"
|
|
55
|
+
|
|
56
|
+
if @uri.opaque
|
|
57
|
+
@uri.opaque, @query = @uri.opaque.split("?", 2)
|
|
58
|
+
else
|
|
59
|
+
@query = @uri.query
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Converts the given URL to a full connection hash.
|
|
64
|
+
def to_hash
|
|
65
|
+
config = raw_config.reject { |_, value| value.blank? }
|
|
66
|
+
config.map { |key, value| config[key] = uri_parser.unescape(value) if value.is_a? String }
|
|
67
|
+
config
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
def uri
|
|
73
|
+
@uri
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def uri_parser
|
|
77
|
+
@uri_parser ||= URI::Parser.new
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Converts the query parameters of the URI into a hash.
|
|
81
|
+
#
|
|
82
|
+
# "localhost?pool=5&reaping_frequency=2"
|
|
83
|
+
# # => { "pool" => "5", "reaping_frequency" => "2" }
|
|
84
|
+
#
|
|
85
|
+
# returns empty hash if no query present.
|
|
86
|
+
#
|
|
87
|
+
# "localhost"
|
|
88
|
+
# # => {}
|
|
89
|
+
def query_hash
|
|
90
|
+
Hash[(@query || "").split("&").map { |pair| pair.split("=") }]
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def raw_config
|
|
94
|
+
if uri.opaque
|
|
95
|
+
query_hash.merge(
|
|
96
|
+
"adapter" => @adapter,
|
|
97
|
+
"database" => uri.opaque)
|
|
98
|
+
else
|
|
99
|
+
query_hash.merge(
|
|
100
|
+
"adapter" => @adapter,
|
|
101
|
+
"username" => uri.user,
|
|
102
|
+
"password" => uri.password,
|
|
103
|
+
"port" => uri.port,
|
|
104
|
+
"database" => database_from_path,
|
|
105
|
+
"host" => uri.hostname)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Returns name of the database.
|
|
110
|
+
def database_from_path
|
|
111
|
+
if @adapter == "sqlite3"
|
|
112
|
+
# 'sqlite3:/foo' is absolute, because that makes sense. The
|
|
113
|
+
# corresponding relative version, 'sqlite3:foo', is handled
|
|
114
|
+
# elsewhere, as an "opaque".
|
|
115
|
+
|
|
116
|
+
uri.path
|
|
117
|
+
else
|
|
118
|
+
# Only SQLite uses a filename as the "database" name; for
|
|
119
|
+
# anything else, a leading slash would be silly.
|
|
120
|
+
|
|
121
|
+
uri.path.sub(%r{^/}, "")
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
##
|
|
127
|
+
# Builds a ConnectionSpecification from user input.
|
|
128
|
+
class Resolver # :nodoc:
|
|
129
|
+
attr_reader :configurations
|
|
130
|
+
|
|
131
|
+
# Accepts a hash two layers deep, keys on the first layer represent
|
|
132
|
+
# environments such as "production". Keys must be strings.
|
|
133
|
+
def initialize(configurations)
|
|
134
|
+
@configurations = configurations
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Returns a hash with database connection information.
|
|
138
|
+
#
|
|
139
|
+
# == Examples
|
|
140
|
+
#
|
|
141
|
+
# Full hash Configuration.
|
|
142
|
+
#
|
|
143
|
+
# configurations = { "production" => { "host" => "localhost", "database" => "foo", "adapter" => "sqlite3" } }
|
|
144
|
+
# Resolver.new(configurations).resolve(:production)
|
|
145
|
+
# # => { "host" => "localhost", "database" => "foo", "adapter" => "sqlite3"}
|
|
146
|
+
#
|
|
147
|
+
# Initialized with URL configuration strings.
|
|
148
|
+
#
|
|
149
|
+
# configurations = { "production" => "postgresql://localhost/foo" }
|
|
150
|
+
# Resolver.new(configurations).resolve(:production)
|
|
151
|
+
# # => { "host" => "localhost", "database" => "foo", "adapter" => "postgresql" }
|
|
152
|
+
#
|
|
153
|
+
def resolve(config)
|
|
154
|
+
if config
|
|
155
|
+
resolve_connection config
|
|
156
|
+
elsif env = ConnectionHandling::RAILS_ENV.call
|
|
157
|
+
resolve_symbol_connection env.to_sym
|
|
158
|
+
else
|
|
159
|
+
raise AdapterNotSpecified
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Expands each key in @configurations hash into fully resolved hash
|
|
164
|
+
def resolve_all
|
|
165
|
+
config = configurations.dup
|
|
166
|
+
|
|
167
|
+
if env = ConnectionHandling::DEFAULT_ENV.call
|
|
168
|
+
env_config = config[env] if config[env].is_a?(Hash) && !(config[env].key?("adapter") || config[env].key?("url"))
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
config.reject! { |k, v| v.is_a?(Hash) && !(v.key?("adapter") || v.key?("url")) }
|
|
172
|
+
config.merge! env_config if env_config
|
|
173
|
+
|
|
174
|
+
config.each do |key, value|
|
|
175
|
+
config[key] = resolve(value) if value
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
config
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# Returns an instance of ConnectionSpecification for a given adapter.
|
|
182
|
+
# Accepts a hash one layer deep that contains all connection information.
|
|
183
|
+
#
|
|
184
|
+
# == Example
|
|
185
|
+
#
|
|
186
|
+
# config = { "production" => { "host" => "localhost", "database" => "foo", "adapter" => "sqlite3" } }
|
|
187
|
+
# spec = Resolver.new(config).spec(:production)
|
|
188
|
+
# spec.adapter_method
|
|
189
|
+
# # => "sqlite3_connection"
|
|
190
|
+
# spec.config
|
|
191
|
+
# # => { "host" => "localhost", "database" => "foo", "adapter" => "sqlite3" }
|
|
192
|
+
#
|
|
193
|
+
def spec(config)
|
|
194
|
+
spec = resolve(config).symbolize_keys
|
|
195
|
+
|
|
196
|
+
raise(AdapterNotSpecified, "database configuration does not specify adapter") unless spec.key?(:adapter)
|
|
197
|
+
|
|
198
|
+
# Require the adapter itself and give useful feedback about
|
|
199
|
+
# 1. Missing adapter gems and
|
|
200
|
+
# 2. Adapter gems' missing dependencies.
|
|
201
|
+
path_to_adapter = "active_record/connection_adapters/#{spec[:adapter]}_adapter"
|
|
202
|
+
begin
|
|
203
|
+
require path_to_adapter
|
|
204
|
+
rescue LoadError => e
|
|
205
|
+
# We couldn't require the adapter itself. Raise an exception that
|
|
206
|
+
# points out config typos and missing gems.
|
|
207
|
+
if e.path == path_to_adapter
|
|
208
|
+
# We can assume that a non-builtin adapter was specified, so it's
|
|
209
|
+
# either misspelled or missing from Gemfile.
|
|
210
|
+
raise e.class, "Could not load the '#{spec[:adapter]}' Active Record adapter. Ensure that the adapter is spelled correctly in config/database.yml and that you've added the necessary adapter gem to your Gemfile.", e.backtrace
|
|
211
|
+
|
|
212
|
+
# Bubbled up from the adapter require. Prefix the exception message
|
|
213
|
+
# with some guidance about how to address it and reraise.
|
|
214
|
+
else
|
|
215
|
+
raise e.class, "Error loading the '#{spec[:adapter]}' Active Record adapter. Missing a gem it depends on? #{e.message}", e.backtrace
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
adapter_method = "#{spec[:adapter]}_connection"
|
|
220
|
+
|
|
221
|
+
unless ::ActiveRecord::Base.respond_to?(adapter_method)
|
|
222
|
+
raise AdapterNotFound, "database configuration specifies nonexistent #{spec.config[:adapter]} adapter"
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
ConnectionSpecification.new(spec.delete(:name) || "primary", spec, adapter_method)
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
private
|
|
229
|
+
|
|
230
|
+
# Returns fully resolved connection, accepts hash, string or symbol.
|
|
231
|
+
# Always returns a hash.
|
|
232
|
+
#
|
|
233
|
+
# == Examples
|
|
234
|
+
#
|
|
235
|
+
# Symbol representing current environment.
|
|
236
|
+
#
|
|
237
|
+
# Resolver.new("production" => {}).resolve_connection(:production)
|
|
238
|
+
# # => {}
|
|
239
|
+
#
|
|
240
|
+
# One layer deep hash of connection values.
|
|
241
|
+
#
|
|
242
|
+
# Resolver.new({}).resolve_connection("adapter" => "sqlite3")
|
|
243
|
+
# # => { "adapter" => "sqlite3" }
|
|
244
|
+
#
|
|
245
|
+
# Connection URL.
|
|
246
|
+
#
|
|
247
|
+
# Resolver.new({}).resolve_connection("postgresql://localhost/foo")
|
|
248
|
+
# # => { "host" => "localhost", "database" => "foo", "adapter" => "postgresql" }
|
|
249
|
+
#
|
|
250
|
+
def resolve_connection(spec)
|
|
251
|
+
case spec
|
|
252
|
+
when Symbol
|
|
253
|
+
resolve_symbol_connection spec
|
|
254
|
+
when String
|
|
255
|
+
resolve_url_connection spec
|
|
256
|
+
when Hash
|
|
257
|
+
resolve_hash_connection spec
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
# Takes the environment such as +:production+ or +:development+.
|
|
262
|
+
# This requires that the @configurations was initialized with a key that
|
|
263
|
+
# matches.
|
|
264
|
+
#
|
|
265
|
+
# Resolver.new("production" => {}).resolve_symbol_connection(:production)
|
|
266
|
+
# # => {}
|
|
267
|
+
#
|
|
268
|
+
def resolve_symbol_connection(spec)
|
|
269
|
+
if config = configurations[spec.to_s]
|
|
270
|
+
resolve_connection(config).merge("name" => spec.to_s)
|
|
271
|
+
else
|
|
272
|
+
raise(AdapterNotSpecified, "'#{spec}' database is not configured. Available: #{configurations.keys.inspect}")
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
# Accepts a hash. Expands the "url" key that contains a
|
|
277
|
+
# URL database connection to a full connection
|
|
278
|
+
# hash and merges with the rest of the hash.
|
|
279
|
+
# Connection details inside of the "url" key win any merge conflicts
|
|
280
|
+
def resolve_hash_connection(spec)
|
|
281
|
+
if spec["url"] && spec["url"] !~ /^jdbc:/
|
|
282
|
+
connection_hash = resolve_url_connection(spec.delete("url"))
|
|
283
|
+
spec.merge!(connection_hash)
|
|
284
|
+
end
|
|
285
|
+
spec
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
# Takes a connection URL.
|
|
289
|
+
#
|
|
290
|
+
# Resolver.new({}).resolve_url_connection("postgresql://localhost/foo")
|
|
291
|
+
# # => { "host" => "localhost", "database" => "foo", "adapter" => "postgresql" }
|
|
292
|
+
#
|
|
293
|
+
def resolve_url_connection(url)
|
|
294
|
+
ConnectionUrlResolver.new(url).to_hash
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
end
|