ddtrace 0.45.0 → 0.47.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (302) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +131 -12
  3. data/.circleci/images/primary/{Dockerfile-jruby-9.2 → Dockerfile-jruby-9.2-latest} +2 -1
  4. data/.circleci/images/primary/Dockerfile-jruby-9.2.0.0 +73 -0
  5. data/.circleci/images/primary/Dockerfile-truffleruby-21.0.0 +73 -0
  6. data/.github/workflows/create-next-milestone.yml +2 -2
  7. data/.rubocop.yml +250 -7
  8. data/.rubocop_todo.yml +397 -0
  9. data/.simplecov +6 -0
  10. data/Appraisals +16 -1
  11. data/CHANGELOG.md +150 -1
  12. data/Gemfile +53 -3
  13. data/LICENSE-3rdparty.csv +2 -0
  14. data/Rakefile +5 -23
  15. data/ddtrace.gemspec +6 -36
  16. data/docker-compose.yml +75 -7
  17. data/docs/DevelopmentGuide.md +28 -0
  18. data/docs/GettingStarted.md +69 -17
  19. data/integration/README.md +68 -0
  20. data/integration/apps/rack/.dockerignore +1 -0
  21. data/integration/apps/rack/.envrc.sample +1 -0
  22. data/integration/apps/rack/.gitignore +4 -0
  23. data/integration/apps/rack/.rspec +1 -0
  24. data/integration/apps/rack/Dockerfile +25 -0
  25. data/integration/apps/rack/Dockerfile-ci +11 -0
  26. data/integration/apps/rack/Gemfile +24 -0
  27. data/integration/apps/rack/README.md +93 -0
  28. data/integration/apps/rack/app/acme.rb +80 -0
  29. data/integration/apps/rack/app/datadog.rb +17 -0
  30. data/integration/apps/rack/bin/run +22 -0
  31. data/integration/apps/rack/bin/setup +17 -0
  32. data/integration/apps/rack/bin/test +24 -0
  33. data/integration/apps/rack/config.ru +6 -0
  34. data/integration/apps/rack/config/puma.rb +14 -0
  35. data/integration/apps/rack/config/unicorn.rb +23 -0
  36. data/integration/apps/rack/docker-compose.ci.yml +62 -0
  37. data/integration/apps/rack/docker-compose.yml +78 -0
  38. data/integration/apps/rack/script/build-images +38 -0
  39. data/integration/apps/rack/script/ci +50 -0
  40. data/integration/apps/rack/spec/integration/basic_spec.rb +10 -0
  41. data/integration/apps/rack/spec/spec_helper.rb +16 -0
  42. data/integration/apps/rack/spec/support/integration_helper.rb +22 -0
  43. data/integration/apps/rails-five/.dockerignore +1 -0
  44. data/integration/apps/rails-five/.env +3 -0
  45. data/integration/apps/rails-five/.envrc.sample +1 -0
  46. data/integration/apps/rails-five/.gitignore +30 -0
  47. data/integration/apps/rails-five/Dockerfile +25 -0
  48. data/integration/apps/rails-five/Dockerfile-ci +11 -0
  49. data/integration/apps/rails-five/Gemfile +104 -0
  50. data/integration/apps/rails-five/README.md +94 -0
  51. data/integration/apps/rails-five/Rakefile +6 -0
  52. data/integration/apps/rails-five/app/channels/application_cable/channel.rb +4 -0
  53. data/integration/apps/rails-five/app/channels/application_cable/connection.rb +4 -0
  54. data/integration/apps/rails-five/app/controllers/application_controller.rb +2 -0
  55. data/integration/apps/rails-five/app/controllers/basic_controller.rb +36 -0
  56. data/integration/apps/rails-five/app/controllers/concerns/.keep +0 -0
  57. data/integration/apps/rails-five/app/controllers/health_controller.rb +9 -0
  58. data/integration/apps/rails-five/app/controllers/jobs_controller.rb +12 -0
  59. data/integration/apps/rails-five/app/jobs/application_job.rb +2 -0
  60. data/integration/apps/rails-five/app/jobs/test_job.rb +12 -0
  61. data/integration/apps/rails-five/app/mailers/application_mailer.rb +4 -0
  62. data/integration/apps/rails-five/app/models/application_record.rb +3 -0
  63. data/integration/apps/rails-five/app/models/concerns/.keep +0 -0
  64. data/integration/apps/rails-five/app/models/test.rb +2 -0
  65. data/integration/apps/rails-five/app/views/layouts/mailer.html.erb +13 -0
  66. data/integration/apps/rails-five/app/views/layouts/mailer.text.erb +1 -0
  67. data/integration/apps/rails-five/bin/bundle +3 -0
  68. data/integration/apps/rails-five/bin/rails +9 -0
  69. data/integration/apps/rails-five/bin/rake +9 -0
  70. data/integration/apps/rails-five/bin/run +24 -0
  71. data/integration/apps/rails-five/bin/setup +27 -0
  72. data/integration/apps/rails-five/bin/spring +17 -0
  73. data/integration/apps/rails-five/bin/test +21 -0
  74. data/integration/apps/rails-five/bin/update +28 -0
  75. data/integration/apps/rails-five/config.ru +5 -0
  76. data/integration/apps/rails-five/config/application.rb +97 -0
  77. data/integration/apps/rails-five/config/boot.rb +4 -0
  78. data/integration/apps/rails-five/config/cable.yml +10 -0
  79. data/integration/apps/rails-five/config/credentials.yml.enc +1 -0
  80. data/integration/apps/rails-five/config/database.yml +28 -0
  81. data/integration/apps/rails-five/config/environment.rb +5 -0
  82. data/integration/apps/rails-five/config/environments/development.rb +51 -0
  83. data/integration/apps/rails-five/config/environments/production.rb +82 -0
  84. data/integration/apps/rails-five/config/environments/test.rb +43 -0
  85. data/integration/apps/rails-five/config/initializers/datadog.rb +18 -0
  86. data/integration/apps/rails-five/config/initializers/filter_parameter_logging.rb +4 -0
  87. data/integration/apps/rails-five/config/initializers/resque.rb +4 -0
  88. data/integration/apps/rails-five/config/initializers/rollbar.rb +5 -0
  89. data/integration/apps/rails-five/config/initializers/wrap_parameters.rb +14 -0
  90. data/integration/apps/rails-five/config/locales/en.yml +33 -0
  91. data/integration/apps/rails-five/config/puma.rb +24 -0
  92. data/integration/apps/rails-five/config/routes.rb +11 -0
  93. data/integration/apps/rails-five/config/spring.rb +6 -0
  94. data/integration/apps/rails-five/config/unicorn.rb +29 -0
  95. data/integration/apps/rails-five/db/migrate/20190927215052_create_tests.rb +11 -0
  96. data/integration/apps/rails-five/db/schema.rb +23 -0
  97. data/integration/apps/rails-five/db/seeds.rb +7 -0
  98. data/integration/apps/rails-five/docker-compose.ci.yml +98 -0
  99. data/integration/apps/rails-five/docker-compose.yml +100 -0
  100. data/integration/apps/rails-five/lib/tasks/.keep +0 -0
  101. data/integration/apps/rails-five/log/.keep +0 -0
  102. data/integration/apps/rails-five/public/robots.txt +1 -0
  103. data/integration/apps/rails-five/script/build-images +35 -0
  104. data/integration/apps/rails-five/script/ci +50 -0
  105. data/integration/apps/rails-five/spec/integration/basic_spec.rb +10 -0
  106. data/integration/apps/rails-five/spec/spec_helper.rb +16 -0
  107. data/integration/apps/rails-five/spec/support/integration_helper.rb +22 -0
  108. data/integration/apps/rails-five/storage/.keep +0 -0
  109. data/integration/apps/rails-five/tmp/.keep +0 -0
  110. data/integration/apps/rails-five/vendor/.keep +0 -0
  111. data/integration/apps/ruby/.dockerignore +1 -0
  112. data/integration/apps/ruby/.envrc.sample +1 -0
  113. data/integration/apps/ruby/.gitignore +2 -0
  114. data/integration/apps/ruby/Dockerfile +25 -0
  115. data/integration/apps/ruby/Dockerfile-ci +11 -0
  116. data/integration/apps/ruby/Gemfile +11 -0
  117. data/integration/apps/ruby/README.md +70 -0
  118. data/integration/apps/ruby/agent.yaml +3 -0
  119. data/integration/apps/ruby/app/datadog.rb +13 -0
  120. data/integration/apps/ruby/app/fibonacci.rb +58 -0
  121. data/integration/apps/ruby/bin/run +20 -0
  122. data/integration/apps/ruby/bin/setup +17 -0
  123. data/integration/apps/ruby/bin/test +21 -0
  124. data/integration/apps/ruby/docker-compose.ci.yml +51 -0
  125. data/integration/apps/ruby/docker-compose.yml +63 -0
  126. data/integration/apps/ruby/script/build-images +38 -0
  127. data/integration/apps/ruby/script/ci +50 -0
  128. data/integration/images/agent/Dockerfile +2 -0
  129. data/integration/images/agent/agent.yaml +3 -0
  130. data/integration/images/include/datadog/analyzer.rb +71 -0
  131. data/integration/images/include/datadog/demo_env.rb +101 -0
  132. data/integration/images/include/http-health-check +33 -0
  133. data/integration/images/ruby/2.0/Dockerfile +54 -0
  134. data/integration/images/ruby/2.1/Dockerfile +54 -0
  135. data/integration/images/ruby/2.2/Dockerfile +54 -0
  136. data/integration/images/ruby/2.3/Dockerfile +70 -0
  137. data/integration/images/ruby/2.4/Dockerfile +54 -0
  138. data/integration/images/ruby/2.5/Dockerfile +54 -0
  139. data/integration/images/ruby/2.6/Dockerfile +54 -0
  140. data/integration/images/ruby/2.7/Dockerfile +54 -0
  141. data/integration/images/ruby/3.0/Dockerfile +54 -0
  142. data/integration/images/wrk/Dockerfile +33 -0
  143. data/integration/images/wrk/scripts/entrypoint.sh +17 -0
  144. data/integration/images/wrk/scripts/scenarios/basic/default.lua +1 -0
  145. data/integration/images/wrk/scripts/scenarios/basic/fibonacci.lua +1 -0
  146. data/integration/script/build-images +43 -0
  147. data/lib/ddtrace.rb +0 -5
  148. data/lib/ddtrace/analytics.rb +2 -0
  149. data/lib/ddtrace/buffer.rb +4 -4
  150. data/lib/ddtrace/configuration.rb +92 -23
  151. data/lib/ddtrace/configuration/base.rb +1 -1
  152. data/lib/ddtrace/configuration/components.rb +2 -2
  153. data/lib/ddtrace/configuration/option_definition.rb +1 -3
  154. data/lib/ddtrace/configuration/options.rb +4 -7
  155. data/lib/ddtrace/configuration/settings.rb +17 -3
  156. data/lib/ddtrace/context.rb +5 -6
  157. data/lib/ddtrace/context_provider.rb +0 -1
  158. data/lib/ddtrace/contrib/action_cable/event.rb +1 -0
  159. data/lib/ddtrace/contrib/action_pack/action_controller/instrumentation.rb +1 -3
  160. data/lib/ddtrace/contrib/action_view/event.rb +1 -1
  161. data/lib/ddtrace/contrib/action_view/utils.rb +1 -1
  162. data/lib/ddtrace/contrib/active_record/configuration/resolver.rb +101 -18
  163. data/lib/ddtrace/contrib/active_record/utils.rb +1 -0
  164. data/lib/ddtrace/contrib/active_support/notifications/event.rb +2 -1
  165. data/lib/ddtrace/contrib/active_support/notifications/subscriber.rb +1 -0
  166. data/lib/ddtrace/contrib/active_support/notifications/subscription.rb +9 -5
  167. data/lib/ddtrace/contrib/auto_instrument.rb +1 -0
  168. data/lib/ddtrace/contrib/aws/patcher.rb +1 -0
  169. data/lib/ddtrace/contrib/aws/services.rb +2 -0
  170. data/lib/ddtrace/contrib/configurable.rb +63 -39
  171. data/lib/ddtrace/contrib/configuration/resolver.rb +70 -5
  172. data/lib/ddtrace/contrib/configuration/resolvers/pattern_resolver.rb +19 -20
  173. data/lib/ddtrace/contrib/configuration/settings.rb +7 -6
  174. data/lib/ddtrace/contrib/cucumber/configuration/settings.rb +0 -10
  175. data/lib/ddtrace/contrib/cucumber/ext.rb +0 -2
  176. data/lib/ddtrace/contrib/cucumber/formatter.rb +5 -11
  177. data/lib/ddtrace/contrib/dalli/patcher.rb +0 -38
  178. data/lib/ddtrace/contrib/delayed_job/plugin.rb +0 -1
  179. data/lib/ddtrace/contrib/elasticsearch/patcher.rb +1 -0
  180. data/lib/ddtrace/contrib/elasticsearch/quantize.rb +3 -2
  181. data/lib/ddtrace/contrib/ethon/easy_patch.rb +5 -5
  182. data/lib/ddtrace/contrib/excon/middleware.rb +2 -6
  183. data/lib/ddtrace/contrib/extensions.rb +27 -3
  184. data/lib/ddtrace/contrib/faraday/middleware.rb +1 -3
  185. data/lib/ddtrace/contrib/faraday/patcher.rb +0 -36
  186. data/lib/ddtrace/contrib/grape/endpoint.rb +8 -15
  187. data/lib/ddtrace/contrib/grape/patcher.rb +0 -42
  188. data/lib/ddtrace/contrib/grpc/datadog_interceptor.rb +8 -8
  189. data/lib/ddtrace/contrib/grpc/datadog_interceptor/server.rb +1 -0
  190. data/lib/ddtrace/contrib/grpc/patcher.rb +0 -36
  191. data/lib/ddtrace/contrib/http/circuit_breaker.rb +1 -3
  192. data/lib/ddtrace/contrib/http/instrumentation.rb +5 -5
  193. data/lib/ddtrace/contrib/httpclient/instrumentation.rb +14 -19
  194. data/lib/ddtrace/contrib/httpclient/patcher.rb +5 -2
  195. data/lib/ddtrace/contrib/httprb/instrumentation.rb +14 -20
  196. data/lib/ddtrace/contrib/httprb/patcher.rb +5 -2
  197. data/lib/ddtrace/contrib/mongodb/instrumentation.rb +2 -0
  198. data/lib/ddtrace/contrib/mongodb/subscribers.rb +2 -3
  199. data/lib/ddtrace/contrib/patcher.rb +9 -6
  200. data/lib/ddtrace/contrib/presto/patcher.rb +5 -2
  201. data/lib/ddtrace/contrib/qless/qless_job.rb +1 -0
  202. data/lib/ddtrace/contrib/qless/tracer_cleaner.rb +1 -0
  203. data/lib/ddtrace/contrib/que/ext.rb +19 -19
  204. data/lib/ddtrace/contrib/que/tracer.rb +1 -1
  205. data/lib/ddtrace/contrib/racecar/event.rb +1 -0
  206. data/lib/ddtrace/contrib/rack/configuration/settings.rb +3 -3
  207. data/lib/ddtrace/contrib/rack/middlewares.rb +5 -10
  208. data/lib/ddtrace/contrib/rack/patcher.rb +1 -3
  209. data/lib/ddtrace/contrib/rails/patcher.rb +6 -2
  210. data/lib/ddtrace/contrib/rake/instrumentation.rb +4 -2
  211. data/lib/ddtrace/contrib/redis/configuration/resolver.rb +11 -4
  212. data/lib/ddtrace/contrib/redis/quantize.rb +1 -0
  213. data/lib/ddtrace/contrib/redis/vendor/LICENSE +20 -0
  214. data/lib/ddtrace/contrib/redis/vendor/resolver.rb +6 -7
  215. data/lib/ddtrace/contrib/registry.rb +2 -2
  216. data/lib/ddtrace/contrib/resque/integration.rb +1 -1
  217. data/lib/ddtrace/contrib/resque/resque_job.rb +2 -0
  218. data/lib/ddtrace/contrib/rest_client/request_patch.rb +1 -3
  219. data/lib/ddtrace/contrib/rspec/configuration/settings.rb +0 -10
  220. data/lib/ddtrace/contrib/rspec/example.rb +24 -10
  221. data/lib/ddtrace/contrib/rspec/ext.rb +0 -3
  222. data/lib/ddtrace/contrib/rspec/integration.rb +1 -1
  223. data/lib/ddtrace/contrib/rspec/patcher.rb +0 -2
  224. data/lib/ddtrace/contrib/sequel/utils.rb +5 -6
  225. data/lib/ddtrace/contrib/shoryuken/tracer.rb +0 -1
  226. data/lib/ddtrace/contrib/sidekiq/server_tracer.rb +2 -7
  227. data/lib/ddtrace/contrib/sidekiq/tracing.rb +0 -1
  228. data/lib/ddtrace/contrib/sinatra/env.rb +1 -3
  229. data/lib/ddtrace/contrib/sinatra/headers.rb +1 -3
  230. data/lib/ddtrace/contrib/sinatra/tracer.rb +1 -3
  231. data/lib/ddtrace/contrib/sinatra/tracer_middleware.rb +3 -3
  232. data/lib/ddtrace/contrib/sneakers/ext.rb +11 -11
  233. data/lib/ddtrace/contrib/sneakers/tracer.rb +2 -4
  234. data/lib/ddtrace/contrib/status_code_matcher.rb +5 -3
  235. data/lib/ddtrace/correlation.rb +1 -0
  236. data/lib/ddtrace/diagnostics/environment_logger.rb +2 -1
  237. data/lib/ddtrace/distributed_tracing/headers/headers.rb +1 -0
  238. data/lib/ddtrace/distributed_tracing/headers/helpers.rb +1 -3
  239. data/lib/ddtrace/ext/ci.rb +2 -2
  240. data/lib/ddtrace/ext/distributed.rb +1 -1
  241. data/lib/ddtrace/ext/http.rb +1 -1
  242. data/lib/ddtrace/ext/runtime.rb +3 -1
  243. data/lib/ddtrace/forced_tracing.rb +2 -0
  244. data/lib/ddtrace/logger.rb +1 -1
  245. data/lib/ddtrace/metrics.rb +10 -6
  246. data/lib/ddtrace/opentracer/distributed_headers.rb +3 -0
  247. data/lib/ddtrace/opentracer/span.rb +2 -6
  248. data/lib/ddtrace/opentracer/thread_local_scope.rb +1 -0
  249. data/lib/ddtrace/patcher.rb +25 -4
  250. data/lib/ddtrace/pin.rb +8 -61
  251. data/lib/ddtrace/pipeline/span_filter.rb +1 -1
  252. data/lib/ddtrace/propagation/grpc_propagator.rb +1 -0
  253. data/lib/ddtrace/quantization/http.rb +1 -0
  254. data/lib/ddtrace/runtime/cgroup.rb +2 -2
  255. data/lib/ddtrace/runtime/container.rb +27 -29
  256. data/lib/ddtrace/runtime/identity.rb +8 -0
  257. data/lib/ddtrace/sampler.rb +1 -1
  258. data/lib/ddtrace/sampling/rule_sampler.rb +1 -0
  259. data/lib/ddtrace/span.rb +7 -7
  260. data/lib/ddtrace/sync_writer.rb +12 -12
  261. data/lib/ddtrace/tracer.rb +7 -5
  262. data/lib/ddtrace/transport/http.rb +15 -8
  263. data/lib/ddtrace/transport/http/adapters/net.rb +27 -8
  264. data/lib/ddtrace/transport/http/adapters/registry.rb +1 -0
  265. data/lib/ddtrace/transport/http/adapters/unix_socket.rb +2 -4
  266. data/lib/ddtrace/transport/http/builder.rb +7 -1
  267. data/lib/ddtrace/transport/http/env.rb +8 -0
  268. data/lib/ddtrace/transport/http/traces.rb +2 -3
  269. data/lib/ddtrace/transport/io.rb +1 -1
  270. data/lib/ddtrace/transport/io/response.rb +1 -3
  271. data/lib/ddtrace/transport/io/traces.rb +6 -0
  272. data/lib/ddtrace/transport/traces.rb +18 -1
  273. data/lib/ddtrace/utils/compression.rb +27 -0
  274. data/lib/ddtrace/utils/object_set.rb +41 -0
  275. data/lib/ddtrace/utils/only_once.rb +40 -0
  276. data/lib/ddtrace/utils/sequence.rb +17 -0
  277. data/lib/ddtrace/utils/string_table.rb +45 -0
  278. data/lib/ddtrace/utils/time.rb +32 -1
  279. data/lib/ddtrace/vendor/active_record/MIT-LICENSE +20 -0
  280. data/lib/ddtrace/vendor/multipart-post/LICENSE +11 -0
  281. data/lib/ddtrace/vendor/multipart-post/multipart.rb +12 -0
  282. data/lib/ddtrace/vendor/multipart-post/multipart/post.rb +8 -0
  283. data/lib/ddtrace/vendor/multipart-post/multipart/post/composite_read_io.rb +116 -0
  284. data/lib/ddtrace/vendor/multipart-post/multipart/post/multipartable.rb +57 -0
  285. data/lib/ddtrace/vendor/multipart-post/multipart/post/parts.rb +135 -0
  286. data/lib/ddtrace/vendor/multipart-post/multipart/post/version.rb +9 -0
  287. data/lib/ddtrace/vendor/multipart-post/net/http/post/multipart.rb +32 -0
  288. data/lib/ddtrace/version.rb +1 -1
  289. data/lib/ddtrace/workers.rb +5 -0
  290. data/lib/ddtrace/workers/async.rb +11 -3
  291. data/lib/ddtrace/workers/loop.rb +17 -3
  292. data/lib/ddtrace/workers/polling.rb +1 -0
  293. data/lib/ddtrace/workers/queue.rb +1 -0
  294. data/lib/ddtrace/workers/trace_writer.rb +10 -10
  295. data/lib/ddtrace/writer.rb +7 -4
  296. metadata +152 -402
  297. data/lib/ddtrace/augmentation.rb +0 -13
  298. data/lib/ddtrace/augmentation/method_wrapper.rb +0 -20
  299. data/lib/ddtrace/augmentation/method_wrapping.rb +0 -38
  300. data/lib/ddtrace/augmentation/shim.rb +0 -102
  301. data/lib/ddtrace/contrib/rspec/example_group.rb +0 -61
  302. data/lib/ddtrace/monkey.rb +0 -58
@@ -55,7 +55,6 @@ module Datadog
55
55
 
56
56
  # Return the thread-local context.
57
57
  def local(thread = Thread.current)
58
- raise ArgumentError, '\'thread\' must be a Thread.' unless thread.is_a?(Thread)
59
58
  thread[@key] ||= Datadog::Context.new
60
59
  end
61
60
  end
@@ -56,6 +56,7 @@ module Datadog
56
56
  # preventing such a leak.
57
57
  def ensure_clean_context!
58
58
  return unless configuration[:tracer].call_context.current_span
59
+
59
60
  configuration[:tracer].provider.context = Context.new
60
61
  end
61
62
  end
@@ -36,9 +36,7 @@ module Datadog
36
36
 
37
37
  begin
38
38
  # Set the resource name, if it's still the default name
39
- if span.resource == span.name
40
- span.resource = "#{payload.fetch(:controller)}##{payload.fetch(:action)}"
41
- end
39
+ span.resource = "#{payload.fetch(:controller)}##{payload.fetch(:action)}" if span.resource == span.name
42
40
 
43
41
  # Set the resource name of the Rack request span unless this is an exception controller.
44
42
  unless exception_controller?(payload)
@@ -21,7 +21,7 @@ module Datadog
21
21
  end
22
22
 
23
23
  def record_exception(span, payload)
24
- if payload [:exception_object]
24
+ if payload[:exception_object]
25
25
  span.set_error(payload[:exception_object])
26
26
  elsif payload[:exception]
27
27
  # Fallback for ActiveSupport < 5.0
@@ -24,7 +24,7 @@ module Datadog
24
24
  sections_view[-1]
25
25
  end
26
26
  rescue
27
- return name.to_s
27
+ name.to_s
28
28
  end
29
29
  end
30
30
  end
@@ -6,36 +6,119 @@ module Datadog
6
6
  module ActiveRecord
7
7
  module Configuration
8
8
  # Converts Symbols, Strings, and Hashes to a normalized connection settings Hash.
9
+ #
10
+ # When matching using a Hash, these are the valid fields:
11
+ # ```
12
+ # {
13
+ # adapter: ...,
14
+ # host: ...,
15
+ # port: ...,
16
+ # database: ...,
17
+ # username: ...,
18
+ # role: ...,
19
+ # }
20
+ # ```
21
+ #
22
+ # Partial matching is supported: not including certain fields or setting them to `nil`
23
+ # will cause them to matching all values for that field. For example: `database: nil`
24
+ # will match any database, given the remaining fields match.
25
+ #
26
+ # Any fields not listed above are discarded.
27
+ #
28
+ # When more than one configuration could be matched, the last one to match is selected,
29
+ # based on addition order (`#add`).
9
30
  class Resolver < Contrib::Configuration::Resolver
10
- def initialize(configurations = nil)
11
- @configurations = configurations
31
+ def initialize(active_record_configuration = nil)
32
+ super()
33
+
34
+ @active_record_configuration = active_record_configuration
12
35
  end
13
36
 
14
- def resolve(key)
15
- normalize(connection_resolver.resolve(key).symbolize_keys)
37
+ def active_record_configuration
38
+ @active_record_configuration || ::ActiveRecord::Base.configurations
16
39
  end
17
40
 
18
- def configurations
19
- @configurations || ::ActiveRecord::Base.configurations
41
+ def add(matcher, value)
42
+ parsed = parse_matcher(matcher)
43
+
44
+ # In case of error parsing, don't store `nil` key
45
+ # as it wouldn't be useful for matching configuration
46
+ # hashes in `#resolve`.
47
+ super(parsed, value) if parsed
20
48
  end
21
49
 
22
- def connection_resolver
23
- @resolver ||= begin
24
- if defined?(::ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver)
25
- ::ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver.new(configurations)
26
- else
27
- ::Datadog::Vendor::ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver.new(configurations)
50
+ def resolve(db_config)
51
+ active_record_config = resolve_connection_key(db_config).symbolize_keys
52
+
53
+ hash = normalize(active_record_config)
54
+
55
+ # Hashes in Ruby maintain insertion order
56
+ _, config = @configurations.reverse_each.find do |matcher, _|
57
+ matcher.none? do |key, value|
58
+ value != hash[key]
28
59
  end
29
60
  end
61
+
62
+ config
63
+ rescue => e
64
+ Datadog.logger.error(
65
+ "Failed to resolve ActiveRecord configuration key #{db_config.inspect}. " \
66
+ "Cause: #{e.message} Source: #{e.backtrace.first}"
67
+ )
68
+
69
+ nil
70
+ end
71
+
72
+ protected
73
+
74
+ def parse_matcher(matcher)
75
+ resolved_pattern = resolve_connection_key(matcher).symbolize_keys
76
+ normalized = normalize(resolved_pattern)
77
+
78
+ # Remove empty fields to allow for partial matching
79
+ normalized.reject! { |_, v| v.nil? }
80
+
81
+ normalized
82
+ rescue => e
83
+ Datadog.logger.error(
84
+ "Failed to resolve ActiveRecord configuration key #{matcher.inspect}. " \
85
+ "Cause: #{e.message} Source: #{e.backtrace.first}"
86
+ )
87
+ end
88
+
89
+ def connection_resolver
90
+ @resolver ||= if defined?(::ActiveRecord::Base.configurations.resolve)
91
+ ::ActiveRecord::DatabaseConfigurations.new(active_record_configuration)
92
+ elsif defined?(::ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver)
93
+ ::ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver.new(
94
+ active_record_configuration
95
+ )
96
+ else
97
+ ::Datadog::Vendor::ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver.new(
98
+ active_record_configuration
99
+ )
100
+ end
101
+ end
102
+
103
+ def resolve_connection_key(key)
104
+ result = connection_resolver.resolve(key)
105
+
106
+ if result.respond_to?(:configuration_hash) # Rails >= 6.1
107
+ result.configuration_hash
108
+ else # Rails < 6.1
109
+ result
110
+ end
30
111
  end
31
112
 
32
- def normalize(hash)
113
+ # Extract only fields we'd like to match
114
+ # from the ActiveRecord configuration.
115
+ def normalize(active_record_config)
33
116
  {
34
- adapter: hash[:adapter],
35
- host: hash[:host],
36
- port: hash[:port],
37
- database: hash[:database],
38
- username: hash[:username]
117
+ adapter: active_record_config[:adapter],
118
+ host: active_record_config[:host],
119
+ port: active_record_config[:port],
120
+ database: active_record_config[:database],
121
+ username: active_record_config[:username]
39
122
  }
40
123
  end
41
124
  end
@@ -96,6 +96,7 @@ module Datadog
96
96
  # @return [Hash]
97
97
  def self.default_connection_config
98
98
  return @default_connection_config if instance_variable_defined?(:@default_connection_config)
99
+
99
100
  current_connection_name = if ::ActiveRecord::Base.respond_to?(:connection_specification_name)
100
101
  ::ActiveRecord::Base.connection_specification_name
101
102
  else
@@ -20,7 +20,8 @@ module Datadog
20
20
  module ClassMethods
21
21
  DEFAULT_TRACER = -> { Datadog.tracer }
22
22
 
23
- def subscribe!
23
+ # Publicly exposes protected method `subscribe!`
24
+ def subscribe! # rubocop:disable Lint/UselessMethodDefinition
24
25
  super
25
26
  end
26
27
 
@@ -36,6 +36,7 @@ module Datadog
36
36
  # Should be triggered by the inheriting class.
37
37
  def subscribe!
38
38
  return subscribed? if subscribed? || on_subscribe_block.nil?
39
+
39
40
  on_subscribe_block.call
40
41
  @subscribed = true
41
42
  end
@@ -9,7 +9,8 @@ module Datadog
9
9
  :options
10
10
 
11
11
  def initialize(tracer, span_name, options, &block)
12
- raise ArgumentError, 'Must be given a block!' unless block_given?
12
+ raise ArgumentError, 'Must be given a block!' unless block
13
+
13
14
  @tracer = tracer
14
15
  @span_name = span_name
15
16
  @options = options
@@ -38,21 +39,23 @@ module Datadog
38
39
  end
39
40
 
40
41
  def before_trace(&block)
41
- callbacks.add(:before_trace, &block) if block_given?
42
+ callbacks.add(:before_trace, &block) if block
42
43
  end
43
44
 
44
45
  def after_trace(&block)
45
- callbacks.add(:after_trace, &block) if block_given?
46
+ callbacks.add(:after_trace, &block) if block
46
47
  end
47
48
 
48
49
  def subscribe(pattern)
49
50
  return false if subscribers.key?(pattern)
51
+
50
52
  subscribers[pattern] = ::ActiveSupport::Notifications.subscribe(pattern, self)
51
53
  true
52
54
  end
53
55
 
54
56
  def unsubscribe(pattern)
55
57
  return false unless subscribers.key?(pattern)
58
+
56
59
  ::ActiveSupport::Notifications.unsubscribe(subscribers[pattern])
57
60
  subscribers.delete(pattern)
58
61
  true
@@ -60,7 +63,8 @@ module Datadog
60
63
 
61
64
  def unsubscribe_all
62
65
  return false if subscribers.empty?
63
- subscribers.keys.each { |pattern| unsubscribe(pattern) }
66
+
67
+ subscribers.each_key { |pattern| unsubscribe(pattern) }
64
68
  true
65
69
  end
66
70
 
@@ -131,7 +135,7 @@ module Datadog
131
135
  end
132
136
 
133
137
  def add(key, &block)
134
- blocks_for(key) << block if block_given?
138
+ blocks_for(key) << block if block
135
139
  end
136
140
 
137
141
  def run(event, key, *args)
@@ -32,6 +32,7 @@ module Datadog
32
32
  # cause undesirable service naming, so we exclude them based their auto_instrument? setting.
33
33
  # we also don't want to mix rspec/cucumber integration in as rspec is env we run tests in.
34
34
  next unless integration.klass.auto_instrument?
35
+
35
36
  integrations << integration.name
36
37
  end
37
38
 
@@ -35,6 +35,7 @@ module Datadog
35
35
 
36
36
  available_services.each_with_object([]) do |service, constants|
37
37
  next if ::Aws.autoload?(service)
38
+
38
39
  constants << ::Aws.const_get(service, false).const_get(:Client, false) rescue next
39
40
  end
40
41
  end
@@ -52,6 +52,7 @@ module Datadog
52
52
  ElasticLoadBalancingV2
53
53
  ElasticTranscoder
54
54
  ElasticsearchService
55
+ EventBridge
55
56
  Firehose
56
57
  GameLift
57
58
  Glacier
@@ -98,6 +99,7 @@ module Datadog
98
99
  STS
99
100
  SWF
100
101
  ServiceCatalog
102
+ Schemas
101
103
  Shield
102
104
  SimpleDB
103
105
  Snowball
@@ -3,7 +3,11 @@ require 'ddtrace/contrib/configuration/settings'
3
3
 
4
4
  module Datadog
5
5
  module Contrib
6
- # Defines configurable behavior for integrations
6
+ # Defines configurable behavior for integrations.
7
+ #
8
+ # This module is responsible for coordination between
9
+ # the configuration resolver and default configuration
10
+ # fallback.
7
11
  module Configurable
8
12
  def self.included(base)
9
13
  base.send(:include, InstanceMethods)
@@ -11,66 +15,86 @@ module Datadog
11
15
 
12
16
  # Configurable instance behavior for integrations
13
17
  module InstanceMethods
18
+ # Provides a new configuration instance for this integration.
19
+ #
20
+ # This method normally needs to be overridden for each integration
21
+ # as their settings, defaults and environment variables are
22
+ # specific for each integration.
23
+ #
24
+ # DEV(1.0): Rename to `new_configuration`, make it protected.
25
+ # DEV(1.0):
26
+ # DEV(1.0): This method always provides a new instance of the configuration object for
27
+ # DEV(1.0): the current integration, not the currently effective default configuration.
28
+ # DEV(1.0): This is a misnomer of its function.
29
+ # DEV(1.0):
30
+ # DEV(1.0): Unfortunately, change this would be a breaking change for all custom integrations,
31
+ # DEV(1.0): thus we have to be very intentional with the right time to make this change.
32
+ # DEV(1.0): Currently marking this for a 1.0 milestone.
14
33
  def default_configuration
15
34
  Configuration::Settings.new
16
35
  end
17
36
 
18
- def reset_configuration!
19
- @configurations = nil
20
- @resolver = nil
21
- end
37
+ # Get matching configuration by matcher.
38
+ # If no match, returns the default configuration instance.
39
+ def configuration(matcher = :default)
40
+ return default_configuration_instance if matcher == :default
22
41
 
23
- # Get matching configuration for key.
24
- # If no match, returns default configuration.
25
- def configuration(key = :default)
26
- configurations[configuration_key(key)]
42
+ resolver.get(matcher) || default_configuration_instance
27
43
  end
28
44
 
29
- # If the key has matching configuration explicitly defined for it,
30
- # then return true. Otherwise return false.
31
- # Note: a resolver's resolve method should not return a fallback value
32
- # See: https://github.com/DataDog/dd-trace-rb/issues/1204
33
- def configuration_for?(key)
34
- key = resolver.resolve(key) unless key == :default
35
- configurations.key?(key)
45
+ # Resolves the matching configuration for integration-specific value.
46
+ # If no match, returns the default configuration instance.
47
+ def resolve(value)
48
+ return default_configuration_instance if value == :default
49
+
50
+ resolver.resolve(value) || default_configuration_instance
36
51
  end
37
52
 
53
+ # Returns all registered matchers and their respective configurations.
38
54
  def configurations
39
- @configurations ||= {
40
- default: default_configuration
41
- }
55
+ resolver.configurations.merge(default: default_configuration_instance)
42
56
  end
43
57
 
44
- # Create or update configuration with provided settings.
45
- def configure(key, options = {}, &block)
46
- key ||= :default
47
-
48
- # Get or add the configuration
49
- config = configuration_for?(key) ? configuration(key) : add_configuration(key)
58
+ # Create or update configuration associated with `matcher` with
59
+ # the provided `options` and `&block`.
60
+ def configure(matcher = :default, options = {}, &block)
61
+ config = if matcher == :default
62
+ default_configuration_instance
63
+ else
64
+ # Get or add the configuration
65
+ resolver.get(matcher) || resolver.add(matcher, default_configuration)
66
+ end
50
67
 
51
68
  # Apply the settings
52
69
  config.configure(options, &block)
53
70
  config
54
71
  end
55
72
 
56
- protected
57
-
58
- def resolver
59
- @resolver ||= Configuration::Resolver.new
73
+ # Resets all configuration options
74
+ def reset_configuration!
75
+ @resolver = nil
76
+ @default_configuration = nil
60
77
  end
61
78
 
62
- def add_configuration(key)
63
- resolver.add(key)
64
- config_key = resolver.resolve(key)
65
- configurations[config_key] = default_configuration
66
- end
79
+ protected
67
80
 
68
- def configuration_key(key)
69
- return :default if key.nil? || key == :default
81
+ # DEV(1.0): Rename to `default_configuration`, make it public.
82
+ # DEV(1.0): See comment on `default_configuration` for more information.
83
+ def default_configuration_instance
84
+ @default_configuration ||= default_configuration # rubocop:disable Naming/MemoizedInstanceVariableName
85
+ end
70
86
 
71
- key = resolver.resolve(key)
72
- key = :default unless configurations.key?(key)
73
- key
87
+ # Overridable configuration resolver.
88
+ #
89
+ # This resolver is responsible for performing the matching
90
+ # of `#configure(matcher)` `matcher`s with `value`s provided
91
+ # in subsequent calls to `#resolve(value)`.
92
+ #
93
+ # By default, the `value` in `#resolve(value)` must be equal
94
+ # to the `matcher` object provided in `#configure(matcher)`
95
+ # to retrieve the associated configuration.
96
+ def resolver
97
+ @resolver ||= Configuration::Resolver.new
74
98
  end
75
99
  end
76
100
  end
@@ -1,14 +1,79 @@
1
1
  module Datadog
2
2
  module Contrib
3
3
  module Configuration
4
- # Resolves a configuration key to a Datadog::Contrib::Configuration:Settings object
4
+ # Resolves an integration-specific matcher to an associated
5
+ # object.
6
+ #
7
+ # Integrations that perform any configuration matching
8
+ # based on patterns might want to override this class
9
+ # to provide richer matching. For example, match configuration
10
+ # based on: HTTP request parameters, request headers,
11
+ # async queue name.
12
+ #
13
+ # When overriding this class, for simple use cases, only
14
+ # overriding `#parse_matcher` might suffice. See
15
+ # `#parse_matcher`'s documentation for more information.
5
16
  class Resolver
6
- def resolve(key)
7
- key
17
+ attr_reader :configurations
18
+
19
+ def initialize
20
+ @configurations = {}
21
+ end
22
+
23
+ # Adds a new `matcher`, associating with it a `value`.
24
+ #
25
+ # This `value` is returned when `#resolve` is called
26
+ # with a matching value for this matcher. When multiple
27
+ # matchers would match, `#resolve` returns the latest
28
+ # added one.
29
+ #
30
+ # The `matcher` can be transformed internally by the
31
+ # `#parse_matcher` method before being stored.
32
+ #
33
+ # The `value` can also be retrieved by calling `#get`
34
+ # with the same `matcher` added by this method.
35
+ #
36
+ # @param [Object] matcher integration-specific matcher
37
+ # @param [Object] value arbitrary value to be associated with `matcher`
38
+ def add(matcher, value)
39
+ @configurations[parse_matcher(matcher)] = value
40
+ end
41
+
42
+ # Retrieves the stored value for a `matcher`
43
+ # previously stored by `#add`.
44
+ #
45
+ # @param [Object] matcher integration-specific matcher
46
+ # @return [Object] previously stored `value` from `#add`, or `nil` if not found
47
+ def get(matcher)
48
+ @configurations[parse_matcher(matcher)]
49
+ end
50
+
51
+ # Matches an arbitrary value against the configured
52
+ # matchers previously set with `#add`.
53
+ #
54
+ # If multiple matchers would match, returns the latest one.
55
+ #
56
+ # @param [Object] value integration-specific value
57
+ # @return [Object] matching `value` configured at `#add`, or `nil` if none match
58
+ def resolve(value)
59
+ @configurations[value]
8
60
  end
9
61
 
10
- def add(key)
11
- key
62
+ protected
63
+
64
+ # Converts `matcher` into an appropriate key
65
+ # for the internal Hash storage.
66
+ #
67
+ # It's recommended to override this method,
68
+ # instead of the public methods, if the
69
+ # integration can simply convert both
70
+ # `matcher` (provided to `#add`) and `value`
71
+ # (provided to `#resolve`) to the same value.
72
+ #
73
+ # @param [Object] matcher integration-specific matcher
74
+ # @return [Object] processed matcher
75
+ def parse_matcher(matcher)
76
+ matcher
12
77
  end
13
78
  end
14
79
  end