ddtrace 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,181 @@
1
+
2
+ require 'sinatra/base'
3
+
4
+ require 'ddtrace/ext/app_types'
5
+ require 'ddtrace/ext/errors'
6
+ require 'ddtrace/ext/http'
7
+
8
+ sinatra_vs = Gem::Version.new(Sinatra::VERSION)
9
+ sinatra_min_vs = Gem::Version.new('1.4.0')
10
+ if sinatra_vs < sinatra_min_vs
11
+ raise "sinatra version #{sinatra_vs} is not supported yet " \
12
+ + "(supporting versions >=#{sinatra_min_vs})"
13
+ end
14
+
15
+ Datadog::Tracer.log.info("activating instrumentation for sinatra #{sinatra_vs}")
16
+
17
+ module Datadog
18
+ module Contrib
19
+ module Sinatra
20
+ # TracerCfg is used to manipulate the configuration of the Sinatra
21
+ # tracing extension.
22
+ class TracerCfg
23
+ DEFAULT_CFG = {
24
+ enabled: true,
25
+ default_service: 'sinatra',
26
+ tracer: Datadog.tracer,
27
+ debug: false,
28
+ trace_agent_hostname: Datadog::Writer::HOSTNAME,
29
+ trace_agent_port: Datadog::Writer::PORT
30
+ }.freeze()
31
+
32
+ attr_accessor :cfg
33
+
34
+ def initialize
35
+ @cfg = DEFAULT_CFG.dup()
36
+ end
37
+
38
+ def configure(**args)
39
+ args.each do |name, value|
40
+ self[name] = value
41
+ end
42
+
43
+ apply()
44
+ end
45
+
46
+ def apply
47
+ Datadog::Tracer.debug_logging = @cfg[:debug]
48
+
49
+ tracer = @cfg[:tracer]
50
+
51
+ tracer.enabled = @cfg[:enabled]
52
+ tracer.configure(hostname: @cfg[:trace_agent_hostname],
53
+ port: @cfg[:trace_agent_port])
54
+
55
+ tracer.set_service_info(@cfg[:default_service], 'sinatra',
56
+ Datadog::Ext::AppTypes::WEB)
57
+ end
58
+
59
+ def [](key)
60
+ raise ArgumentError, "unknown setting '#{key}'" unless @cfg.key? key
61
+ @cfg[key]
62
+ end
63
+
64
+ def []=(key, value)
65
+ raise ArgumentError, "unknown setting '#{key}'" unless @cfg.key? key
66
+ @cfg[key] = value
67
+ end
68
+
69
+ def enabled?
70
+ @cfg[:enabled] && @cfg[:tracer]
71
+ end
72
+ end
73
+
74
+ # Datadog::Contrib::Sinatra::Tracer is a Sinatra extension which traces
75
+ # requests.
76
+ module Tracer
77
+ def route(verb, action, *)
78
+ # Keep track of the route name when the app is instantiated for an
79
+ # incoming request.
80
+ condition do
81
+ @datadog_route = action
82
+ end
83
+
84
+ super
85
+ end
86
+
87
+ # rubocop:disable Metrics/AbcSize
88
+ # rubocop:disable Metrics/CyclomaticComplexity
89
+ # rubocop:disable Metrics/MethodLength
90
+ # rubocop:disable Metrics/PerceivedComplexity
91
+ def self.registered(app)
92
+ ::Sinatra::Base.module_eval do
93
+ def render(engine, data, *)
94
+ cfg = settings.datadog_tracer
95
+
96
+ output = ''
97
+ if cfg.enabled?
98
+ tracer = cfg[:tracer]
99
+ tracer.trace('sinatra.render_template') do |span|
100
+ # If data is a string, it is a literal template and we don't
101
+ # want to record it.
102
+ span.set_tag('sinatra.template_name', data) if data.is_a? Symbol
103
+ output = super
104
+ end
105
+ else
106
+ output = super
107
+ end
108
+
109
+ output
110
+ end
111
+ end
112
+
113
+ app.set :datadog_tracer, TracerCfg.new()
114
+
115
+ app.configure do
116
+ app.settings.datadog_tracer.apply()
117
+ end
118
+
119
+ app.before do
120
+ cfg = settings.datadog_tracer
121
+ return unless cfg.enabled?
122
+
123
+ if instance_variable_defined? :@datadog_request_span
124
+ if @datadog_request_span
125
+ Datadog::Tracer.log.error('request span active in :before hook')
126
+ @datadog_request_span.finish()
127
+ @datadog_request_span = nil
128
+ end
129
+ end
130
+
131
+ tracer = cfg[:tracer]
132
+
133
+ span = tracer.trace('sinatra.request',
134
+ service: cfg.cfg[:default_service],
135
+ span_type: Datadog::Ext::HTTP::TYPE)
136
+ span.set_tag(Datadog::Ext::HTTP::URL, request.path)
137
+ span.set_tag(Datadog::Ext::HTTP::METHOD, request.request_method)
138
+
139
+ @datadog_request_span = span
140
+ end
141
+
142
+ app.after do
143
+ cfg = settings.datadog_tracer
144
+ return unless cfg.enabled?
145
+
146
+ span = @datadog_request_span
147
+ begin
148
+ unless span
149
+ Datadog::Tracer.log.error('missing request span in :after hook')
150
+ return
151
+ end
152
+
153
+ span.resource = "#{request.request_method} #{@datadog_route}"
154
+ span.set_tag('sinatra.route.path', @datadog_route)
155
+ span.set_tag(Datadog::Ext::HTTP::STATUS_CODE, response.status)
156
+
157
+ if response.server_error?
158
+ span.status = 1
159
+
160
+ err = env['sinatra.error']
161
+ if err
162
+ span.set_tag(Datadog::Ext::Errors::TYPE, err.class)
163
+ span.set_tag(Datadog::Ext::Errors::MSG, err.message)
164
+ end
165
+ end
166
+
167
+ span.finish()
168
+ ensure
169
+ @datadog_request_span = nil
170
+ end
171
+ end
172
+ end
173
+ end
174
+ end
175
+ end
176
+ end
177
+
178
+ # rubocop:disable Style/Documentation
179
+ module Sinatra
180
+ register Datadog::Contrib::Sinatra::Tracer
181
+ end
@@ -4,19 +4,21 @@ require 'thread'
4
4
  # because patchers do not include any 3rd party module nor even our
5
5
  # patching code, which is required on demand, when patching.
6
6
  require 'ddtrace/contrib/elasticsearch/patcher'
7
+ require 'ddtrace/contrib/http/patcher'
7
8
  require 'ddtrace/contrib/redis/patcher'
8
9
 
9
10
  module Datadog
10
11
  # Monkey is used for monkey-patching 3rd party libs.
11
12
  module Monkey
12
13
  @patched = []
13
- @autopatch_modules = { elasticsearch: true, redis: true }
14
+ @autopatch_modules = { elasticsearch: true, http: true, redis: true }
14
15
  # Patchers should expose 2 methods:
15
16
  # - patch, which applies our patch if needed. Should be idempotent,
16
17
  # can be call twice but should just do nothing the second time.
17
18
  # - patched?, which returns true if the module has been succesfully
18
19
  # patched (patching might have failed if requirements were not here)
19
20
  @patchers = { elasticsearch: Datadog::Contrib::Elasticsearch::Patcher,
21
+ http: Datadog::Contrib::HTTP::Patcher,
20
22
  redis: Datadog::Contrib::Redis::Patcher }
21
23
  @mutex = Mutex.new
22
24
 
@@ -56,5 +58,17 @@ module Datadog
56
58
  end
57
59
  patched
58
60
  end
61
+
62
+ def without_warnings
63
+ # This is typically used when monkey patching functions such as
64
+ # intialize, which Ruby advices you not to. Use cautiously.
65
+ v = $VERBOSE
66
+ $VERBOSE = nil
67
+ begin
68
+ yield
69
+ ensure
70
+ $VERBOSE = v
71
+ end
72
+ end
59
73
  end
60
74
  end
@@ -36,7 +36,7 @@ module Datadog
36
36
  unless obj.respond_to? :datadog_pin=
37
37
  obj.instance_exec do
38
38
  def datadog_pin=(pin)
39
- Datadog::Tracer.log.debug('Set pin #{pin.service} on #{obj.class}.')
39
+ Datadog::Tracer.log.debug("Set pin #{pin.service} on #{self.class}.")
40
40
  @datadog_pin = pin
41
41
  end
42
42
  end
@@ -45,7 +45,7 @@ module Datadog
45
45
  unless obj.respond_to? :datadog_pin
46
46
  obj.instance_exec do
47
47
  def datadog_pin
48
- Datadog::Tracer.log.debug('Get pin from #{obj.class}.')
48
+ Datadog::Tracer.log.debug("Get pin from #{self.class}.")
49
49
  @datadog_pin
50
50
  end
51
51
  end
@@ -67,9 +67,9 @@ module Datadog
67
67
  def set_error(e)
68
68
  return if e.nil?
69
69
  @status = 1
70
- @meta[Datadog::Ext::Errors::MSG] = e.message
70
+ @meta[Datadog::Ext::Errors::MSG] = e.message if e.respond_to?(:message) && e.message
71
71
  @meta[Datadog::Ext::Errors::TYPE] = e.class.to_s
72
- @meta[Datadog::Ext::Errors::STACK] = e.backtrace.join("\n")
72
+ @meta[Datadog::Ext::Errors::STACK] = e.backtrace.join("\n") if e.respond_to?(:backtrace) && e.backtrace
73
73
  end
74
74
 
75
75
  # Mark the span finished at the current time and submit it.
@@ -9,6 +9,7 @@ module Datadog
9
9
  # so that the Transport is thread-safe.
10
10
  class HTTPTransport
11
11
  attr_accessor :hostname, :port
12
+ attr_reader :traces_endpoint, :services_endpoint
12
13
 
13
14
  # seconds before the transport timeout
14
15
  TIMEOUT = 1
@@ -1,8 +1,8 @@
1
1
  module Datadog
2
2
  module VERSION
3
3
  MAJOR = 0
4
- MINOR = 3
5
- PATCH = 1
4
+ MINOR = 4
5
+ PATCH = 0
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.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Datadog, Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-01-23 00:00:00.000000000 Z
11
+ date: 2017-01-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: msgpack
@@ -24,62 +24,48 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: bundler
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '1.12'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '1.12'
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: rake
43
29
  requirement: !ruby/object:Gem::Requirement
44
30
  requirements:
45
31
  - - "~>"
46
32
  - !ruby/object:Gem::Version
47
- version: '10.0'
33
+ version: '12.0'
48
34
  type: :development
49
35
  prerelease: false
50
36
  version_requirements: !ruby/object:Gem::Requirement
51
37
  requirements:
52
38
  - - "~>"
53
39
  - !ruby/object:Gem::Version
54
- version: '10.0'
40
+ version: '12.0'
55
41
  - !ruby/object:Gem::Dependency
56
42
  name: rubocop
57
43
  requirement: !ruby/object:Gem::Requirement
58
44
  requirements:
59
45
  - - "~>"
60
46
  - !ruby/object:Gem::Version
61
- version: '0.43'
47
+ version: '0.47'
62
48
  type: :development
63
49
  prerelease: false
64
50
  version_requirements: !ruby/object:Gem::Requirement
65
51
  requirements:
66
52
  - - "~>"
67
53
  - !ruby/object:Gem::Version
68
- version: '0.43'
54
+ version: '0.47'
69
55
  - !ruby/object:Gem::Dependency
70
56
  name: minitest
71
57
  requirement: !ruby/object:Gem::Requirement
72
58
  requirements:
73
59
  - - "~>"
74
60
  - !ruby/object:Gem::Version
75
- version: '5.0'
61
+ version: '5.10'
76
62
  type: :development
77
63
  prerelease: false
78
64
  version_requirements: !ruby/object:Gem::Requirement
79
65
  requirements:
80
66
  - - "~>"
81
67
  - !ruby/object:Gem::Version
82
- version: '5.0'
68
+ version: '5.10'
83
69
  - !ruby/object:Gem::Dependency
84
70
  name: appraisal
85
71
  requirement: !ruby/object:Gem::Requirement
@@ -131,6 +117,7 @@ files:
131
117
  - lib/ddtrace/contrib/elasticsearch/core.rb
132
118
  - lib/ddtrace/contrib/elasticsearch/patcher.rb
133
119
  - lib/ddtrace/contrib/elasticsearch/quantize.rb
120
+ - lib/ddtrace/contrib/http/patcher.rb
134
121
  - lib/ddtrace/contrib/rails/action_controller.rb
135
122
  - lib/ddtrace/contrib/rails/action_view.rb
136
123
  - lib/ddtrace/contrib/rails/active_record.rb
@@ -138,10 +125,10 @@ files:
138
125
  - lib/ddtrace/contrib/rails/core_extensions.rb
139
126
  - lib/ddtrace/contrib/rails/framework.rb
140
127
  - lib/ddtrace/contrib/rails/utils.rb
141
- - lib/ddtrace/contrib/redis/core.rb
142
128
  - lib/ddtrace/contrib/redis/patcher.rb
143
129
  - lib/ddtrace/contrib/redis/quantize.rb
144
130
  - lib/ddtrace/contrib/redis/tags.rb
131
+ - lib/ddtrace/contrib/sinatra/tracer.rb
145
132
  - lib/ddtrace/encoding.rb
146
133
  - lib/ddtrace/ext/app_types.rb
147
134
  - lib/ddtrace/ext/cache.rb
@@ -180,7 +167,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
180
167
  version: '0'
181
168
  requirements: []
182
169
  rubyforge_project:
183
- rubygems_version: 2.5.2
170
+ rubygems_version: 2.6.9
184
171
  signing_key:
185
172
  specification_version: 4
186
173
  summary: Datadog tracing code for your Ruby applications
@@ -1,72 +0,0 @@
1
- require 'ddtrace/ext/app_types'
2
- require 'ddtrace/contrib/redis/tags'
3
- require 'ddtrace/contrib/redis/quantize'
4
-
5
- module Datadog
6
- module Contrib
7
- module Redis
8
- SERVICE = 'redis'.freeze
9
-
10
- DRIVER = 'redis.driver'.freeze
11
-
12
- # TracedRedis is a wrapper so that caller can pin on parent object without knowing about client member.
13
- module TracedRedis
14
- def datadog_pin=(pin)
15
- # Forward the pin to client, which actually traces calls.
16
- Datadog::Pin.onto(client, pin)
17
- end
18
-
19
- def datadog_pin
20
- # Get the pin from client, which actually traces calls.
21
- Datadog::Pin.get_from(client)
22
- end
23
- end
24
-
25
- # Datadog APM Redis integration.
26
- module TracedRedisClient
27
- def initialize(*args)
28
- pin = Datadog::Pin.new(SERVICE, app: 'redis', app_type: Datadog::Ext::AppTypes::DB)
29
- pin.onto(self)
30
- super(*args)
31
- end
32
-
33
- def call(*args, &block)
34
- pin = Datadog::Pin.get_from(self)
35
- return super(*args, &block) unless pin
36
-
37
- response = nil
38
- pin.tracer.trace('redis.command') do |span|
39
- span.service = pin.service
40
- span.span_type = Datadog::Ext::Redis::TYPE
41
- span.resource = Datadog::Contrib::Redis::Quantize.format_command_args(*args)
42
- span.set_tag(Datadog::Ext::Redis::RAWCMD, span.resource)
43
- Datadog::Contrib::Redis::Tags.set_common_tags(self, span)
44
-
45
- response = super(*args, &block)
46
- end
47
-
48
- response
49
- end
50
-
51
- def call_pipeline(*args, &block)
52
- pin = Datadog::Pin.get_from(self)
53
- return super(*args, &block) unless pin
54
-
55
- response = nil
56
- pin.tracer.trace('redis.command') do |span|
57
- span.service = pin.service
58
- span.span_type = Datadog::Ext::Redis::TYPE
59
- commands = args[0].commands.map { |c| Datadog::Contrib::Redis::Quantize.format_command_args(c) }
60
- span.resource = commands.join("\n")
61
- span.set_tag(Datadog::Ext::Redis::RAWCMD, span.resource)
62
- Datadog::Contrib::Redis::Tags.set_common_tags(self, span)
63
-
64
- response = super(*args, &block)
65
- end
66
-
67
- response
68
- end
69
- end
70
- end
71
- end
72
- end