ddtrace 0.11.0 → 0.11.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b3bb99f4104ccd84acde3279b412e90d531ecfea
4
- data.tar.gz: 63d063737c4e830b84d24471fc1ff356ca703af6
3
+ metadata.gz: edcd0745f2ad784016b18e4b7e4694e4af12223a
4
+ data.tar.gz: '0952683e8798ee961851a881d0ea4343a121572a'
5
5
  SHA512:
6
- metadata.gz: b271d08b6eae8c40116c68b21ef46c4fb110fba35b331913b902e9fc0b7ce5fa4868e997c7984eff71d8f325f98f3276c6bc11b6da69bdf877903338fb599948
7
- data.tar.gz: d86ca3ce85531ea82e437f2f9495deed831ab10a2e15d35a78a1095607f99c9ef901cb6cf800f084a4f4142f200f339997b60e30fa87b80d66de3c9706f23346
6
+ metadata.gz: 5cae4b99e2e0170f5a7da8a320ae7235ec7cc3431c8dee355a84e921b2f7933bbc2e32058547a8bea6dcbabfe94a4b1aff3bb293d7d059f480fca84f8ca5eb62
7
+ data.tar.gz: b74edf57aeee710af1024f68eee73e804f3bff2cb0ee4426c384b6fc8626f36db85ea7fa95e698d4b3cc32f33ffc78d2e6fdc49368a11a4122cf2a847ebaf9f8
data/Appraisals CHANGED
@@ -114,7 +114,7 @@ end
114
114
  if RUBY_VERSION >= '2.2.2' && RUBY_PLATFORM != 'java'
115
115
  appraise 'contrib' do
116
116
  gem 'elasticsearch-transport'
117
- gem 'mongo'
117
+ gem 'mongo', '< 2.5'
118
118
  gem 'grape'
119
119
  gem 'rack'
120
120
  gem 'rack-test'
@@ -129,11 +129,12 @@ if RUBY_VERSION >= '2.2.2' && RUBY_PLATFORM != 'java'
129
129
  gem 'dalli'
130
130
  gem 'resque', '< 2.0'
131
131
  gem 'racecar', '>= 0.3.5'
132
+ gem 'mysql2', platform: :ruby
132
133
  end
133
134
  else
134
135
  appraise 'contrib-old' do
135
136
  gem 'elasticsearch-transport'
136
- gem 'mongo'
137
+ gem 'mongo', '< 2.5'
137
138
  gem 'redis', '< 4.0'
138
139
  gem 'hiredis'
139
140
  gem 'rack', '1.4.7'
@@ -146,5 +147,7 @@ else
146
147
  gem 'sucker_punch'
147
148
  gem 'dalli'
148
149
  gem 'resque', '< 2.0'
150
+ gem 'mysql2', '0.3.21', platform: :ruby
151
+ gem 'activerecord-mysql-adapter', platform: :ruby
149
152
  end
150
153
  end
data/README.md CHANGED
@@ -75,7 +75,10 @@ you can activate it. The example above would become:
75
75
  require 'sinatra'
76
76
  require 'active_record'
77
77
 
78
- Datadog::Monkey.patch_all # monkey patch all available integrations
78
+ Datadog.configure do |c|
79
+ c.use :sinatra
80
+ c.use :active_record
81
+ end
79
82
 
80
83
  # now write your code naturally, it's traced automatically
81
84
  get '/' do
data/Rakefile CHANGED
@@ -11,11 +11,11 @@ desc 'Run RSpec'
11
11
  namespace :spec do
12
12
  task all: [:main,
13
13
  :rails, :railsredis, :railssidekiq, :railsactivejob,
14
- :elasticsearch, :http, :redis, :sidekiq, :sinatra, :monkey]
14
+ :elasticsearch, :http, :redis, :sidekiq, :sinatra]
15
15
 
16
16
  RSpec::Core::RakeTask.new(:main) do |t|
17
17
  t.pattern = 'spec/**/*_spec.rb'
18
- t.exclude_pattern = 'spec/**/{contrib,benchmark,redis}/**/*_spec.rb,spec/monkey_spec.rb'
18
+ t.exclude_pattern = 'spec/**/{contrib,benchmark,redis}/**/*_spec.rb'
19
19
  end
20
20
 
21
21
  RSpec::Core::RakeTask.new(:rails) do |t|
@@ -53,30 +53,26 @@ namespace :spec do
53
53
  :mongodb,
54
54
  :racecar,
55
55
  :resque,
56
+ :active_record,
56
57
  :dalli
57
58
  ].each do |contrib|
58
59
  RSpec::Core::RakeTask.new(contrib) do |t|
59
60
  t.pattern = "spec/ddtrace/contrib/#{contrib}/*_spec.rb"
60
61
  end
61
62
  end
62
-
63
- RSpec::Core::RakeTask.new(:monkey) do |t|
64
- t.pattern = 'spec/ddtrace/monkey_spec.rb'
65
- end
66
63
  end
67
64
 
68
65
  namespace :test do
69
66
  task all: [:main,
70
67
  :rails, :railsredis, :railssidekiq, :railsactivejob,
71
- :elasticsearch, :http, :redis, :sidekiq, :sinatra, :monkey]
68
+ :elasticsearch, :http, :redis, :sidekiq, :sinatra]
72
69
 
73
70
  Rake::TestTask.new(:main) do |t|
74
71
  t.libs << %w[test lib]
75
72
  t.test_files = FileList['test/**/*_test.rb'].reject do |path|
76
73
  path.include?('contrib') ||
77
74
  path.include?('benchmark') ||
78
- path.include?('redis') ||
79
- path.include?('monkey_test.rb')
75
+ path.include?('redis')
80
76
  end
81
77
  end
82
78
 
@@ -129,11 +125,6 @@ namespace :test do
129
125
  t.test_files = FileList["test/contrib/#{contrib}/*_test.rb"]
130
126
  end
131
127
  end
132
-
133
- Rake::TestTask.new(:monkey) do |t|
134
- t.libs << %w[test lib]
135
- t.test_files = FileList['test/monkey_test.rb']
136
- end
137
128
  end
138
129
 
139
130
  Rake::TestTask.new(:benchmark) do |t|
@@ -219,7 +210,6 @@ task :ci do
219
210
  sh 'rvm $MRI_VERSIONS --verbose do appraisal contrib rake test:mongodb'
220
211
  sh 'rvm $MRI_VERSIONS --verbose do appraisal contrib rake test:sucker_punch'
221
212
  sh 'rvm $MRI_VERSIONS --verbose do appraisal contrib rake test:resque'
222
- sh 'rvm $MRI_OLD_VERSIONS --verbose do appraisal contrib-old rake test:monkey'
223
213
  sh 'rvm $MRI_OLD_VERSIONS --verbose do appraisal contrib-old rake test:elasticsearch'
224
214
  sh 'rvm $MRI_OLD_VERSIONS --verbose do appraisal contrib-old rake test:http'
225
215
  sh 'rvm $MRI_OLD_VERSIONS --verbose do appraisal contrib-old rake test:redis'
@@ -231,9 +221,11 @@ task :ci do
231
221
  sh 'rvm $MRI_OLD_VERSIONS --verbose do appraisal contrib-old rake test:sucker_punch'
232
222
  sh 'rvm $MRI_OLD_VERSIONS --verbose do appraisal contrib-old rake test:resque'
233
223
  # RSpec
224
+ sh 'rvm $MRI_VERSIONS --verbose do appraisal contrib rake spec:active_record'
234
225
  sh 'rvm $MRI_VERSIONS --verbose do appraisal contrib rake spec:dalli'
235
226
  sh 'rvm $MRI_VERSIONS --verbose do appraisal contrib rake spec:racecar'
236
227
  sh 'rvm $MRI_OLD_VERSIONS --verbose do appraisal contrib-old rake spec:dalli'
228
+ sh 'rvm $MRI_OLD_VERSIONS --verbose do appraisal contrib-old rake spec:active_record'
237
229
  when 2
238
230
  sh 'rvm $MRI_VERSIONS --verbose do appraisal contrib rake test:sidekiq'
239
231
  sh 'rvm $SIDEKIQ_OLD_VERSIONS --verbose do appraisal contrib-old rake test:sidekiq'
@@ -77,7 +77,8 @@ Where `options` is an optional `Hash` that accepts the following parameters:
77
77
  | ``service_name`` | Service name used when tracing application requests (on the `rack` level) | ``<app_name>`` (inferred from your Rails application namespace) |
78
78
  | ``controller_service`` | Service name used when tracing a Rails action controller | ``<app_name>-controller`` |
79
79
  | ``cache_service`` | Cache service name used when tracing cache activity | ``<app_name>-cache`` |
80
- | ``database_service`` | Database service name used when tracing database activity | ``<app_name>-<adapter_name>``. |
80
+ | ``database_service`` | Database service name used when tracing database activity | ``<app_name>-<adapter_name>`` |
81
+ | ``exception_controller`` | Class or Module which identifies a custom exception controller class. Tracer provides improved error behavior when it can identify custom exception controllers. By default, without this option, it 'guesses' what a custom exception controller looks like. Providing this option aids this identification. | ``nil`` |
81
82
  | ``distributed_tracing`` | Enables [distributed tracing](#Distributed_Tracing) so that this service trace is connected with a trace of another service if tracing headers are received | `false` |
82
83
  | ``template_base_path`` | Used when the template name is parsed. If you don't store your templates in the ``views/`` folder, you may need to change this value | ``views/`` |
83
84
  | ``tracer`` | A ``Datadog::Tracer`` instance used to instrument the application. Usually you don't need to set that. | ``Datadog.tracer`` |
@@ -107,6 +108,7 @@ Where `options` is an optional `Hash` that accepts the following parameters:
107
108
  | --- | --- | --- |
108
109
  | ``service_name`` | Service name used for `sinatra` instrumentation | sinatra |
109
110
  | ``resource_script_names`` | Prepend resource names with script name | ``false`` |
111
+ | ``distributed_tracing`` | Enables [distributed tracing](#Distributed_Tracing) so that this service trace is connected with a trace of another service if tracing headers are received | `false` |
110
112
  | ``tracer`` | A ``Datadog::Tracer`` instance used to instrument the application. Usually you don't need to set that. | ``Datadog.tracer`` |
111
113
 
112
114
  ### Rack
@@ -4,7 +4,7 @@ source "https://rubygems.org"
4
4
 
5
5
  gem "pry-nav", git: "https://github.com/nixme/pry-nav.git", branch: "master"
6
6
  gem "elasticsearch-transport"
7
- gem "mongo"
7
+ gem "mongo", "< 2.5"
8
8
  gem "grape"
9
9
  gem "rack"
10
10
  gem "rack-test"
@@ -19,5 +19,6 @@ gem "sucker_punch"
19
19
  gem "dalli"
20
20
  gem "resque", "< 2.0"
21
21
  gem "racecar", ">= 0.3.5"
22
+ gem "mysql2", platform: :ruby
22
23
 
23
24
  gemspec path: "../"
@@ -4,7 +4,7 @@ source "https://rubygems.org"
4
4
 
5
5
  gem "pry-nav", git: "https://github.com/nixme/pry-nav.git", branch: "master"
6
6
  gem "elasticsearch-transport"
7
- gem "mongo"
7
+ gem "mongo", "< 2.5"
8
8
  gem "redis", "< 4.0"
9
9
  gem "hiredis"
10
10
  gem "rack", "1.4.7"
@@ -17,5 +17,7 @@ gem "aws-sdk", "~> 2.0"
17
17
  gem "sucker_punch"
18
18
  gem "dalli"
19
19
  gem "resque", "< 2.0"
20
+ gem "mysql2", "0.3.21", platform: :ruby
21
+ gem "activerecord-mysql-adapter", platform: :ruby
20
22
 
21
23
  gemspec path: "../"
data/lib/ddtrace.rb CHANGED
@@ -1,9 +1,12 @@
1
+ require 'thread'
2
+
1
3
  require 'ddtrace/registry'
2
4
  require 'ddtrace/pin'
3
5
  require 'ddtrace/tracer'
4
6
  require 'ddtrace/error'
5
7
  require 'ddtrace/pipeline'
6
8
  require 'ddtrace/configuration'
9
+ require 'ddtrace/patcher'
7
10
 
8
11
  # \Datadog global namespace that includes all tracing functionality for Tracer and Span classes.
9
12
  module Datadog
@@ -49,8 +52,19 @@ module Datadog
49
52
  end
50
53
  end
51
54
 
52
- # Monkey currently is responsible for loading all contributions, which in turn
53
- # rely on the registry defined above. We should make our code less dependent on
54
- # the load order, by letting things be lazily loaded while keeping
55
- # thread-safety.
56
- require 'ddtrace/monkey'
55
+ require 'ddtrace/contrib/base'
56
+ require 'ddtrace/contrib/rack/patcher'
57
+ require 'ddtrace/contrib/rails/patcher'
58
+ require 'ddtrace/contrib/active_record/patcher'
59
+ require 'ddtrace/contrib/elasticsearch/patcher'
60
+ require 'ddtrace/contrib/faraday/patcher'
61
+ require 'ddtrace/contrib/grape/patcher'
62
+ require 'ddtrace/contrib/redis/patcher'
63
+ require 'ddtrace/contrib/http/patcher'
64
+ require 'ddtrace/contrib/aws/patcher'
65
+ require 'ddtrace/contrib/sucker_punch/patcher'
66
+ require 'ddtrace/contrib/mongodb/patcher'
67
+ require 'ddtrace/contrib/dalli/patcher'
68
+ require 'ddtrace/contrib/resque/patcher'
69
+ require 'ddtrace/contrib/racecar/patcher'
70
+ require 'ddtrace/contrib/sidekiq/patcher'
@@ -2,11 +2,11 @@ module Datadog
2
2
  module Contrib
3
3
  module ActiveRecord
4
4
  # Patcher enables patching of 'active_record' module.
5
- # This is used in monkey.rb to manually apply patches
6
5
  module Patcher
7
6
  include Base
8
7
  register_as :active_record, auto_patch: false
9
8
  option :service_name
9
+ option :tracer, default: Datadog.tracer
10
10
 
11
11
  @patched = false
12
12
 
@@ -58,22 +58,18 @@ module Datadog
58
58
  @adapter_port ||= Datadog::Contrib::Rails::Utils.adapter_port
59
59
  end
60
60
 
61
- def self.tracer
62
- @tracer ||= Datadog.configuration[:sinatra][:tracer]
63
- end
64
-
65
61
  def self.database_service
66
62
  return @database_service if defined?(@database_service)
67
63
 
68
64
  @database_service = get_option(:service_name) || adapter_name
69
- tracer.set_service_info(@database_service, 'sinatra', Ext::AppTypes::DB)
65
+ get_option(:tracer).set_service_info(@database_service, 'active_record', Ext::AppTypes::DB)
70
66
  @database_service
71
67
  end
72
68
 
73
69
  def self.sql(_name, start, finish, _id, payload)
74
70
  span_type = Datadog::Ext::SQL::TYPE
75
71
 
76
- span = tracer.trace(
72
+ span = get_option(:tracer).trace(
77
73
  "#{adapter_name}.query",
78
74
  resource: payload.fetch(:sql),
79
75
  service: database_service,
@@ -8,6 +8,7 @@ module Datadog
8
8
  def self.included(base)
9
9
  base.send(:include, Registry::Registerable)
10
10
  base.send(:include, Configurable)
11
+ base.send(:include, Patcher)
11
12
  end
12
13
  end
13
14
  end
@@ -11,7 +11,6 @@ module Datadog
11
11
  SERVICE = 'elasticsearch'.freeze
12
12
 
13
13
  # Patcher enables patching of 'elasticsearch/transport' module.
14
- # This is used in monkey.rb to automatically apply patches
15
14
  module Patcher
16
15
  include Base
17
16
  register_as :elasticsearch, auto_patch: true
@@ -28,7 +27,6 @@ module Datadog
28
27
  begin
29
28
  require 'uri'
30
29
  require 'json'
31
- require 'ddtrace/monkey'
32
30
  require 'ddtrace/pin'
33
31
  require 'ddtrace/ext/app_types'
34
32
  require 'ddtrace/contrib/elasticsearch/quantize'
@@ -49,7 +47,7 @@ module Datadog
49
47
  # rubocop:disable Metrics/BlockLength
50
48
  ::Elasticsearch::Transport::Client.class_eval do
51
49
  alias_method :initialize_without_datadog, :initialize
52
- Datadog::Monkey.without_warnings do
50
+ Datadog::Patcher.without_warnings do
53
51
  remove_method :initialize
54
52
  end
55
53
 
@@ -44,7 +44,6 @@ module Datadog
44
44
  end
45
45
 
46
46
  # Patcher enables patching of 'net/http' module.
47
- # This is used in monkey.rb to automatically apply patches
48
47
  module Patcher
49
48
  include Base
50
49
  register_as :http, auto_patch: true
@@ -60,7 +59,6 @@ module Datadog
60
59
  begin
61
60
  require 'uri'
62
61
  require 'ddtrace/pin'
63
- require 'ddtrace/monkey'
64
62
  require 'ddtrace/ext/app_types'
65
63
  require 'ddtrace/ext/http'
66
64
  require 'ddtrace/ext/net'
@@ -87,7 +85,7 @@ module Datadog
87
85
  def patch_http
88
86
  ::Net::HTTP.class_eval do
89
87
  alias_method :initialize_without_datadog, :initialize
90
- Datadog::Monkey.without_warnings do
88
+ Datadog::Patcher.without_warnings do
91
89
  remove_method :initialize
92
90
  end
93
91
 
@@ -8,8 +8,6 @@ module Datadog
8
8
  SERVICE = 'mongodb'.freeze
9
9
 
10
10
  # Patcher adds subscribers to the MongoDB driver so that each command is traced.
11
- # Use the `Datadog::Monkey.patch_module(:mongodb)` to activate tracing for
12
- # this module.
13
11
  module Patcher
14
12
  include Base
15
13
  register_as :mongo, auto_patch: true
@@ -57,7 +55,7 @@ module Datadog
57
55
  def patch_mongo_client
58
56
  ::Mongo::Client.class_eval do
59
57
  alias_method :initialize_without_datadog, :initialize
60
- Datadog::Monkey.without_warnings do
58
+ Datadog::Patcher.without_warnings do
61
59
  remove_method :initialize
62
60
  end
63
61
 
@@ -16,10 +16,8 @@ module Datadog
16
16
  def patch
17
17
  return patched? if patched? || !compatible?
18
18
 
19
- ::ActiveSupport::Notifications.subscribe('start_process_batch.racecar', &method(:start))
20
- ::ActiveSupport::Notifications.subscribe('start_process_message.racecar', &method(:start))
21
- ::ActiveSupport::Notifications.subscribe('process_batch.racecar', &method(:finish))
22
- ::ActiveSupport::Notifications.subscribe('process_message.racecar', &method(:finish))
19
+ ::ActiveSupport::Notifications.subscribe('process_batch.racecar', self)
20
+ ::ActiveSupport::Notifications.subscribe('process_message.racecar', self)
23
21
 
24
22
  configuration[:tracer].set_service_info(
25
23
  configuration[:service_name],
@@ -35,17 +33,7 @@ module Datadog
35
33
  @patched = false
36
34
  end
37
35
 
38
- private
39
-
40
- def configuration
41
- Datadog.configuration[:racecar]
42
- end
43
-
44
- def compatible?
45
- defined?(::Racecar) && defined?(::ActiveSupport::Notifications)
46
- end
47
-
48
- def start(event, *_, payload)
36
+ def start(event, _, payload)
49
37
  ensure_clean_context!
50
38
 
51
39
  name = event[/message/] ? NAME_MESSAGE : NAME_BATCH
@@ -60,7 +48,7 @@ module Datadog
60
48
  span.set_tag('kafka.message_count', payload[:message_count]) if payload.key?(:message_count)
61
49
  end
62
50
 
63
- def finish(*_, payload)
51
+ def finish(_, _, payload)
64
52
  current_span = configuration[:tracer].call_context.current_span
65
53
 
66
54
  return unless current_span
@@ -69,6 +57,16 @@ module Datadog
69
57
  current_span.finish
70
58
  end
71
59
 
60
+ private
61
+
62
+ def configuration
63
+ Datadog.configuration[:racecar]
64
+ end
65
+
66
+ def compatible?
67
+ defined?(::Racecar) && defined?(::ActiveSupport::Notifications)
68
+ end
69
+
72
70
  def ensure_clean_context!
73
71
  return unless configuration[:tracer].call_context.current_span
74
72
 
@@ -20,16 +20,14 @@ module Datadog
20
20
  def call(env)
21
21
  # retrieve integration settings
22
22
  tracer = Datadog.configuration[:rack][:tracer]
23
- service = Datadog.configuration[:rack][:service_name]
24
- distributed_tracing = Datadog.configuration[:rack][:distributed_tracing]
25
23
 
26
24
  trace_options = {
27
- service: service,
25
+ service: Datadog.configuration[:rack][:service_name],
28
26
  resource: nil,
29
27
  span_type: Datadog::Ext::HTTP::TYPE
30
28
  }
31
29
 
32
- if distributed_tracing
30
+ if Datadog.configuration[:rack][:distributed_tracing]
33
31
  context = HTTPPropagator.extract(env)
34
32
  tracer.provider.context = context if context.trace_id
35
33
  end
@@ -56,35 +54,13 @@ module Datadog
56
54
  request_span.set_error(e) unless request_span.nil?
57
55
  raise e
58
56
  ensure
59
- # the source of truth in Rack is the PATH_INFO key that holds the
60
- # URL for the current request; some framework may override that
61
- # value, especially during exception handling and because of that
62
- # we prefer using the `REQUEST_URI` if this is available.
63
- # NOTE: `REQUEST_URI` is Rails specific and may not apply for other frameworks
64
- url = env['REQUEST_URI'] || env['PATH_INFO']
65
-
66
57
  # Rack is a really low level interface and it doesn't provide any
67
58
  # advanced functionality like routers. Because of that, we assume that
68
59
  # the underlying framework or application has more knowledge about
69
60
  # the result for this request; `resource` and `tags` are expected to
70
61
  # be set in another level but if they're missing, reasonable defaults
71
62
  # are used.
72
- request_span.resource ||= resource_name_for(env, status)
73
- if request_span.get_tag(Datadog::Ext::HTTP::METHOD).nil?
74
- request_span.set_tag(Datadog::Ext::HTTP::METHOD, env['REQUEST_METHOD'])
75
- end
76
- if request_span.get_tag(Datadog::Ext::HTTP::URL).nil?
77
- request_span.set_tag(Datadog::Ext::HTTP::URL, url)
78
- end
79
- if request_span.get_tag(Datadog::Ext::HTTP::STATUS_CODE).nil? && status
80
- request_span.set_tag(Datadog::Ext::HTTP::STATUS_CODE, status)
81
- end
82
-
83
- # detect if the status code is a 5xx and flag the request span as an error
84
- # unless it has been already set by the underlying framework
85
- if status.to_s.start_with?('5') && request_span.status.zero?
86
- request_span.status = 1
87
- end
63
+ set_request_tags!(request_span, env, status, headers, response)
88
64
 
89
65
  # ensure the request_span is finished and the context reset;
90
66
  # this assumes that the Rack middleware creates a root span
@@ -103,6 +79,44 @@ module Datadog
103
79
  "#{env['REQUEST_METHOD']} #{status}".strip
104
80
  end
105
81
  end
82
+
83
+ def set_request_tags!(request_span, env, status, headers, response)
84
+ # the source of truth in Rack is the PATH_INFO key that holds the
85
+ # URL for the current request; some framework may override that
86
+ # value, especially during exception handling and because of that
87
+ # we prefer using the `REQUEST_URI` if this is available.
88
+ # NOTE: `REQUEST_URI` is Rails specific and may not apply for other frameworks
89
+ url = env['REQUEST_URI'] || env['PATH_INFO']
90
+
91
+ request_span.resource ||= resource_name_for(env, status)
92
+ if request_span.get_tag(Datadog::Ext::HTTP::METHOD).nil?
93
+ request_span.set_tag(Datadog::Ext::HTTP::METHOD, env['REQUEST_METHOD'])
94
+ end
95
+ if request_span.get_tag(Datadog::Ext::HTTP::URL).nil?
96
+ request_span.set_tag(Datadog::Ext::HTTP::URL, url)
97
+ end
98
+ if request_span.get_tag(Datadog::Ext::HTTP::BASE_URL).nil?
99
+ request_obj = ::Rack::Request.new(env)
100
+
101
+ base_url = if request_obj.respond_to?(:base_url)
102
+ request_obj.base_url
103
+ else
104
+ # Compatibility for older Rack versions
105
+ request_obj.url.chomp(request_obj.fullpath)
106
+ end
107
+
108
+ request_span.set_tag(Datadog::Ext::HTTP::BASE_URL, base_url)
109
+ end
110
+ if request_span.get_tag(Datadog::Ext::HTTP::STATUS_CODE).nil? && status
111
+ request_span.set_tag(Datadog::Ext::HTTP::STATUS_CODE, status)
112
+ end
113
+
114
+ # detect if the status code is a 5xx and flag the request span as an error
115
+ # unless it has been already set by the underlying framework
116
+ if status.to_s.start_with?('5') && request_span.status.zero?
117
+ request_span.status = 1
118
+ end
119
+ end
106
120
  end
107
121
  end
108
122
  end
@@ -32,12 +32,15 @@ module Datadog
32
32
  return unless span && !span.finished?
33
33
 
34
34
  begin
35
- resource = "#{payload.fetch(:controller)}##{payload.fetch(:action)}"
36
- span.resource = resource
35
+ # Set the resource name, if it's still the default name
36
+ if span.resource == span.name
37
+ span.resource = "#{payload.fetch(:controller)}##{payload.fetch(:action)}"
38
+ end
37
39
 
38
- # set the parent resource if it's a `rack.request` span
39
- if !span.parent.nil? && span.parent.name == 'rack.request'
40
- span.parent.resource = resource
40
+ # Set the parent resource if it's a `rack.request` span,
41
+ # but not if its an exception contoller.
42
+ if !span.parent.nil? && span.parent.name == 'rack.request' && !exception_controller?(payload)
43
+ span.parent.resource = span.resource
41
44
  end
42
45
 
43
46
  span.set_tag('rails.route.action', payload.fetch(:action))
@@ -64,6 +67,26 @@ module Datadog
64
67
  rescue StandardError => e
65
68
  Datadog::Tracer.log.error(e.message)
66
69
  end
70
+
71
+ def self.exception_controller?(payload)
72
+ exception_controller_class = Datadog.configuration[:rails][:exception_controller]
73
+ controller = payload.fetch(:controller)
74
+ headers = payload.fetch(:headers)
75
+
76
+ # If no exception controller class has been set,
77
+ # guess whether this is an exception controller from the headers.
78
+ if exception_controller_class.nil?
79
+ !headers[:request_exception].nil?
80
+ # If an exception controller class has been specified,
81
+ # check if the controller is a kind of the exception controller class.
82
+ elsif exception_controller_class.is_a?(Class) || exception_controller_class.is_a?(Module)
83
+ controller <= exception_controller_class
84
+ # Otherwise if the exception controller class is some other value (like false)
85
+ # assume that this controller doesn't handle exceptions.
86
+ else
87
+ false
88
+ end
89
+ end
67
90
  end
68
91
  end
69
92
  end
@@ -150,8 +150,13 @@ module Datadog
150
150
  # signals; it propagates the request span so that it can be finished
151
151
  # no matter what
152
152
  payload = {
153
- controller: self.class.name,
153
+ controller: self.class,
154
154
  action: action_name,
155
+ headers: {
156
+ # The exception this controller was given in the request,
157
+ # which is typical if the controller is configured to handle exceptions.
158
+ request_exception: request.headers['action_dispatch.exception']
159
+ },
155
160
  tracing_context: {}
156
161
  }
157
162
 
@@ -12,6 +12,7 @@ module Datadog
12
12
  option :database_service
13
13
  option :distributed_tracing, default: false
14
14
  option :template_base_path, default: 'views/'
15
+ option :exception_controller, default: nil
15
16
  option :tracer, default: Datadog.tracer
16
17
 
17
18
  @patched = false
@@ -7,7 +7,6 @@ module Datadog
7
7
  DRIVER = 'redis.driver'.freeze
8
8
 
9
9
  # Patcher enables patching of 'redis' module.
10
- # This is used in monkey.rb to automatically apply patches
11
10
  module Patcher
12
11
  include Base
13
12
  register_as :redis, auto_patch: true
@@ -23,7 +22,6 @@ module Datadog
23
22
  if !@patched && compatible?
24
23
  begin
25
24
  # do not require these by default, but only when actually patching
26
- require 'ddtrace/monkey'
27
25
  require 'ddtrace/ext/app_types'
28
26
  require 'ddtrace/contrib/redis/tags'
29
27
  require 'ddtrace/contrib/redis/quantize'
@@ -47,7 +45,7 @@ module Datadog
47
45
  def patch_redis_client
48
46
  ::Redis::Client.class_eval do
49
47
  alias_method :initialize_without_datadog, :initialize
50
- Datadog::Monkey.without_warnings do
48
+ Datadog::Patcher.without_warnings do
51
49
  remove_method :initialize
52
50
  end
53
51
 
@@ -4,6 +4,7 @@ require 'sinatra/base'
4
4
  require 'ddtrace/ext/app_types'
5
5
  require 'ddtrace/ext/errors'
6
6
  require 'ddtrace/ext/http'
7
+ require 'ddtrace/propagation/http_propagator'
7
8
 
8
9
  sinatra_vs = Gem::Version.new(Sinatra::VERSION)
9
10
  sinatra_min_vs = Gem::Version.new('1.4.0')
@@ -29,8 +30,8 @@ module Datadog
29
30
  end
30
31
 
31
32
  option :tracer, default: Datadog.tracer
32
-
33
33
  option :resource_script_names, default: false
34
+ option :distributed_tracing, default: false
34
35
 
35
36
  def route(verb, action, *)
36
37
  # Keep track of the route name when the app is instantiated for an
@@ -82,6 +83,12 @@ module Datadog
82
83
  end
83
84
 
84
85
  tracer = Datadog.configuration[:sinatra][:tracer]
86
+ distributed_tracing = Datadog.configuration[:sinatra][:distributed_tracing]
87
+
88
+ if distributed_tracing && tracer.provider.context.trace_id.nil?
89
+ context = HTTPPropagator.extract(request.env)
90
+ tracer.provider.context = context if context.trace_id
91
+ end
85
92
 
86
93
  span = tracer.trace('sinatra.request',
87
94
  service: Datadog.configuration[:sinatra][:service_name],
@@ -4,6 +4,7 @@ module Datadog
4
4
  TYPE = 'http'.freeze
5
5
  TEMPLATE = 'template'.freeze
6
6
  URL = 'http.url'.freeze
7
+ BASE_URL = 'http.base_url'.freeze
7
8
  METHOD = 'http.method'.freeze
8
9
  STATUS_CODE = 'http.status_code'.freeze
9
10
  ERROR_RANGE = 500...600
@@ -0,0 +1,18 @@
1
+ module Datadog
2
+ # Defines some useful patching methods for integrations
3
+ module Patcher
4
+ module_function
5
+
6
+ def without_warnings
7
+ # This is typically used when monkey patching functions such as
8
+ # intialize, which Ruby advices you not to. Use cautiously.
9
+ v = $VERBOSE
10
+ $VERBOSE = nil
11
+ begin
12
+ yield
13
+ ensure
14
+ $VERBOSE = v
15
+ end
16
+ end
17
+ end
18
+ end
@@ -2,7 +2,7 @@ module Datadog
2
2
  module VERSION
3
3
  MAJOR = 0
4
4
  MINOR = 11
5
- PATCH = 0
5
+ PATCH = 1
6
6
 
7
7
  STRING = [MAJOR, MINOR, PATCH].compact.join('.')
8
8
  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.11.0
4
+ version: 0.11.1
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-01-17 00:00:00.000000000 Z
11
+ date: 2018-01-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: msgpack
@@ -310,7 +310,7 @@ files:
310
310
  - lib/ddtrace/ext/redis.rb
311
311
  - lib/ddtrace/ext/sql.rb
312
312
  - lib/ddtrace/logger.rb
313
- - lib/ddtrace/monkey.rb
313
+ - lib/ddtrace/patcher.rb
314
314
  - lib/ddtrace/pin.rb
315
315
  - lib/ddtrace/pipeline.rb
316
316
  - lib/ddtrace/pipeline/span_filter.rb
@@ -1,88 +0,0 @@
1
- require 'thread'
2
-
3
- # We import all patchers for every module we support, but this is fine
4
- # because patchers do not include any 3rd party module nor even our
5
- # patching code, which is required on demand, when patching.
6
- require 'ddtrace/contrib/base'
7
- require 'ddtrace/contrib/rack/patcher'
8
- require 'ddtrace/contrib/rails/patcher'
9
- require 'ddtrace/contrib/active_record/patcher'
10
- require 'ddtrace/contrib/elasticsearch/patcher'
11
- require 'ddtrace/contrib/faraday/patcher'
12
- require 'ddtrace/contrib/grape/patcher'
13
- require 'ddtrace/contrib/redis/patcher'
14
- require 'ddtrace/contrib/http/patcher'
15
- require 'ddtrace/contrib/aws/patcher'
16
- require 'ddtrace/contrib/sucker_punch/patcher'
17
- require 'ddtrace/contrib/mongodb/patcher'
18
- require 'ddtrace/contrib/dalli/patcher'
19
- require 'ddtrace/contrib/resque/patcher'
20
- require 'ddtrace/contrib/racecar/patcher'
21
- require 'ddtrace/contrib/sidekiq/patcher'
22
-
23
- module Datadog
24
- # Monkey is used for monkey-patching 3rd party libs.
25
- module Monkey
26
- # Patchers should expose 2 methods:
27
- # - patch, which applies our patch if needed. Should be idempotent,
28
- # can be call twice but should just do nothing the second time.
29
- # - patched?, which returns true if the module has been succesfully
30
- # patched (patching might have failed if requirements were not here)
31
-
32
- @mutex = Mutex.new
33
- @registry = Datadog.registry
34
-
35
- module_function
36
-
37
- attr_accessor :registry
38
-
39
- def autopatch_modules
40
- registry.to_h
41
- end
42
-
43
- def patch_all
44
- patch(autopatch_modules)
45
- end
46
-
47
- def patch_module(m)
48
- @mutex.synchronize do
49
- patcher = registry[m]
50
- raise "Unsupported module #{m}" unless patcher
51
- patcher.patch if patcher.respond_to?(:patch)
52
- end
53
- end
54
-
55
- def patch(modules)
56
- modules.each do |k, v|
57
- patch_module(k) if v
58
- end
59
- end
60
-
61
- def get_patched_modules
62
- @mutex.synchronize do
63
- registry.each_with_object({}) do |entry, patched|
64
- next unless entry.klass.respond_to?(:patched?)
65
- patched[entry.name] = entry.klass.patched?
66
- end
67
- end
68
- end
69
-
70
- def without_warnings
71
- # This is typically used when monkey patching functions such as
72
- # intialize, which Ruby advices you not to. Use cautiously.
73
- v = $VERBOSE
74
- $VERBOSE = nil
75
- begin
76
- yield
77
- ensure
78
- $VERBOSE = v
79
- end
80
- end
81
-
82
- class << self
83
- attr_accessor :registry
84
- end
85
- end
86
- end
87
-
88
- Datadog::Monkey.patch_module(:rails)