ddtrace 0.13.2 → 0.14.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +10 -0
  3. data/Appraisals +12 -0
  4. data/CHANGELOG.md +16 -5
  5. data/Rakefile +18 -1
  6. data/docs/GettingStarted.md +63 -0
  7. data/lib/ddtrace.rb +3 -1
  8. data/lib/ddtrace/configuration.rb +18 -6
  9. data/lib/ddtrace/contrib/active_record/configuration/resolver.rb +46 -0
  10. data/lib/ddtrace/contrib/active_record/configuration/settings.rb +28 -0
  11. data/lib/ddtrace/contrib/active_record/events/sql.rb +11 -7
  12. data/lib/ddtrace/contrib/active_record/integration.rb +44 -0
  13. data/lib/ddtrace/contrib/active_record/patcher.rb +4 -28
  14. data/lib/ddtrace/contrib/active_record/utils.rb +5 -11
  15. data/lib/ddtrace/contrib/base.rb +4 -3
  16. data/lib/ddtrace/contrib/configurable.rb +55 -0
  17. data/lib/ddtrace/contrib/configuration/option.rb +33 -0
  18. data/lib/ddtrace/contrib/configuration/option_definition.rb +29 -0
  19. data/lib/ddtrace/contrib/configuration/option_definition_set.rb +20 -0
  20. data/lib/ddtrace/contrib/configuration/option_set.rb +8 -0
  21. data/lib/ddtrace/contrib/configuration/options.rb +95 -0
  22. data/lib/ddtrace/contrib/configuration/resolver.rb +12 -0
  23. data/lib/ddtrace/contrib/configuration/settings.rb +35 -0
  24. data/lib/ddtrace/contrib/delayed_job/patcher.rb +41 -0
  25. data/lib/ddtrace/contrib/delayed_job/plugin.rb +43 -0
  26. data/lib/ddtrace/contrib/integration.rb +16 -0
  27. data/lib/ddtrace/contrib/patchable.rb +38 -0
  28. data/lib/ddtrace/contrib/patcher.rb +28 -0
  29. data/lib/ddtrace/contrib/rake/instrumentation.rb +3 -15
  30. data/lib/ddtrace/contrib/registerable.rb +33 -0
  31. data/lib/ddtrace/contrib/resque/resque_job.rb +2 -10
  32. data/lib/ddtrace/contrib/sequel/configuration/settings.rb +13 -0
  33. data/lib/ddtrace/contrib/sequel/database.rb +1 -1
  34. data/lib/ddtrace/contrib/sequel/integration.rb +38 -0
  35. data/lib/ddtrace/contrib/sequel/patcher.rb +4 -20
  36. data/lib/ddtrace/patcher.rb +5 -0
  37. data/lib/ddtrace/propagation/http_propagator.rb +0 -6
  38. data/lib/ddtrace/tracer.rb +17 -5
  39. data/lib/ddtrace/vendor/active_record/connection_specification.rb +301 -0
  40. data/lib/ddtrace/version.rb +3 -3
  41. metadata +24 -4
@@ -9,12 +9,6 @@ module Datadog
9
9
 
10
10
  # inject! popolates the env with span ID, trace ID and sampling priority
11
11
  def self.inject!(context, env)
12
- # Prevent propagation from being attempted if context provided is nil.
13
- if context.nil?
14
- Datadog::Tracer.log.debug('Cannot inject context into env to propagate over HTTP: context is nil.'.freeze)
15
- return
16
- end
17
-
18
12
  env[HTTP_HEADER_TRACE_ID] = context.trace_id.to_s
19
13
  env[HTTP_HEADER_PARENT_ID] = context.span_id.to_s
20
14
  env[HTTP_HEADER_SAMPLING_PRIORITY] = context.sampling_priority.to_s
@@ -24,6 +24,7 @@ module Datadog
24
24
  attr_writer :default_service
25
25
 
26
26
  ALLOWED_SPAN_OPTIONS = [:service, :resource, :span_type].freeze
27
+ DEFAULT_ON_ERROR = proc { |span, error| span.set_error(error) unless span.nil? }
27
28
 
28
29
  # Global, memoized, lazy initialized instance of a logger that is used within the the Datadog
29
30
  # namespace. This logger outputs to +STDOUT+ by default, and is considered thread-safe.
@@ -277,14 +278,23 @@ module Datadog
277
278
  # * +tags+: extra tags which should be added to the span.
278
279
  def trace(name, options = {})
279
280
  options[:child_of] = call_context
280
- span = start_span(name, options)
281
281
 
282
282
  # call the finish only if a block is given; this ensures
283
283
  # that a call to tracer.trace() without a block, returns
284
284
  # a span that should be manually finished.
285
285
  if block_given?
286
+ span = nil
287
+ return_value = nil
288
+
286
289
  begin
287
- yield(span)
290
+ begin
291
+ span = start_span(name, options)
292
+ # rubocop:disable Lint/UselessAssignment
293
+ rescue StandardError => e
294
+ Datadog::Tracer.log.debug('Failed to start span: #{e}')
295
+ ensure
296
+ return_value = yield(span)
297
+ end
288
298
  # rubocop:disable Lint/RescueException
289
299
  # Here we really want to catch *any* exception, not only StandardError,
290
300
  # as we really have no clue of what is in the block,
@@ -292,13 +302,15 @@ module Datadog
292
302
  # It's not a problem since we re-raise it afterwards so for example a
293
303
  # SignalException::Interrupt would still bubble up.
294
304
  rescue Exception => e
295
- span.set_error(e)
305
+ (options[:on_error] || DEFAULT_ON_ERROR).call(span, e)
296
306
  raise e
297
307
  ensure
298
- span.finish()
308
+ span.finish unless span.nil?
299
309
  end
310
+
311
+ return_value
300
312
  else
301
- span
313
+ start_span(name, options)
302
314
  end
303
315
  end
304
316
 
@@ -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
@@ -1,9 +1,9 @@
1
1
  module Datadog
2
2
  module VERSION
3
3
  MAJOR = 0
4
- MINOR = 13
5
- PATCH = 2
6
- PRE = nil
4
+ MINOR = 14
5
+ PATCH = 0
6
+ PRE = 'beta1'.freeze
7
7
 
8
8
  STRING = [MAJOR, MINOR, PATCH, PRE].compact.join('.')
9
9
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ddtrace
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.2
4
+ version: 0.14.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Datadog, Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-08-07 00:00:00.000000000 Z
11
+ date: 2018-07-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: msgpack
@@ -282,10 +282,13 @@ files:
282
282
  - lib/ddtrace/contrib/active_model_serializers/events/render.rb
283
283
  - lib/ddtrace/contrib/active_model_serializers/events/serialize.rb
284
284
  - lib/ddtrace/contrib/active_model_serializers/patcher.rb
285
+ - lib/ddtrace/contrib/active_record/configuration/resolver.rb
286
+ - lib/ddtrace/contrib/active_record/configuration/settings.rb
285
287
  - lib/ddtrace/contrib/active_record/event.rb
286
288
  - lib/ddtrace/contrib/active_record/events.rb
287
289
  - lib/ddtrace/contrib/active_record/events/instantiation.rb
288
290
  - lib/ddtrace/contrib/active_record/events/sql.rb
291
+ - lib/ddtrace/contrib/active_record/integration.rb
289
292
  - lib/ddtrace/contrib/active_record/patcher.rb
290
293
  - lib/ddtrace/contrib/active_record/utils.rb
291
294
  - lib/ddtrace/contrib/active_support/notifications/event.rb
@@ -296,9 +299,19 @@ files:
296
299
  - lib/ddtrace/contrib/aws/patcher.rb
297
300
  - lib/ddtrace/contrib/aws/services.rb
298
301
  - lib/ddtrace/contrib/base.rb
302
+ - lib/ddtrace/contrib/configurable.rb
303
+ - lib/ddtrace/contrib/configuration/option.rb
304
+ - lib/ddtrace/contrib/configuration/option_definition.rb
305
+ - lib/ddtrace/contrib/configuration/option_definition_set.rb
306
+ - lib/ddtrace/contrib/configuration/option_set.rb
307
+ - lib/ddtrace/contrib/configuration/options.rb
308
+ - lib/ddtrace/contrib/configuration/resolver.rb
309
+ - lib/ddtrace/contrib/configuration/settings.rb
299
310
  - lib/ddtrace/contrib/dalli/instrumentation.rb
300
311
  - lib/ddtrace/contrib/dalli/patcher.rb
301
312
  - lib/ddtrace/contrib/dalli/quantize.rb
313
+ - lib/ddtrace/contrib/delayed_job/patcher.rb
314
+ - lib/ddtrace/contrib/delayed_job/plugin.rb
302
315
  - lib/ddtrace/contrib/elasticsearch/patcher.rb
303
316
  - lib/ddtrace/contrib/elasticsearch/quantize.rb
304
317
  - lib/ddtrace/contrib/excon/middleware.rb
@@ -314,11 +327,14 @@ files:
314
327
  - lib/ddtrace/contrib/grpc/intercept_with_datadog.rb
315
328
  - lib/ddtrace/contrib/grpc/patcher.rb
316
329
  - lib/ddtrace/contrib/http/patcher.rb
330
+ - lib/ddtrace/contrib/integration.rb
317
331
  - lib/ddtrace/contrib/mongodb/parsers.rb
318
332
  - lib/ddtrace/contrib/mongodb/patcher.rb
319
333
  - lib/ddtrace/contrib/mongodb/subscribers.rb
320
334
  - lib/ddtrace/contrib/mysql2/client.rb
321
335
  - lib/ddtrace/contrib/mysql2/patcher.rb
336
+ - lib/ddtrace/contrib/patchable.rb
337
+ - lib/ddtrace/contrib/patcher.rb
322
338
  - lib/ddtrace/contrib/racecar/event.rb
323
339
  - lib/ddtrace/contrib/racecar/events.rb
324
340
  - lib/ddtrace/contrib/racecar/events/batch.rb
@@ -342,10 +358,13 @@ files:
342
358
  - lib/ddtrace/contrib/redis/patcher.rb
343
359
  - lib/ddtrace/contrib/redis/quantize.rb
344
360
  - lib/ddtrace/contrib/redis/tags.rb
361
+ - lib/ddtrace/contrib/registerable.rb
345
362
  - lib/ddtrace/contrib/resque/patcher.rb
346
363
  - lib/ddtrace/contrib/resque/resque_job.rb
364
+ - lib/ddtrace/contrib/sequel/configuration/settings.rb
347
365
  - lib/ddtrace/contrib/sequel/database.rb
348
366
  - lib/ddtrace/contrib/sequel/dataset.rb
367
+ - lib/ddtrace/contrib/sequel/integration.rb
349
368
  - lib/ddtrace/contrib/sequel/patcher.rb
350
369
  - lib/ddtrace/contrib/sequel/utils.rb
351
370
  - lib/ddtrace/contrib/sidekiq/patcher.rb
@@ -392,6 +411,7 @@ files:
392
411
  - lib/ddtrace/transport.rb
393
412
  - lib/ddtrace/utils.rb
394
413
  - lib/ddtrace/utils/database.rb
414
+ - lib/ddtrace/vendor/active_record/connection_specification.rb
395
415
  - lib/ddtrace/version.rb
396
416
  - lib/ddtrace/workers.rb
397
417
  - lib/ddtrace/writer.rb
@@ -411,9 +431,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
411
431
  version: 1.9.1
412
432
  required_rubygems_version: !ruby/object:Gem::Requirement
413
433
  requirements:
414
- - - ">="
434
+ - - ">"
415
435
  - !ruby/object:Gem::Version
416
- version: '0'
436
+ version: 1.3.1
417
437
  requirements: []
418
438
  rubyforge_project:
419
439
  rubygems_version: 2.7.7