ddtrace 0.12.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.circleci/config.yml +468 -0
- data/.circleci/images/primary/Dockerfile-1.9.3 +69 -0
- data/.circleci/images/primary/Dockerfile-2.0.0 +69 -0
- data/.circleci/images/primary/Dockerfile-2.1.10 +69 -0
- data/.circleci/images/primary/Dockerfile-2.2.10 +69 -0
- data/.circleci/images/primary/Dockerfile-2.3.7 +73 -0
- data/.circleci/images/primary/Dockerfile-2.4.4 +73 -0
- data/.dockerignore +1 -0
- data/.env +21 -11
- data/.gitignore +1 -1
- data/.rubocop.yml +4 -1
- data/Appraisals +471 -66
- data/CHANGELOG.md +80 -2
- data/Rakefile +304 -80
- data/ddtrace.gemspec +7 -7
- data/docker-compose.yml +240 -37
- data/docs/GettingStarted.md +273 -7
- data/lib/ddtrace/configuration.rb +2 -2
- data/lib/ddtrace/contrib/active_model_serializers/event.rb +57 -0
- data/lib/ddtrace/contrib/active_model_serializers/events/render.rb +32 -0
- data/lib/ddtrace/contrib/active_model_serializers/events/serialize.rb +35 -0
- data/lib/ddtrace/contrib/active_model_serializers/events.rb +30 -0
- data/lib/ddtrace/contrib/active_model_serializers/patcher.rb +62 -0
- data/lib/ddtrace/contrib/active_record/event.rb +30 -0
- data/lib/ddtrace/contrib/active_record/events/instantiation.rb +51 -0
- data/lib/ddtrace/contrib/active_record/events/sql.rb +48 -0
- data/lib/ddtrace/contrib/active_record/events.rb +30 -0
- data/lib/ddtrace/contrib/active_record/patcher.rb +3 -73
- data/lib/ddtrace/contrib/active_record/utils.rb +1 -15
- data/lib/ddtrace/contrib/active_support/notifications/event.rb +62 -0
- data/lib/ddtrace/contrib/aws/instrumentation.rb +2 -2
- data/lib/ddtrace/contrib/elasticsearch/patcher.rb +2 -2
- data/lib/ddtrace/contrib/elasticsearch/quantize.rb +18 -49
- data/lib/ddtrace/contrib/excon/middleware.rb +139 -0
- data/lib/ddtrace/contrib/excon/patcher.rb +50 -0
- data/lib/ddtrace/contrib/grpc/datadog_interceptor/client.rb +49 -0
- data/lib/ddtrace/contrib/grpc/datadog_interceptor/server.rb +66 -0
- data/lib/ddtrace/contrib/grpc/datadog_interceptor.rb +65 -0
- data/lib/ddtrace/contrib/grpc/intercept_with_datadog.rb +49 -0
- data/lib/ddtrace/contrib/grpc/patcher.rb +62 -0
- data/lib/ddtrace/contrib/http/patcher.rb +18 -16
- data/lib/ddtrace/contrib/mongodb/parsers.rb +24 -13
- data/lib/ddtrace/contrib/mongodb/patcher.rb +1 -0
- data/lib/ddtrace/contrib/mongodb/subscribers.rb +5 -4
- data/lib/ddtrace/contrib/mysql2/client.rb +60 -0
- data/lib/ddtrace/contrib/mysql2/patcher.rb +43 -0
- data/lib/ddtrace/contrib/racecar/event.rb +61 -0
- data/lib/ddtrace/contrib/racecar/events/batch.rb +27 -0
- data/lib/ddtrace/contrib/racecar/events/message.rb +27 -0
- data/lib/ddtrace/contrib/racecar/events.rb +30 -0
- data/lib/ddtrace/contrib/racecar/patcher.rb +6 -52
- data/lib/ddtrace/contrib/rack/middlewares.rb +65 -11
- data/lib/ddtrace/contrib/rack/patcher.rb +16 -0
- data/lib/ddtrace/contrib/rack/request_queue.rb +34 -0
- data/lib/ddtrace/contrib/rails/action_controller_patch.rb +77 -0
- data/lib/ddtrace/contrib/rails/action_view.rb +0 -65
- data/lib/ddtrace/contrib/rails/active_support.rb +9 -8
- data/lib/ddtrace/contrib/rails/core_extensions.rb +74 -115
- data/lib/ddtrace/contrib/rake/instrumentation.rb +70 -0
- data/lib/ddtrace/contrib/rake/patcher.rb +53 -0
- data/lib/ddtrace/contrib/sequel/database.rb +58 -0
- data/lib/ddtrace/contrib/sequel/dataset.rb +59 -0
- data/lib/ddtrace/contrib/sequel/patcher.rb +56 -0
- data/lib/ddtrace/contrib/sequel/utils.rb +28 -0
- data/lib/ddtrace/contrib/sidekiq/tracer.rb +1 -0
- data/lib/ddtrace/contrib/sinatra/env.rb +39 -0
- data/lib/ddtrace/contrib/sinatra/headers.rb +31 -0
- data/lib/ddtrace/contrib/sinatra/tracer.rb +21 -38
- data/lib/ddtrace/contrib/sinatra/tracer_middleware.rb +61 -0
- data/lib/ddtrace/ext/distributed.rb +5 -0
- data/lib/ddtrace/ext/grpc.rb +7 -0
- data/lib/ddtrace/ext/http.rb +35 -5
- data/lib/ddtrace/propagation/grpc_propagator.rb +54 -0
- data/lib/ddtrace/quantization/hash.rb +103 -0
- data/lib/ddtrace/tracer.rb +4 -1
- data/lib/ddtrace/utils/database.rb +21 -0
- data/lib/ddtrace/utils.rb +12 -2
- data/lib/ddtrace/version.rb +1 -1
- data/lib/ddtrace.rb +7 -0
- metadata +50 -21
- data/circle.yml +0 -69
- data/gemfiles/contrib.gemfile +0 -25
- data/gemfiles/contrib_old.gemfile +0 -23
- data/gemfiles/rails30_postgres.gemfile +0 -11
- data/gemfiles/rails30_postgres_sidekiq.gemfile +0 -12
- data/gemfiles/rails32_mysql2.gemfile +0 -12
- data/gemfiles/rails32_postgres.gemfile +0 -11
- data/gemfiles/rails32_postgres_redis.gemfile +0 -13
- data/gemfiles/rails32_postgres_sidekiq.gemfile +0 -12
- data/gemfiles/rails4_mysql2.gemfile +0 -10
- data/gemfiles/rails4_postgres.gemfile +0 -10
- data/gemfiles/rails4_postgres_redis.gemfile +0 -12
- data/gemfiles/rails4_postgres_sidekiq.gemfile +0 -12
- data/gemfiles/rails5_mysql2.gemfile +0 -9
- data/gemfiles/rails5_postgres.gemfile +0 -9
- data/gemfiles/rails5_postgres_redis.gemfile +0 -11
- data/gemfiles/rails5_postgres_sidekiq.gemfile +0 -11
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
require 'ddtrace/ext/sql'
|
|
2
|
+
require 'ddtrace/ext/app_types'
|
|
3
|
+
require 'ddtrace/contrib/sequel/utils'
|
|
4
|
+
|
|
5
|
+
module Datadog
|
|
6
|
+
module Contrib
|
|
7
|
+
module Sequel
|
|
8
|
+
# Adds instrumentation to Sequel::Dataset
|
|
9
|
+
module Dataset
|
|
10
|
+
def self.included(base)
|
|
11
|
+
base.send(:prepend, InstanceMethods)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Instance methods for instrumenting Sequel::Dataset
|
|
15
|
+
module InstanceMethods
|
|
16
|
+
def execute(sql, options = ::Sequel::OPTS, &block)
|
|
17
|
+
trace_execute(proc { super(sql, options, &block) }, sql, options, &block)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def execute_ddl(sql, options = ::Sequel::OPTS, &block)
|
|
21
|
+
trace_execute(proc { super(sql, options, &block) }, sql, options, &block)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def execute_dui(sql, options = ::Sequel::OPTS, &block)
|
|
25
|
+
trace_execute(proc { super(sql, options, &block) }, sql, options, &block)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def execute_insert(sql, options = ::Sequel::OPTS, &block)
|
|
29
|
+
trace_execute(proc { super(sql, options, &block) }, sql, options, &block)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def datadog_pin
|
|
33
|
+
Datadog::Pin.get_from(db)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def trace_execute(super_method, sql, options, &block)
|
|
39
|
+
opts = Utils.parse_opts(sql, options, db.opts)
|
|
40
|
+
response = nil
|
|
41
|
+
|
|
42
|
+
datadog_pin.tracer.trace('sequel.query') do |span|
|
|
43
|
+
span.service = datadog_pin.service
|
|
44
|
+
span.resource = opts[:query]
|
|
45
|
+
span.span_type = Datadog::Ext::SQL::TYPE
|
|
46
|
+
span.set_tag('sequel.db.vendor', adapter_name)
|
|
47
|
+
response = super_method.call(sql, options, &block)
|
|
48
|
+
end
|
|
49
|
+
response
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def adapter_name
|
|
53
|
+
Utils.adapter_name(db)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require 'ddtrace/contrib/sequel/database'
|
|
2
|
+
require 'ddtrace/contrib/sequel/dataset'
|
|
3
|
+
|
|
4
|
+
module Datadog
|
|
5
|
+
module Contrib
|
|
6
|
+
module Sequel
|
|
7
|
+
# Patcher enables patching of 'sequel' module.
|
|
8
|
+
# This is used in monkey.rb to manually apply patches
|
|
9
|
+
module Patcher
|
|
10
|
+
include Base
|
|
11
|
+
|
|
12
|
+
APP = 'sequel'.freeze
|
|
13
|
+
|
|
14
|
+
register_as :sequel, auto_patch: false
|
|
15
|
+
option :service_name
|
|
16
|
+
option :tracer, default: Datadog.tracer
|
|
17
|
+
|
|
18
|
+
@patched = false
|
|
19
|
+
|
|
20
|
+
module_function
|
|
21
|
+
|
|
22
|
+
# patched? tells whether patch has been successfully applied
|
|
23
|
+
def patched?
|
|
24
|
+
@patched
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def patch
|
|
28
|
+
if !@patched && compatible?
|
|
29
|
+
begin
|
|
30
|
+
patch_sequel_database
|
|
31
|
+
patch_sequel_dataset
|
|
32
|
+
|
|
33
|
+
@patched = true
|
|
34
|
+
rescue StandardError => e
|
|
35
|
+
Datadog::Tracer.log.error("Unable to apply Sequel integration: #{e}")
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
@patched
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def compatible?
|
|
43
|
+
RUBY_VERSION >= '2.0.0' && defined?(::Sequel)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def patch_sequel_database
|
|
47
|
+
::Sequel::Database.send(:include, Database)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def patch_sequel_dataset
|
|
51
|
+
::Sequel::Dataset.send(:include, Dataset)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Datadog
|
|
2
|
+
module Contrib
|
|
3
|
+
module Sequel
|
|
4
|
+
# General purpose functions for Sequel
|
|
5
|
+
module Utils
|
|
6
|
+
module_function
|
|
7
|
+
|
|
8
|
+
def adapter_name(database)
|
|
9
|
+
Datadog::Utils::Database.normalize_vendor(database.adapter_scheme.to_s)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def parse_opts(sql, opts, db_opts)
|
|
13
|
+
if ::Sequel::VERSION >= '4.37.0' && !sql.is_a?(String)
|
|
14
|
+
# In 4.37.0, sql was converted to a prepared statement object
|
|
15
|
+
sql = sql.prepared_sql unless sql.is_a?(Symbol)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
{
|
|
19
|
+
name: opts[:type],
|
|
20
|
+
query: sql,
|
|
21
|
+
database: db_opts[:database],
|
|
22
|
+
host: db_opts[:host]
|
|
23
|
+
}
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -32,6 +32,7 @@ module Datadog
|
|
|
32
32
|
span.set_tag('sidekiq.job.retry', job['retry'])
|
|
33
33
|
span.set_tag('sidekiq.job.queue', job['queue'])
|
|
34
34
|
span.set_tag('sidekiq.job.wrapper', job['class']) if job['wrapped']
|
|
35
|
+
span.set_tag('sidekiq.job.delay', 1000.0 * (Time.now.utc.to_f - job['enqueued_at'].to_f))
|
|
35
36
|
|
|
36
37
|
yield
|
|
37
38
|
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require 'ddtrace/ext/http'
|
|
2
|
+
|
|
3
|
+
module Datadog
|
|
4
|
+
module Contrib
|
|
5
|
+
module Sinatra
|
|
6
|
+
# Gets and sets trace information from a Rack Env
|
|
7
|
+
module Env
|
|
8
|
+
ENV_SPAN = 'datadog.sinatra_request_span'.freeze
|
|
9
|
+
|
|
10
|
+
module_function
|
|
11
|
+
|
|
12
|
+
def datadog_span(env)
|
|
13
|
+
env[ENV_SPAN]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def set_datadog_span(env, span)
|
|
17
|
+
env[ENV_SPAN] = span
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def request_header_tags(env, headers)
|
|
21
|
+
headers ||= []
|
|
22
|
+
|
|
23
|
+
{}.tap do |result|
|
|
24
|
+
headers.each do |header|
|
|
25
|
+
rack_header = header_to_rack_header(header)
|
|
26
|
+
if env.key?(rack_header)
|
|
27
|
+
result[Datadog::Ext::HTTP::RequestHeaders.to_tag(header)] = env[rack_header]
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def header_to_rack_header(name)
|
|
34
|
+
"HTTP_#{name.to_s.upcase.gsub(/[-\s]/, '_')}"
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require 'ddtrace/ext/http'
|
|
2
|
+
|
|
3
|
+
module Datadog
|
|
4
|
+
module Contrib
|
|
5
|
+
module Sinatra
|
|
6
|
+
# Gets and sets trace information from a Rack headers Hash
|
|
7
|
+
module Headers
|
|
8
|
+
module_function
|
|
9
|
+
|
|
10
|
+
def response_header_tags(headers, target_headers)
|
|
11
|
+
target_headers ||= []
|
|
12
|
+
|
|
13
|
+
{}.tap do |result|
|
|
14
|
+
target_headers.each do |header|
|
|
15
|
+
if headers.key?(header)
|
|
16
|
+
result[Datadog::Ext::HTTP::ResponseHeaders.to_tag(header)] = headers[header]
|
|
17
|
+
else
|
|
18
|
+
# Try a case-insensitive lookup
|
|
19
|
+
uppercased_header = header.to_s.upcase
|
|
20
|
+
matching_header = headers.keys.find { |h| h.upcase == uppercased_header }
|
|
21
|
+
if matching_header
|
|
22
|
+
result[Datadog::Ext::HTTP::ResponseHeaders.to_tag(header)] = headers[matching_header]
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
require 'sinatra/base'
|
|
3
2
|
|
|
4
3
|
require 'ddtrace/ext/app_types'
|
|
@@ -6,11 +5,14 @@ require 'ddtrace/ext/errors'
|
|
|
6
5
|
require 'ddtrace/ext/http'
|
|
7
6
|
require 'ddtrace/propagation/http_propagator'
|
|
8
7
|
|
|
8
|
+
require 'ddtrace/contrib/sinatra/tracer_middleware'
|
|
9
|
+
require 'ddtrace/contrib/sinatra/env'
|
|
10
|
+
|
|
9
11
|
sinatra_vs = Gem::Version.new(Sinatra::VERSION)
|
|
10
12
|
sinatra_min_vs = Gem::Version.new('1.4.0')
|
|
11
13
|
if sinatra_vs < sinatra_min_vs
|
|
12
14
|
raise "sinatra version #{sinatra_vs} is not supported yet " \
|
|
13
|
-
|
|
15
|
+
+ "(supporting versions >=#{sinatra_min_vs})"
|
|
14
16
|
end
|
|
15
17
|
|
|
16
18
|
Datadog::Tracer.log.info("activating instrumentation for sinatra #{sinatra_vs}")
|
|
@@ -21,6 +23,10 @@ module Datadog
|
|
|
21
23
|
# Datadog::Contrib::Sinatra::Tracer is a Sinatra extension which traces
|
|
22
24
|
# requests.
|
|
23
25
|
module Tracer
|
|
26
|
+
DEFAULT_HEADERS = {
|
|
27
|
+
response: %w[Content-Type X-Request-ID]
|
|
28
|
+
}.freeze
|
|
29
|
+
|
|
24
30
|
include Base
|
|
25
31
|
register_as :sinatra
|
|
26
32
|
|
|
@@ -32,6 +38,7 @@ module Datadog
|
|
|
32
38
|
option :tracer, default: Datadog.tracer
|
|
33
39
|
option :resource_script_names, default: false
|
|
34
40
|
option :distributed_tracing, default: false
|
|
41
|
+
option :headers, default: DEFAULT_HEADERS
|
|
35
42
|
|
|
36
43
|
def route(verb, action, *)
|
|
37
44
|
# Keep track of the route name when the app is instantiated for an
|
|
@@ -49,8 +56,6 @@ module Datadog
|
|
|
49
56
|
super
|
|
50
57
|
end
|
|
51
58
|
|
|
52
|
-
# rubocop:disable Metrics/AbcSize
|
|
53
|
-
# rubocop:disable Metrics/MethodLength
|
|
54
59
|
def self.registered(app)
|
|
55
60
|
::Sinatra::Base.module_eval do
|
|
56
61
|
def render(engine, data, *)
|
|
@@ -71,52 +76,30 @@ module Datadog
|
|
|
71
76
|
end
|
|
72
77
|
end
|
|
73
78
|
|
|
79
|
+
app.use TracerMiddleware
|
|
80
|
+
|
|
74
81
|
app.before do
|
|
75
82
|
return unless Datadog.configuration[:sinatra][:tracer].enabled
|
|
76
83
|
|
|
77
|
-
|
|
78
|
-
if @datadog_request_span
|
|
79
|
-
Datadog::Tracer.log.error('request span active in :before hook')
|
|
80
|
-
@datadog_request_span.finish()
|
|
81
|
-
@datadog_request_span = nil
|
|
82
|
-
end
|
|
83
|
-
end
|
|
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
|
|
92
|
-
|
|
93
|
-
span = tracer.trace('sinatra.request',
|
|
94
|
-
service: Datadog.configuration[:sinatra][:service_name],
|
|
95
|
-
span_type: Datadog::Ext::HTTP::TYPE)
|
|
84
|
+
span = Sinatra::Env.datadog_span(env)
|
|
96
85
|
span.set_tag(Datadog::Ext::HTTP::URL, request.path)
|
|
97
86
|
span.set_tag(Datadog::Ext::HTTP::METHOD, request.request_method)
|
|
98
|
-
|
|
99
|
-
@datadog_request_span = span
|
|
100
87
|
end
|
|
101
88
|
|
|
102
89
|
app.after do
|
|
103
90
|
return unless Datadog.configuration[:sinatra][:tracer].enabled
|
|
104
91
|
|
|
105
|
-
span =
|
|
106
|
-
begin
|
|
107
|
-
unless span
|
|
108
|
-
Datadog::Tracer.log.error('missing request span in :after hook')
|
|
109
|
-
return
|
|
110
|
-
end
|
|
92
|
+
span = Sinatra::Env.datadog_span(env)
|
|
111
93
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
span.set_error(env['sinatra.error']) if response.server_error?
|
|
116
|
-
span.finish()
|
|
117
|
-
ensure
|
|
118
|
-
@datadog_request_span = nil
|
|
94
|
+
unless span
|
|
95
|
+
Datadog::Tracer.log.error('missing request span in :after hook')
|
|
96
|
+
return
|
|
119
97
|
end
|
|
98
|
+
|
|
99
|
+
span.resource = "#{request.request_method} #{@datadog_route}"
|
|
100
|
+
span.set_tag('sinatra.route.path', @datadog_route)
|
|
101
|
+
span.set_tag(Datadog::Ext::HTTP::STATUS_CODE, response.status)
|
|
102
|
+
span.set_error(env['sinatra.error']) if response.server_error?
|
|
120
103
|
end
|
|
121
104
|
end
|
|
122
105
|
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
require 'ddtrace/contrib/sinatra/env'
|
|
2
|
+
require 'ddtrace/contrib/sinatra/headers'
|
|
3
|
+
|
|
4
|
+
module Datadog
|
|
5
|
+
module Contrib
|
|
6
|
+
module Sinatra
|
|
7
|
+
# Middleware used for automatically tagging configured headers and handle request span
|
|
8
|
+
class TracerMiddleware
|
|
9
|
+
REQUEST_TRACE_NAME = 'sinatra.request'.freeze
|
|
10
|
+
|
|
11
|
+
def initialize(app)
|
|
12
|
+
@app = app
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def call(env)
|
|
16
|
+
# Set the trace context (e.g. distributed tracing)
|
|
17
|
+
if configuration[:distributed_tracing] && tracer.provider.context.trace_id.nil?
|
|
18
|
+
context = HTTPPropagator.extract(env)
|
|
19
|
+
tracer.provider.context = context if context.trace_id
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Begin the trace
|
|
23
|
+
tracer.trace(
|
|
24
|
+
REQUEST_TRACE_NAME,
|
|
25
|
+
service: configuration[:service_name],
|
|
26
|
+
span_type: Datadog::Ext::HTTP::TYPE
|
|
27
|
+
) do |span|
|
|
28
|
+
Sinatra::Env.set_datadog_span(env, span)
|
|
29
|
+
|
|
30
|
+
Sinatra::Env.request_header_tags(env, configuration[:headers][:request]).each do |name, value|
|
|
31
|
+
span.set_tag(name, value) if span.get_tag(name).nil?
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Run application stack
|
|
35
|
+
status, headers, response_body = @app.call(env)
|
|
36
|
+
|
|
37
|
+
Sinatra::Headers.response_header_tags(headers, configuration[:headers][:response]).each do |name, value|
|
|
38
|
+
span.set_tag(name, value) if span.get_tag(name).nil?
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
[status, headers, response_body]
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def tracer
|
|
48
|
+
configuration[:tracer]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def configuration
|
|
52
|
+
Datadog.configuration[:sinatra]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def header_to_rack_header(name)
|
|
56
|
+
"HTTP_#{name.to_s.upcase.gsub(/[-\s]/, '_')}"
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -7,6 +7,11 @@ module Datadog
|
|
|
7
7
|
HTTP_HEADER_PARENT_ID = 'x-datadog-parent-id'.freeze
|
|
8
8
|
HTTP_HEADER_SAMPLING_PRIORITY = 'x-datadog-sampling-priority'.freeze
|
|
9
9
|
SAMPLING_PRIORITY_KEY = '_sampling_priority_v1'.freeze
|
|
10
|
+
|
|
11
|
+
# gRPC metadata keys for distributed tracing. https://github.com/grpc/grpc-go/blob/v1.10.x/Documentation/grpc-metadata.md
|
|
12
|
+
GRPC_METADATA_TRACE_ID = 'x-datadog-trace-id'.freeze
|
|
13
|
+
GRPC_METADATA_PARENT_ID = 'x-datadog-parent-id'.freeze
|
|
14
|
+
GRPC_METADATA_SAMPLING_PRIORITY = 'x-datadog-sampling-priority'.freeze
|
|
10
15
|
end
|
|
11
16
|
end
|
|
12
17
|
end
|
data/lib/ddtrace/ext/http.rb
CHANGED
|
@@ -1,14 +1,44 @@
|
|
|
1
1
|
module Datadog
|
|
2
2
|
module Ext
|
|
3
3
|
module HTTP
|
|
4
|
-
TYPE = 'http'.freeze
|
|
5
|
-
TEMPLATE = 'template'.freeze
|
|
6
|
-
URL = 'http.url'.freeze
|
|
7
4
|
BASE_URL = 'http.base_url'.freeze
|
|
5
|
+
ERROR_RANGE = 500...600
|
|
8
6
|
METHOD = 'http.method'.freeze
|
|
9
|
-
REQUEST_ID = 'http.request_id'.freeze
|
|
10
7
|
STATUS_CODE = 'http.status_code'.freeze
|
|
11
|
-
|
|
8
|
+
TEMPLATE = 'template'.freeze
|
|
9
|
+
TYPE = 'http'.freeze
|
|
10
|
+
URL = 'http.url'.freeze
|
|
11
|
+
|
|
12
|
+
# General header functionality
|
|
13
|
+
module Headers
|
|
14
|
+
module_function
|
|
15
|
+
|
|
16
|
+
def to_tag(name)
|
|
17
|
+
name.to_s.downcase.gsub(/[-\s]/, '_')
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Request headers
|
|
22
|
+
module RequestHeaders
|
|
23
|
+
PREFIX = 'http.request.headers'.freeze
|
|
24
|
+
|
|
25
|
+
module_function
|
|
26
|
+
|
|
27
|
+
def to_tag(name)
|
|
28
|
+
"#{PREFIX}.#{Headers.to_tag(name)}"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Response headers
|
|
33
|
+
module ResponseHeaders
|
|
34
|
+
PREFIX = 'http.response.headers'.freeze
|
|
35
|
+
|
|
36
|
+
module_function
|
|
37
|
+
|
|
38
|
+
def to_tag(name)
|
|
39
|
+
"#{PREFIX}.#{Headers.to_tag(name)}"
|
|
40
|
+
end
|
|
41
|
+
end
|
|
12
42
|
end
|
|
13
43
|
end
|
|
14
44
|
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
require 'ddtrace/context'
|
|
2
|
+
require 'ddtrace/ext/distributed'
|
|
3
|
+
|
|
4
|
+
module Datadog
|
|
5
|
+
# opentracing.io compliant methods for distributing trace context
|
|
6
|
+
# between two or more distributed services. Note this is very close
|
|
7
|
+
# to the HTTPPropagator; the key difference is the way gRPC handles
|
|
8
|
+
# header information (called "metadata") as it operates over HTTP2
|
|
9
|
+
module GRPCPropagator
|
|
10
|
+
include Ext::DistributedTracing
|
|
11
|
+
|
|
12
|
+
def self.inject!(context, metadata)
|
|
13
|
+
metadata[GRPC_METADATA_TRACE_ID] = context.trace_id.to_s
|
|
14
|
+
metadata[GRPC_METADATA_PARENT_ID] = context.span_id.to_s
|
|
15
|
+
metadata[GRPC_METADATA_SAMPLING_PRIORITY] = context.sampling_priority.to_s if context.sampling_priority
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.extract(metadata)
|
|
19
|
+
metadata = Carrier.new(metadata)
|
|
20
|
+
return Datadog::Context.new unless metadata.valid?
|
|
21
|
+
Datadog::Context.new(trace_id: metadata.trace_id,
|
|
22
|
+
span_id: metadata.parent_id,
|
|
23
|
+
sampling_priority: metadata.sampling_priority)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# opentracing.io compliant carrier object
|
|
27
|
+
class Carrier
|
|
28
|
+
include Ext::DistributedTracing
|
|
29
|
+
|
|
30
|
+
def initialize(metadata = {})
|
|
31
|
+
@metadata = metadata || {}
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def valid?
|
|
35
|
+
trace_id && parent_id
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def trace_id
|
|
39
|
+
value = @metadata[GRPC_METADATA_TRACE_ID].to_i
|
|
40
|
+
value if (1..Span::MAX_ID).cover? value
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def parent_id
|
|
44
|
+
value = @metadata[GRPC_METADATA_PARENT_ID].to_i
|
|
45
|
+
value if (1..Span::MAX_ID).cover? value
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def sampling_priority
|
|
49
|
+
value = @metadata[GRPC_METADATA_SAMPLING_PRIORITY]
|
|
50
|
+
value && value.to_i
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
module Datadog
|
|
2
|
+
module Quantization
|
|
3
|
+
# Quantization for HTTP resources
|
|
4
|
+
module Hash
|
|
5
|
+
PLACEHOLDER = '?'.freeze
|
|
6
|
+
EXCLUDE_KEYS = [].freeze
|
|
7
|
+
SHOW_KEYS = [].freeze
|
|
8
|
+
DEFAULT_OPTIONS = {
|
|
9
|
+
exclude: EXCLUDE_KEYS,
|
|
10
|
+
show: SHOW_KEYS,
|
|
11
|
+
placeholder: PLACEHOLDER
|
|
12
|
+
}.freeze
|
|
13
|
+
|
|
14
|
+
module_function
|
|
15
|
+
|
|
16
|
+
def format(hash_obj, options = {})
|
|
17
|
+
options ||= {}
|
|
18
|
+
format!(hash_obj, options)
|
|
19
|
+
rescue StandardError
|
|
20
|
+
options[:placeholder] || PLACEHOLDER
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def format!(hash_obj, options = {})
|
|
24
|
+
options ||= {}
|
|
25
|
+
options = merge_options(DEFAULT_OPTIONS, options)
|
|
26
|
+
format_hash(hash_obj, options)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def format_hash(hash_obj, options = {})
|
|
30
|
+
case hash_obj
|
|
31
|
+
when ::Hash
|
|
32
|
+
return {} if options[:exclude] == :all
|
|
33
|
+
return hash_obj if options[:show] == :all
|
|
34
|
+
|
|
35
|
+
hash_obj.each_with_object({}) do |(key, value), quantized|
|
|
36
|
+
if options[:show].any?(&indifferent_equals(key))
|
|
37
|
+
quantized[key] = value
|
|
38
|
+
elsif options[:exclude].none?(&indifferent_equals(key))
|
|
39
|
+
quantized[key] = format_value(value, options)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
else
|
|
43
|
+
format_value(hash_obj, options)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def format_value(value, options = {})
|
|
48
|
+
return value if options[:show] == :all
|
|
49
|
+
|
|
50
|
+
case value
|
|
51
|
+
when ::Hash
|
|
52
|
+
format_hash(value, options)
|
|
53
|
+
when Array
|
|
54
|
+
# If any are objects, format them.
|
|
55
|
+
format_array(value, options)
|
|
56
|
+
else
|
|
57
|
+
options[:placeholder]
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def format_array(value, options)
|
|
62
|
+
if value.any? { |v| v.class <= ::Hash || v.class <= Array }
|
|
63
|
+
first_entry = format_value(value.first, options)
|
|
64
|
+
value.size > 1 ? [first_entry, options[:placeholder]] : [first_entry]
|
|
65
|
+
# Otherwise short-circuit and return single placeholder
|
|
66
|
+
else
|
|
67
|
+
[options[:placeholder]]
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def merge_options(original, additional)
|
|
72
|
+
{}.tap do |options|
|
|
73
|
+
# Show
|
|
74
|
+
# If either is :all, value becomes :all
|
|
75
|
+
options[:show] = if original[:show] == :all || additional[:show] == :all
|
|
76
|
+
:all
|
|
77
|
+
else
|
|
78
|
+
(original[:show] || []).dup.concat(additional[:show] || []).uniq
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Exclude
|
|
82
|
+
# If either is :all, value becomes :all
|
|
83
|
+
options[:exclude] = if original[:exclude] == :all || additional[:exclude] == :all
|
|
84
|
+
:all
|
|
85
|
+
else
|
|
86
|
+
(original[:exclude] || []).dup.concat(additional[:exclude] || []).uniq
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
options[:placeholder] = additional[:placeholder] || original[:placeholder]
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def indifferent_equals(value)
|
|
94
|
+
value = convert_value(value)
|
|
95
|
+
->(compared_value) { value == convert_value(compared_value) }
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def convert_value(value)
|
|
99
|
+
value.is_a?(Symbol) ? value.to_s : value
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
data/lib/ddtrace/tracer.rb
CHANGED
|
@@ -23,6 +23,8 @@ module Datadog
|
|
|
23
23
|
attr_accessor :enabled, :writer
|
|
24
24
|
attr_writer :default_service
|
|
25
25
|
|
|
26
|
+
ALLOWED_SPAN_OPTIONS = [:service, :resource, :span_type].freeze
|
|
27
|
+
|
|
26
28
|
# Global, memoized, lazy initialized instance of a logger that is used within the the Datadog
|
|
27
29
|
# namespace. This logger outputs to +STDOUT+ by default, and is considered thread-safe.
|
|
28
30
|
def self.log
|
|
@@ -204,12 +206,13 @@ module Datadog
|
|
|
204
206
|
# * +tags+: extra tags which should be added to the span.
|
|
205
207
|
def start_span(name, options = {})
|
|
206
208
|
start_time = options.fetch(:start_time, Time.now.utc)
|
|
209
|
+
|
|
207
210
|
tags = options.fetch(:tags, {})
|
|
208
211
|
|
|
209
212
|
opts = options.select do |k, _v|
|
|
210
213
|
# Filter options, we want no side effects with unexpected args.
|
|
211
214
|
# Plus, this documents the code (Ruby 2 named args would be better but we're Ruby 1.9 compatible)
|
|
212
|
-
|
|
215
|
+
ALLOWED_SPAN_OPTIONS.include?(k)
|
|
213
216
|
end
|
|
214
217
|
|
|
215
218
|
ctx, parent = guess_context_and_parent(options[:child_of])
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Datadog
|
|
2
|
+
module Utils
|
|
3
|
+
# Common database-related utility functions.
|
|
4
|
+
module Database
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
def normalize_vendor(vendor)
|
|
8
|
+
case vendor
|
|
9
|
+
when nil
|
|
10
|
+
'defaultdb'
|
|
11
|
+
when 'postgresql'
|
|
12
|
+
'postgres'
|
|
13
|
+
when 'sqlite3'
|
|
14
|
+
'sqlite'
|
|
15
|
+
else
|
|
16
|
+
vendor
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|