ddtrace 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/.env +11 -0
  3. data/.gitignore +56 -0
  4. data/.rubocop.yml +43 -0
  5. data/Appraisals +65 -0
  6. data/Gemfile +3 -0
  7. data/LICENSE +24 -0
  8. data/README.md +119 -0
  9. data/Rakefile +103 -0
  10. data/circle.yml +68 -0
  11. data/ddtrace.gemspec +41 -0
  12. data/docker-compose.yml +33 -0
  13. data/docs/GettingStarted +352 -0
  14. data/gemfiles/contrib.gemfile +9 -0
  15. data/gemfiles/rails3_mysql2.gemfile +11 -0
  16. data/gemfiles/rails3_postgres.gemfile +10 -0
  17. data/gemfiles/rails3_postgres_redis.gemfile +11 -0
  18. data/gemfiles/rails4_mysql2.gemfile +9 -0
  19. data/gemfiles/rails4_postgres.gemfile +9 -0
  20. data/gemfiles/rails4_postgres_redis.gemfile +10 -0
  21. data/gemfiles/rails5_mysql2.gemfile +8 -0
  22. data/gemfiles/rails5_postgres.gemfile +8 -0
  23. data/gemfiles/rails5_postgres_redis.gemfile +9 -0
  24. data/lib/ddtrace.rb +63 -0
  25. data/lib/ddtrace/buffer.rb +77 -0
  26. data/lib/ddtrace/contrib/elasticsearch/core.rb +56 -0
  27. data/lib/ddtrace/contrib/elasticsearch/patcher.rb +35 -0
  28. data/lib/ddtrace/contrib/elasticsearch/quantize.rb +22 -0
  29. data/lib/ddtrace/contrib/rails/action_controller.rb +75 -0
  30. data/lib/ddtrace/contrib/rails/action_view.rb +121 -0
  31. data/lib/ddtrace/contrib/rails/active_record.rb +44 -0
  32. data/lib/ddtrace/contrib/rails/active_support.rb +115 -0
  33. data/lib/ddtrace/contrib/rails/core_extensions.rb +89 -0
  34. data/lib/ddtrace/contrib/rails/framework.rb +107 -0
  35. data/lib/ddtrace/contrib/rails/utils.rb +42 -0
  36. data/lib/ddtrace/contrib/redis/core.rb +72 -0
  37. data/lib/ddtrace/contrib/redis/patcher.rb +36 -0
  38. data/lib/ddtrace/contrib/redis/quantize.rb +30 -0
  39. data/lib/ddtrace/contrib/redis/tags.rb +19 -0
  40. data/lib/ddtrace/encoding.rb +65 -0
  41. data/lib/ddtrace/ext/app_types.rb +9 -0
  42. data/lib/ddtrace/ext/cache.rb +7 -0
  43. data/lib/ddtrace/ext/errors.rb +9 -0
  44. data/lib/ddtrace/ext/http.rb +11 -0
  45. data/lib/ddtrace/ext/net.rb +8 -0
  46. data/lib/ddtrace/ext/redis.rb +16 -0
  47. data/lib/ddtrace/ext/sql.rb +8 -0
  48. data/lib/ddtrace/monkey.rb +60 -0
  49. data/lib/ddtrace/pin.rb +62 -0
  50. data/lib/ddtrace/span.rb +163 -0
  51. data/lib/ddtrace/tracer.rb +180 -0
  52. data/lib/ddtrace/transport.rb +149 -0
  53. data/lib/ddtrace/utils.rb +9 -0
  54. data/lib/ddtrace/version.rb +9 -0
  55. data/lib/ddtrace/workers.rb +109 -0
  56. data/lib/ddtrace/writer.rb +119 -0
  57. metadata +187 -0
@@ -0,0 +1,41 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ddtrace/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "ddtrace"
8
+ spec.version = "#{Datadog::VERSION::STRING}#{ENV['VERSION_SUFFIX']}"
9
+ spec.required_ruby_version = '>= 2.1.0'
10
+ spec.authors = ["Datadog, Inc."]
11
+ spec.email = ["dev@datadoghq.com"]
12
+
13
+ spec.summary = "Datadog tracing code for your Ruby applications"
14
+ spec.description = <<-EOS
15
+ ddtrace is Datadog’s tracing client for Ruby. It is used to trace requests
16
+ as they flow across web servers, databases and microservices so that developers
17
+ have great visiblity into bottlenecks and troublesome requests.
18
+ EOS
19
+
20
+ spec.homepage = "https://github.com/DataDog/dd-trace-rb"
21
+ spec.license = "BSD-3-Clause"
22
+
23
+ if spec.respond_to?(:metadata)
24
+ spec.metadata['allowed_push_host'] = "https://rubygems.org"
25
+ else
26
+ raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
27
+ end
28
+
29
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
30
+ spec.bindir = "exe"
31
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
32
+ spec.require_paths = ["lib"]
33
+
34
+ spec.add_dependency "msgpack"
35
+
36
+ spec.add_development_dependency "bundler", "~> 1.12"
37
+ spec.add_development_dependency "rake", "~> 10.0"
38
+ spec.add_development_dependency "rubocop", "~> 0.43"
39
+ spec.add_development_dependency "minitest", "~> 5.0"
40
+ spec.add_development_dependency "appraisal", "~> 2.1"
41
+ end
@@ -0,0 +1,33 @@
1
+ # remember to use this compose file __ONLY__ for development/testing purposes
2
+ postgres:
3
+ image: postgres:9.6
4
+ environment:
5
+ - POSTGRES_PASSWORD=$TEST_POSTGRES_PASSWORD
6
+ - POSTGRES_USER=$TEST_POSTGRES_USER
7
+ - POSTGRES_DB=$TEST_POSTGRES_DB
8
+ ports:
9
+ - "127.0.0.1:${TEST_POSTGRES_PORT}:5432"
10
+
11
+ mysql:
12
+ image: mysql:5.6
13
+ environment:
14
+ - MYSQL_ROOT_PASSWORD=$TEST_MYSQL_ROOT_PASSWORD
15
+ - MYSQL_PASSWORD=$TEST_MYSQL_PASSWORD
16
+ - MYSQL_USER=$TEST_MYSQL_USER
17
+ ports:
18
+ - "127.0.0.1:${TEST_MYSQL_PORT}:3306"
19
+
20
+ elasticsearch:
21
+ # Note: ES 5.0 dies with error:
22
+ # max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
23
+ # see https://github.com/docker-library/elasticsearch/issues/98 for details
24
+ # For now, just rely on a 2.X server.
25
+ image: elasticsearch:2.4
26
+ ports:
27
+ - "127.0.0.1:${TEST_ELASTICSEARCH_REST_PORT}:9200"
28
+ - "127.0.0.1:${TEST_ELASTICSEARCH_NATIVE_PORT}:9300"
29
+
30
+ redis:
31
+ image: redis:3.0
32
+ ports:
33
+ - "127.0.0.1:${TEST_REDIS_PORT}:6379"
@@ -0,0 +1,352 @@
1
+ = \Datadog Trace Client
2
+
3
+ _ddtrace_ is Datadog’s tracing client for Ruby. It is used to trace requests as they flow across web servers,
4
+ databases and microservices so that developers have great visiblity into bottlenecks and troublesome requests.
5
+
6
+ == Installation
7
+
8
+ Install the tracer with the +gem+ command, but point to Datadog's gems repository:
9
+
10
+ $ gem install ddtrace --source http://gems.datadoghq.com/trace/
11
+
12
+ On the other hand, if you're using +Bundler+, just update your +Gemfile+ as follows:
13
+
14
+ source 'https://rubygems.org'
15
+
16
+ # tracing gem
17
+ gem 'ddtrace', :source => 'http://gems.datadoghq.com/trace/'
18
+
19
+ == Quickstart (Auto Instrumentation)
20
+
21
+ If you are on a {supported integration}[#label-Integrations], you should be able to generate traffic and view
22
+ metrics in your {dashboard}[https://app.datadoghq.com/trace].
23
+
24
+ == Quickstart (Manual Instrumentation)
25
+
26
+ If you aren't using a supported framework instrumentation, you may want to to manually instrument your code.
27
+ Adding tracing to your code is very simple. As an example, let’s imagine we have a web server and we want
28
+ to trace requests to the home page:
29
+
30
+ require 'ddtrace'
31
+ require 'sinatra'
32
+ require 'activerecord'
33
+
34
+ # a generic tracer that you can use across your application
35
+ tracer = Datadog.tracer
36
+
37
+ get '/' do
38
+ tracer.trace('web.request') do |span|
39
+ # set some span metadata
40
+ span.service = 'my-web-site'
41
+ span.resource = '/'
42
+ span.set_tag('http.method', request.request_method)
43
+
44
+ # trace the activerecord call
45
+ tracer.trace('posts.fetch') do
46
+ @posts = Posts.order(created_at: :desc).limit(10)
47
+ end
48
+
49
+ # trace the template rendering
50
+ tracer.trace('template.render') do
51
+ erb :index
52
+ end
53
+ end
54
+ end
55
+
56
+ == Glossary
57
+
58
+ [Service] The name of a set of processes that do the same job. Some examples are +datadog-web-app+ or +datadog-metrics-db+.
59
+
60
+ [Resource] A particular query to a service. For a web application, some examples might be a URL stem like +/user/home+ or a
61
+ handler function like +web.user.home+. For a SQL database, a resource would be the SQL of the query itself like
62
+ <tt>select * from users where id = ?</tt>.
63
+ You can track thousands (not millions or billions) of unique resources per services, so prefer resources like
64
+ +/user/home+ rather than <tt>/user/home?id=123456789</tt>.
65
+
66
+ [Span] A span tracks a unit of work in a service, like querying a database or rendering a template. Spans are associated
67
+ with a service and optionally a resource. Spans have names, start times, durations and optional tags.
68
+
69
+ == Integrations
70
+
71
+ === Ruby on \Rails
72
+
73
+ The \Rails integration will trace requests, database calls, templates rendering and cache read/write/delete
74
+ operations. The integration makes use of the Active Support Instrumentation, listening to the Notification API
75
+ so that any operation instrumented by the API is traced.
76
+
77
+ The supported versions are:
78
+
79
+ * \Rails 3.2 (MRI interpreter, JRuby is experimental)
80
+ * \Rails 4.2 (MRI interpreter, JRuby is experimental)
81
+ * \Rails 5.0 (MRI interpreter)
82
+
83
+ The currently supported web server are:
84
+ * Puma 2.16+ and 3.6+
85
+ * Unicorn 4.8+ and 5.1+
86
+ * Passenger 5.0 (experimental)
87
+
88
+ ==== Installation
89
+
90
+ Add the tracer gem to your +Gemfile+:
91
+
92
+ gem 'ddtrace', :source => 'http://gems.datadoghq.com/trace/'
93
+
94
+ Now you can set your service name, simply creating an initializer file in your +config/+ folder:
95
+
96
+ # config/initializers/datadog-tracer.rb
97
+
98
+ Rails.configuration.datadog_trace = {
99
+ default_service: 'my-rails-app',
100
+ }
101
+
102
+ If you're using \Rails 3 or higher, the auto-instrumentation will be automatically activated and no more configuration
103
+ is required. Your application will be listed as +my-rails-app+ in your {dashboard}[https://app.datadoghq.com/trace].
104
+
105
+ ==== Custom Instrumentation
106
+
107
+ If you need to instrument custom code within your controllers, you can simply:
108
+
109
+ class CustomController < ApplicationController
110
+ def index
111
+ # using auto instrumentation, these calls are already traced
112
+ @values = SomeModel.all
113
+ @counter = Rails.cache.fetch('custom_cache_key')
114
+
115
+ # use the global tracer to instrument your code
116
+ tracer = Datadog.tracer
117
+ tracer.trace('custom.service') do
118
+ data = Something::fetch_data()
119
+ @objects = Something::parse_data(data)
120
+ end
121
+ end
122
+ end
123
+
124
+ With the auto instrumentation turned on, the result trace will include your span correctly nested under the
125
+ +rails.request+ span.
126
+
127
+ ==== Tracer Configuration
128
+
129
+ All tracing settings are namespaced under the +Rails.configuration.datadog_tracer+ hash. To change the default behavior
130
+ of the Datadog tracer, you can override the following defaults:
131
+
132
+ # config/initializers/datadog-tracer.rb
133
+
134
+ Rails.configuration.datadog_trace = {
135
+ enabled: true,
136
+ auto_instrument: true,
137
+ auto_instrument_redis: true,
138
+ default_service: 'rails-app',
139
+ default_cache_service: 'rails-cache',
140
+ template_base_path: 'views/',
141
+ tracer: Datadog.tracer,
142
+ debug: false,
143
+ trace_agent_hostname: 'localhost',
144
+ trace_agent_port: 7777
145
+ }
146
+
147
+ The available settings are:
148
+
149
+ * +enabled+: defines if the +tracer+ is enabled or not. If set to +false+, the code is still instrumented
150
+ but no spans are sent to the local trace agent.
151
+ * +auto_instrument+: if set to false the code will not be instrumented, while the +tracer+ may be active for
152
+ your internal usage. This could be useful if you want to use the \Rails integration, but you want to trace
153
+ only particular functions or views
154
+ * +auto_instrument_redis+: if set to false \Redis calls will not be traced as such. Calls to cache will
155
+ still be instrumented but you will not have the detail of low-level \Redis calls.
156
+ * +default_service+: set the service name used when tracing application requests. Defaults to +rails-app+
157
+ * +default_database_service+: set the database service name used when tracing database activity. Defaults to the
158
+ current adapter name, so if you're using PostgreSQL it will be +postgres+.
159
+ * +default_cache_service+: set the cache service name used when tracing cache activity. Defaults to +rails-cache+
160
+ * +template_base_path+: used when the template name is parsed in the auto instrumented code. If you don't store
161
+ your templates in the +views/+ folder, you may need to change this value
162
+ * +tracer+: is the global tracer used by the tracing application. Usually you don't need to change that value
163
+ unless you're already using a different initialized +tracer+ somewhere else
164
+ * +debug+: set to true to enable debug logging.
165
+ * +trace_agent_hostname+: set the hostname of the trace agent.
166
+ * +trace_agent_port+: set the port the trace agent is listening on.
167
+
168
+ === Redis
169
+
170
+ The \Redis integration will trace simple calls as well as pipelines.
171
+
172
+ require 'redis'
173
+ require 'ddtrace'
174
+
175
+ Datadog::Monkey.patch_module(:redis) # you need to explicitly patch it
176
+
177
+ # now do your Redis stuff, eg:
178
+ redis = Redis.new
179
+ redis.set 'foo', 'bar' # traced!
180
+
181
+ The \patch_module allows you to enable tracing on a per-library basis.
182
+ If you want to enable tracing for all supported integrations, you can simply
183
+ use \patch_all eg:
184
+
185
+ require 'redis'
186
+ require 'ddtrace'
187
+
188
+ Datadog::Monkey.patch_all # enables all available integrations
189
+
190
+ # now do your Redis stuff, eg:
191
+ redis = Redis.new
192
+ redis.set 'foo', 'bar' # traced!
193
+
194
+ === Elastic Search
195
+
196
+ The \Elasticsearch integration will trace any call to \perform_request
197
+ in the \Client object:
198
+
199
+ require 'elasticsearch/transport'
200
+ require 'ddtrace'
201
+
202
+ Datadog::Monkey.patch_module(:elasticsearch) # you need to explicitly patch it
203
+
204
+ # now do your Elastic Search stuff, eg:
205
+ client = Elasticsearch::Client.new url: 'http://127.0.0.1:9200'
206
+ response = client.perform_request 'GET', '_cluster/health'
207
+
208
+ The \patch_module allows you to enable tracing on a per-library basis.
209
+ If you want to enable tracing for all supported integrations, you can simply
210
+ use \patch_all eg:
211
+
212
+ require 'elasticsearch/transport'
213
+ require 'ddtrace'
214
+
215
+ Datadog::Monkey.patch_all # enables all available integrations
216
+
217
+ # now do your Elastic Search stuff, eg:
218
+ client = Elasticsearch::Client.new url: 'http://127.0.0.1:9200'
219
+ response = client.perform_request 'GET', '_cluster/health'
220
+
221
+ == Monkey Patching
222
+
223
+ === Patching methods
224
+
225
+ Integrations such as \Redis or \Elasticsearch use monkey patching.
226
+
227
+ The available methods are:
228
+
229
+ * +autopatch_modules+: returns a \Hash of all modules available for monkey patching,
230
+ the key is the name of the module and the value \true or \false. If it is \true,
231
+ a call to \patch_all will enable the module, if it is \false, it will do nothing.
232
+ * +patch_all+: patches all modules which are supported. Make sure all the necessary
233
+ calls to \require have been done before this is alled, else monkey patching will
234
+ not work.
235
+ * +patch_module+: patches a single module, regardless of its settings in the
236
+ \autopatch_modules list.
237
+ * +patch+: patches some modules, you should pass a hash like the one returned
238
+ by \autopatch_modules
239
+ * +get_patched_modules+: returns the list of patched modules, a module has been
240
+ correctly patched only if it is in this hash, with a value set to \true.
241
+
242
+ Example:
243
+
244
+ require 'ddtrace'
245
+
246
+ puts Datadog::Monkey.autopatch_modules # lists all modules available for monkey patching
247
+ Datadog::Monkey.patch_module(:redis) # patch only one module
248
+ Datadog::Monkey.patch(elasticsearch: false, redis: true) # patch redis, but not elasticsearch
249
+ Datadog::Monkey.patch_all # patch all the available modules
250
+ puts Datadog::Monkey.get_patched_modules # tells wether modules are patched or not
251
+
252
+ It is safe to call \patch_all, \patch_module or \patch several times.
253
+ Make sure the library you want to patch is imported before you call \patch_module.
254
+ In doubt, check with \get_patched_modules.
255
+ Once a module is patched, it is not possible to unpatch it.
256
+
257
+ === Patch Info (PIN)
258
+
259
+ The Patch Info, AKA \Pin object, gives you control on the integration.
260
+
261
+ It has one class method:
262
+
263
+ * +get_from+: returns the Pin object which has been pinned onto some random
264
+ object. It is safe to call \get_from on any object, but it might return \nil.
265
+
266
+ Some instance methods:
267
+
268
+ * +enabled?+: wether tracing is enabled for this object
269
+ * +onto+: applies the patch information to some random object. It is the companion
270
+ function of \get_from.
271
+
272
+ Accessors:
273
+
274
+ * +service+: service, you should typically set some meaningful value for this.
275
+ * +app+: application name
276
+ * +tags+: optional tags
277
+ * +app_type+: application type
278
+ * +name+: span name
279
+ * +tracer+: the tracer object used for tracing
280
+
281
+ By default, a traced integration such as \Redis or \Elasticsearch carries a \Pin object. Eg:
282
+
283
+ require 'redis'
284
+ require 'ddtrace'
285
+
286
+ Datadog::Monkey.patch_all
287
+
288
+ redis = Redis.new
289
+ pin = Datadog::Pin.get_from(redis)
290
+ pin.service = 'my-redis-cache'
291
+ puts redis.get 'my-key' # this will be traced as belonging to 'my-redis-cache' service
292
+ pin.tracer = nil
293
+ puts pin.enabled? # false
294
+ puts redis.get 'my-key' # this won't be traced, tracing has been disabled now
295
+
296
+ You can use this object to instrument your own code:
297
+
298
+ require 'ddtrace'
299
+ require 'ddtrace/ext/app_types'
300
+
301
+ class MyWebSite
302
+ def initialize
303
+ pin = Datadog::Pin.new('my-web-site', app_type: Datadog::Ext::AppTypes::WEB)
304
+ Datadog::Pin.onto(self)
305
+ end
306
+
307
+ def serve(something)
308
+ pin = Datadog::Pin.get_from(self)
309
+ pin.tracer.trace('serve') do |span|
310
+ span.resource = something
311
+ span.service = pin.service
312
+ # serve something here
313
+ end
314
+ end
315
+ end
316
+
317
+ == Debug Mode
318
+
319
+ If you need to check locally what traces and spans are sent after each traced block, you can enable
320
+ a global debug mode for all tracers so that every time a trace is ready to be sent, the content will be
321
+ printed in the +STDOUT+. To enable the debug logging, add this code anywhere before using the tracer
322
+ for the first time:
323
+
324
+ require 'ddtrace'
325
+ require 'sinatra'
326
+ require 'activerecord'
327
+
328
+ # enable debug mode
329
+ Datadog::Tracer.debug_logging = true
330
+
331
+ # use the tracer as usual
332
+ tracer = Datadog.tracer
333
+
334
+ get '/' do
335
+ tracer.trace('web.request') do |span|
336
+ # ...
337
+ end
338
+ end
339
+
340
+ Remember that the debug mode may affect your application performance and so it must not be used
341
+ in a production environment.
342
+
343
+ == Supported Versions
344
+
345
+ The \Datadog Trace Client has been tested with the following Ruby versions:
346
+
347
+ * Ruby MRI 2.1
348
+ * Ruby MRI 2.2
349
+ * Ruby MRI 2.3
350
+ * JRuby 9.1.5 (experimental)
351
+
352
+ Other versions aren't yet officially supported.
@@ -0,0 +1,9 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "elasticsearch-transport"
6
+ gem "redis"
7
+ gem "hiredis"
8
+
9
+ gemspec :path => "../"
@@ -0,0 +1,11 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "test-unit"
6
+ gem "rails", "3.2.22.5"
7
+ gem "mysql2", "0.3.21", :platform => :ruby
8
+ gem "activerecord-mysql-adapter", :platform => :ruby
9
+ gem "activerecord-jdbcmysql-adapter", :platform => :jruby
10
+
11
+ gemspec :path => "../"