fair-ddtrace 0.8.2.a
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 +7 -0
- data/.env +11 -0
- data/.gitignore +59 -0
- data/.rubocop.yml +61 -0
- data/.yardopts +5 -0
- data/Appraisals +136 -0
- data/Gemfile +3 -0
- data/LICENSE +24 -0
- data/README.md +156 -0
- data/Rakefile +176 -0
- data/circle.yml +61 -0
- data/ddtrace.gemspec +44 -0
- data/docker-compose.yml +42 -0
- data/docs/GettingStarted.md +735 -0
- data/gemfiles/contrib.gemfile +16 -0
- data/gemfiles/contrib_old.gemfile +15 -0
- data/gemfiles/rails30_postgres.gemfile +10 -0
- data/gemfiles/rails30_postgres_sidekiq.gemfile +11 -0
- data/gemfiles/rails32_mysql2.gemfile +11 -0
- data/gemfiles/rails32_postgres.gemfile +10 -0
- data/gemfiles/rails32_postgres_redis.gemfile +11 -0
- data/gemfiles/rails32_postgres_sidekiq.gemfile +11 -0
- data/gemfiles/rails4_mysql2.gemfile +9 -0
- data/gemfiles/rails4_postgres.gemfile +9 -0
- data/gemfiles/rails4_postgres_redis.gemfile +10 -0
- data/gemfiles/rails4_postgres_sidekiq.gemfile +11 -0
- data/gemfiles/rails5_mysql2.gemfile +8 -0
- data/gemfiles/rails5_postgres.gemfile +8 -0
- data/gemfiles/rails5_postgres_redis.gemfile +9 -0
- data/gemfiles/rails5_postgres_sidekiq.gemfile +10 -0
- data/lib/ddtrace.rb +73 -0
- data/lib/ddtrace/buffer.rb +52 -0
- data/lib/ddtrace/context.rb +145 -0
- data/lib/ddtrace/contrib/active_record/patcher.rb +94 -0
- data/lib/ddtrace/contrib/elasticsearch/patcher.rb +108 -0
- data/lib/ddtrace/contrib/elasticsearch/quantize.rb +22 -0
- data/lib/ddtrace/contrib/grape/endpoint.rb +164 -0
- data/lib/ddtrace/contrib/grape/patcher.rb +73 -0
- data/lib/ddtrace/contrib/http/patcher.rb +156 -0
- data/lib/ddtrace/contrib/rack/middlewares.rb +150 -0
- data/lib/ddtrace/contrib/rails/action_controller.rb +81 -0
- data/lib/ddtrace/contrib/rails/action_view.rb +110 -0
- data/lib/ddtrace/contrib/rails/active_record.rb +56 -0
- data/lib/ddtrace/contrib/rails/active_support.rb +113 -0
- data/lib/ddtrace/contrib/rails/core_extensions.rb +137 -0
- data/lib/ddtrace/contrib/rails/framework.rb +171 -0
- data/lib/ddtrace/contrib/rails/middlewares.rb +32 -0
- data/lib/ddtrace/contrib/rails/utils.rb +43 -0
- data/lib/ddtrace/contrib/redis/patcher.rb +118 -0
- data/lib/ddtrace/contrib/redis/quantize.rb +30 -0
- data/lib/ddtrace/contrib/redis/tags.rb +19 -0
- data/lib/ddtrace/contrib/sidekiq/tracer.rb +103 -0
- data/lib/ddtrace/contrib/sinatra/tracer.rb +169 -0
- data/lib/ddtrace/distributed.rb +38 -0
- data/lib/ddtrace/encoding.rb +65 -0
- data/lib/ddtrace/error.rb +37 -0
- data/lib/ddtrace/ext/app_types.rb +10 -0
- data/lib/ddtrace/ext/cache.rb +7 -0
- data/lib/ddtrace/ext/distributed.rb +10 -0
- data/lib/ddtrace/ext/errors.rb +10 -0
- data/lib/ddtrace/ext/http.rb +11 -0
- data/lib/ddtrace/ext/net.rb +8 -0
- data/lib/ddtrace/ext/redis.rb +11 -0
- data/lib/ddtrace/ext/sql.rb +8 -0
- data/lib/ddtrace/logger.rb +39 -0
- data/lib/ddtrace/monkey.rb +84 -0
- data/lib/ddtrace/pin.rb +63 -0
- data/lib/ddtrace/provider.rb +21 -0
- data/lib/ddtrace/sampler.rb +49 -0
- data/lib/ddtrace/span.rb +222 -0
- data/lib/ddtrace/tracer.rb +310 -0
- data/lib/ddtrace/transport.rb +162 -0
- data/lib/ddtrace/utils.rb +16 -0
- data/lib/ddtrace/version.rb +9 -0
- data/lib/ddtrace/workers.rb +108 -0
- data/lib/ddtrace/writer.rb +118 -0
- metadata +208 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
module Datadog
|
|
2
|
+
module Contrib
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
# Patcher enables patching of 'active_record' module.
|
|
5
|
+
# This is used in monkey.rb to manually apply patches
|
|
6
|
+
module Patcher
|
|
7
|
+
@patched = false
|
|
8
|
+
|
|
9
|
+
module_function
|
|
10
|
+
|
|
11
|
+
# patched? tells whether patch has been successfully applied
|
|
12
|
+
def patched?
|
|
13
|
+
@patched
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def patch
|
|
17
|
+
if !@patched && defined?(::ActiveRecord)
|
|
18
|
+
begin
|
|
19
|
+
require 'ddtrace/contrib/rails/utils'
|
|
20
|
+
require 'ddtrace/ext/sql'
|
|
21
|
+
require 'ddtrace/ext/app_types'
|
|
22
|
+
|
|
23
|
+
patch_active_record()
|
|
24
|
+
|
|
25
|
+
@patched = true
|
|
26
|
+
rescue StandardError => e
|
|
27
|
+
Datadog::Tracer.log.error("Unable to apply Active Record integration: #{e}")
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
@patched
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def patch_active_record
|
|
35
|
+
# subscribe when the active record query has been processed
|
|
36
|
+
::ActiveSupport::Notifications.subscribe('sql.active_record') do |*args|
|
|
37
|
+
sql(*args)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def self.datadog_trace
|
|
42
|
+
# TODO: Consider using patcher for Rails as well.
|
|
43
|
+
# @tracer ||= defined?(::Rails) && ::Rails.configuration.datadog_trace
|
|
44
|
+
@datadog_trace ||= defined?(::Sinatra) && ::Sinatra::Application.settings.datadog_tracer.cfg
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def self.adapter_name
|
|
48
|
+
@adapter_name ||= Datadog::Contrib::Rails::Utils.normalize_vendor(
|
|
49
|
+
::ActiveRecord::Base.connection_config[:adapter]
|
|
50
|
+
)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def self.tracer
|
|
54
|
+
return Datadog.tracer unless datadog_trace
|
|
55
|
+
@tracer ||= datadog_trace.fetch(:tracer)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def self.database_service
|
|
59
|
+
@database_service ||= if defined?(::Sinatra)
|
|
60
|
+
datadog_trace.fetch(:default_database_service, adapter_name())
|
|
61
|
+
else
|
|
62
|
+
adapter_name()
|
|
63
|
+
end
|
|
64
|
+
if @database_service
|
|
65
|
+
tracer().set_service_info(@database_service, 'sinatra',
|
|
66
|
+
Datadog::Ext::AppTypes::DB)
|
|
67
|
+
end
|
|
68
|
+
@database_service
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def self.sql(_name, start, finish, _id, payload)
|
|
72
|
+
span_type = Datadog::Ext::SQL::TYPE
|
|
73
|
+
|
|
74
|
+
span = tracer.trace(
|
|
75
|
+
"#{adapter_name}.query",
|
|
76
|
+
resource: payload.fetch(:sql),
|
|
77
|
+
service: database_service,
|
|
78
|
+
span_type: span_type
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
# the span should have the query ONLY in the Resource attribute,
|
|
82
|
+
# so that the ``sql.query`` tag will be set in the agent with an
|
|
83
|
+
# obfuscated version
|
|
84
|
+
span.span_type = Datadog::Ext::SQL::TYPE
|
|
85
|
+
span.set_tag('active_record.db.vendor', adapter_name)
|
|
86
|
+
span.start_time = start
|
|
87
|
+
span.finish(finish)
|
|
88
|
+
rescue StandardError => e
|
|
89
|
+
Datadog::Tracer.log.error(e.message)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# requirements should be kept minimal as Patcher is a shared requirement.
|
|
2
|
+
|
|
3
|
+
module Datadog
|
|
4
|
+
module Contrib
|
|
5
|
+
module Elasticsearch
|
|
6
|
+
URL = 'elasticsearch.url'.freeze
|
|
7
|
+
METHOD = 'elasticsearch.method'.freeze
|
|
8
|
+
PARAMS = 'elasticsearch.params'.freeze
|
|
9
|
+
BODY = 'elasticsearch.body'.freeze
|
|
10
|
+
|
|
11
|
+
SERVICE = 'elasticsearch'.freeze
|
|
12
|
+
SPAN_TYPE = 'elasticsearch'.freeze
|
|
13
|
+
|
|
14
|
+
# Patcher enables patching of 'elasticsearch/transport' module.
|
|
15
|
+
# This is used in monkey.rb to automatically apply patches
|
|
16
|
+
module Patcher
|
|
17
|
+
@patched = false
|
|
18
|
+
|
|
19
|
+
module_function
|
|
20
|
+
|
|
21
|
+
# patch applies our patch if needed
|
|
22
|
+
def patch
|
|
23
|
+
if !@patched && (defined?(::Elasticsearch::Transport::VERSION) && \
|
|
24
|
+
Gem::Version.new(::Elasticsearch::Transport::VERSION) >= Gem::Version.new('1.0.0'))
|
|
25
|
+
begin
|
|
26
|
+
require 'uri'
|
|
27
|
+
require 'json'
|
|
28
|
+
require 'ddtrace/monkey'
|
|
29
|
+
require 'ddtrace/pin'
|
|
30
|
+
require 'ddtrace/ext/app_types'
|
|
31
|
+
require 'ddtrace/contrib/elasticsearch/quantize'
|
|
32
|
+
|
|
33
|
+
patch_elasticsearch_transport_client()
|
|
34
|
+
|
|
35
|
+
@patched = true
|
|
36
|
+
rescue StandardError => e
|
|
37
|
+
Datadog::Tracer.log.error("Unable to apply Elastic Search integration: #{e}")
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
@patched
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# rubocop:disable Metrics/MethodLength
|
|
44
|
+
def patch_elasticsearch_transport_client
|
|
45
|
+
::Elasticsearch::Transport::Client.class_eval do
|
|
46
|
+
alias_method :initialize_without_datadog, :initialize
|
|
47
|
+
Datadog::Monkey.without_warnings do
|
|
48
|
+
remove_method :initialize
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def initialize(*args)
|
|
52
|
+
pin = Datadog::Pin.new(SERVICE, app: 'elasticsearch', app_type: Datadog::Ext::AppTypes::DB)
|
|
53
|
+
pin.onto(self)
|
|
54
|
+
initialize_without_datadog(*args)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
alias_method :perform_request_without_datadog, :perform_request
|
|
58
|
+
remove_method :perform_request
|
|
59
|
+
|
|
60
|
+
def perform_request(*args)
|
|
61
|
+
pin = Datadog::Pin.get_from(self)
|
|
62
|
+
return perform_request_without_datadog(*args) unless pin && pin.tracer
|
|
63
|
+
|
|
64
|
+
method = args[0]
|
|
65
|
+
path = args[1]
|
|
66
|
+
params = args[2]
|
|
67
|
+
body = args[3]
|
|
68
|
+
full_url = URI.parse(path)
|
|
69
|
+
|
|
70
|
+
url = full_url.path
|
|
71
|
+
response = nil
|
|
72
|
+
pin.tracer.trace('elasticsearch.query') do |span|
|
|
73
|
+
begin
|
|
74
|
+
span.service = pin.service
|
|
75
|
+
span.span_type = SPAN_TYPE
|
|
76
|
+
|
|
77
|
+
# load JSON for the following fields unless they're already strings
|
|
78
|
+
params = JSON.generate(params) if params && !params.is_a?(String)
|
|
79
|
+
body = JSON.generate(body) if body && !body.is_a?(String)
|
|
80
|
+
|
|
81
|
+
span.set_tag(METHOD, method)
|
|
82
|
+
span.set_tag(URL, url)
|
|
83
|
+
span.set_tag(PARAMS, params) if params
|
|
84
|
+
span.set_tag(BODY, body) if body
|
|
85
|
+
|
|
86
|
+
quantized_url = Datadog::Contrib::Elasticsearch::Quantize.format_url(url)
|
|
87
|
+
span.resource = "#{method} #{quantized_url}"
|
|
88
|
+
rescue StandardError => e
|
|
89
|
+
Datadog::Tracer.log.error(e.message)
|
|
90
|
+
ensure
|
|
91
|
+
# the call is still executed
|
|
92
|
+
response = perform_request_without_datadog(*args)
|
|
93
|
+
span.set_tag('http.status_code', response.status)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
response
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# patched? tells wether patch has been successfully applied
|
|
102
|
+
def patched?
|
|
103
|
+
@patched
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Datadog
|
|
2
|
+
module Contrib
|
|
3
|
+
module Elasticsearch
|
|
4
|
+
# Quantize contains ES-specific resource quantization tools.
|
|
5
|
+
module Quantize
|
|
6
|
+
ID_REGEXP = %r{\/([0-9]+)([\/\?]|$)}
|
|
7
|
+
ID_PLACEHOLDER = '/?\2'.freeze
|
|
8
|
+
|
|
9
|
+
INDEX_REGEXP = /[0-9]{2,}/
|
|
10
|
+
INDEX_PLACEHOLDER = '?'.freeze
|
|
11
|
+
|
|
12
|
+
module_function
|
|
13
|
+
|
|
14
|
+
# Very basic quantization, complex processing should be done in the agent
|
|
15
|
+
def format_url(url)
|
|
16
|
+
quantized_url = url.gsub(ID_REGEXP, ID_PLACEHOLDER)
|
|
17
|
+
quantized_url.gsub(INDEX_REGEXP, INDEX_PLACEHOLDER)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
require 'ddtrace/ext/http'
|
|
2
|
+
require 'ddtrace/ext/errors'
|
|
3
|
+
|
|
4
|
+
module Datadog
|
|
5
|
+
module Contrib
|
|
6
|
+
module Grape
|
|
7
|
+
# rubocop:disable Metrics/ModuleLength
|
|
8
|
+
# Endpoint module includes a list of subscribers to create
|
|
9
|
+
# traces when a Grape endpoint is hit
|
|
10
|
+
module Endpoint
|
|
11
|
+
KEY_RUN = 'datadog_grape_endpoint_run'.freeze
|
|
12
|
+
KEY_RENDER = 'datadog_grape_endpoint_render'.freeze
|
|
13
|
+
|
|
14
|
+
def self.subscribe
|
|
15
|
+
# Grape is instrumented only if it's available
|
|
16
|
+
return unless defined?(::Grape) && defined?(::ActiveSupport::Notifications)
|
|
17
|
+
|
|
18
|
+
# subscribe when a Grape endpoint is hit
|
|
19
|
+
::ActiveSupport::Notifications.subscribe('endpoint_run.grape.start_process') do |*args|
|
|
20
|
+
endpoint_start_process(*args)
|
|
21
|
+
end
|
|
22
|
+
::ActiveSupport::Notifications.subscribe('endpoint_run.grape') do |*args|
|
|
23
|
+
endpoint_run(*args)
|
|
24
|
+
end
|
|
25
|
+
::ActiveSupport::Notifications.subscribe('endpoint_render.grape.start_render') do |*args|
|
|
26
|
+
endpoint_start_render(*args)
|
|
27
|
+
end
|
|
28
|
+
::ActiveSupport::Notifications.subscribe('endpoint_render.grape') do |*args|
|
|
29
|
+
endpoint_render(*args)
|
|
30
|
+
end
|
|
31
|
+
::ActiveSupport::Notifications.subscribe('endpoint_run_filters.grape') do |*args|
|
|
32
|
+
endpoint_run_filters(*args)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def self.endpoint_start_process(*)
|
|
37
|
+
return if Thread.current[KEY_RUN]
|
|
38
|
+
|
|
39
|
+
# retrieve the tracer from the PIN object
|
|
40
|
+
pin = Datadog::Pin.get_from(::Grape)
|
|
41
|
+
return unless pin && pin.enabled?
|
|
42
|
+
|
|
43
|
+
# store the beginning of a trace
|
|
44
|
+
tracer = pin.tracer
|
|
45
|
+
service = pin.service
|
|
46
|
+
type = Datadog::Ext::HTTP::TYPE
|
|
47
|
+
tracer.trace('grape.endpoint_run', service: service, span_type: type)
|
|
48
|
+
|
|
49
|
+
Thread.current[KEY_RUN] = true
|
|
50
|
+
rescue StandardError => e
|
|
51
|
+
Datadog::Tracer.log.error(e.message)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def self.endpoint_run(name, start, finish, id, payload)
|
|
55
|
+
return unless Thread.current[KEY_RUN]
|
|
56
|
+
Thread.current[KEY_RUN] = false
|
|
57
|
+
|
|
58
|
+
# retrieve the tracer from the PIN object
|
|
59
|
+
pin = Datadog::Pin.get_from(::Grape)
|
|
60
|
+
return unless pin && pin.enabled?
|
|
61
|
+
|
|
62
|
+
tracer = pin.tracer
|
|
63
|
+
span = tracer.active_span()
|
|
64
|
+
return unless span
|
|
65
|
+
|
|
66
|
+
begin
|
|
67
|
+
# collect endpoint details
|
|
68
|
+
api_view = payload[:endpoint].options[:for].to_s
|
|
69
|
+
path = payload[:endpoint].options[:path].join('/')
|
|
70
|
+
resource = "#{api_view}##{path}"
|
|
71
|
+
span.resource = resource
|
|
72
|
+
|
|
73
|
+
# set the request span resource if it's a `rack.request` span
|
|
74
|
+
request_span = payload[:env][:datadog_rack_request_span]
|
|
75
|
+
if !request_span.nil? && request_span.name == 'rack.request'
|
|
76
|
+
request_span.resource = resource
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# catch thrown exceptions
|
|
80
|
+
span.set_error(payload[:exception_object]) unless payload[:exception_object].nil?
|
|
81
|
+
|
|
82
|
+
# override the current span with this notification values
|
|
83
|
+
span.set_tag('grape.route.endpoint', api_view)
|
|
84
|
+
span.set_tag('grape.route.path', path)
|
|
85
|
+
ensure
|
|
86
|
+
span.start_time = start
|
|
87
|
+
span.finish(finish)
|
|
88
|
+
end
|
|
89
|
+
rescue StandardError => e
|
|
90
|
+
Datadog::Tracer.log.error(e.message)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def self.endpoint_start_render(*)
|
|
94
|
+
return if Thread.current[KEY_RENDER]
|
|
95
|
+
|
|
96
|
+
# retrieve the tracer from the PIN object
|
|
97
|
+
pin = Datadog::Pin.get_from(::Grape)
|
|
98
|
+
return unless pin && pin.enabled?
|
|
99
|
+
|
|
100
|
+
# store the beginning of a trace
|
|
101
|
+
tracer = pin.tracer
|
|
102
|
+
service = pin.service
|
|
103
|
+
type = Datadog::Ext::HTTP::TYPE
|
|
104
|
+
tracer.trace('grape.endpoint_render', service: service, span_type: type)
|
|
105
|
+
|
|
106
|
+
Thread.current[KEY_RENDER] = true
|
|
107
|
+
rescue StandardError => e
|
|
108
|
+
Datadog::Tracer.log.error(e.message)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def self.endpoint_render(name, start, finish, id, payload)
|
|
112
|
+
return unless Thread.current[KEY_RENDER]
|
|
113
|
+
Thread.current[KEY_RENDER] = false
|
|
114
|
+
|
|
115
|
+
# retrieve the tracer from the PIN object
|
|
116
|
+
pin = Datadog::Pin.get_from(::Grape)
|
|
117
|
+
return unless pin && pin.enabled?
|
|
118
|
+
|
|
119
|
+
tracer = pin.tracer
|
|
120
|
+
span = tracer.active_span()
|
|
121
|
+
return unless span
|
|
122
|
+
|
|
123
|
+
# catch thrown exceptions
|
|
124
|
+
begin
|
|
125
|
+
span.set_error(payload[:exception_object]) unless payload[:exception_object].nil?
|
|
126
|
+
ensure
|
|
127
|
+
span.start_time = start
|
|
128
|
+
span.finish(finish)
|
|
129
|
+
end
|
|
130
|
+
rescue StandardError => e
|
|
131
|
+
Datadog::Tracer.log.error(e.message)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def self.endpoint_run_filters(name, start, finish, id, payload)
|
|
135
|
+
# retrieve the tracer from the PIN object
|
|
136
|
+
pin = Datadog::Pin.get_from(::Grape)
|
|
137
|
+
return unless pin && pin.enabled?
|
|
138
|
+
|
|
139
|
+
# safe-guard to prevent submitting empty filters
|
|
140
|
+
zero_length = (finish - start).zero?
|
|
141
|
+
filters = payload[:filters]
|
|
142
|
+
type = payload[:type]
|
|
143
|
+
return if (!filters || filters.empty?) || !type || zero_length
|
|
144
|
+
|
|
145
|
+
tracer = pin.tracer
|
|
146
|
+
service = pin.service
|
|
147
|
+
type = Datadog::Ext::HTTP::TYPE
|
|
148
|
+
span = tracer.trace('grape.endpoint_run_filters', service: service, span_type: type)
|
|
149
|
+
|
|
150
|
+
begin
|
|
151
|
+
# catch thrown exceptions
|
|
152
|
+
span.set_error(payload[:exception_object]) unless payload[:exception_object].nil?
|
|
153
|
+
span.set_tag('grape.filter.type', type.to_s)
|
|
154
|
+
ensure
|
|
155
|
+
span.start_time = start
|
|
156
|
+
span.finish(finish)
|
|
157
|
+
end
|
|
158
|
+
rescue StandardError => e
|
|
159
|
+
Datadog::Tracer.log.error(e.message)
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
module Datadog
|
|
2
|
+
module Contrib
|
|
3
|
+
module Grape
|
|
4
|
+
SERVICE = 'grape'.freeze
|
|
5
|
+
|
|
6
|
+
# Patcher that introduces more instrumentation for Grape endpoints, so that
|
|
7
|
+
# new signals are executed at the beginning of each step (filters, render and run)
|
|
8
|
+
module Patcher
|
|
9
|
+
@patched = false
|
|
10
|
+
|
|
11
|
+
module_function
|
|
12
|
+
|
|
13
|
+
def patched?
|
|
14
|
+
@patched
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def patch
|
|
18
|
+
if !@patched && defined?(::Grape)
|
|
19
|
+
begin
|
|
20
|
+
# do not require these by default, but only when actually patching
|
|
21
|
+
require 'ddtrace'
|
|
22
|
+
require 'ddtrace/ext/app_types'
|
|
23
|
+
require 'ddtrace/contrib/grape/endpoint'
|
|
24
|
+
|
|
25
|
+
@patched = true
|
|
26
|
+
# patch all endpoints
|
|
27
|
+
patch_endpoint_run()
|
|
28
|
+
patch_endpoint_render()
|
|
29
|
+
|
|
30
|
+
# attach a PIN object globally and set the service once
|
|
31
|
+
pin = Datadog::Pin.new(SERVICE, app: 'grape', app_type: Datadog::Ext::AppTypes::WEB)
|
|
32
|
+
pin.onto(::Grape)
|
|
33
|
+
if pin.tracer && pin.service
|
|
34
|
+
pin.tracer.set_service_info(pin.service, 'grape', pin.app_type)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# subscribe to ActiveSupport events
|
|
38
|
+
Datadog::Contrib::Grape::Endpoint.subscribe()
|
|
39
|
+
rescue StandardError => e
|
|
40
|
+
Datadog::Tracer.log.error("Unable to apply Grape integration: #{e}")
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
@patched
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def patch_endpoint_run
|
|
47
|
+
::Grape::Endpoint.class_eval do
|
|
48
|
+
alias_method :run_without_datadog, :run
|
|
49
|
+
def run(*args)
|
|
50
|
+
::ActiveSupport::Notifications.instrument('endpoint_run.grape.start_process')
|
|
51
|
+
run_without_datadog(*args)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def patch_endpoint_render
|
|
57
|
+
::Grape::Endpoint.class_eval do
|
|
58
|
+
class << self
|
|
59
|
+
alias_method :generate_api_method_without_datadog, :generate_api_method
|
|
60
|
+
def generate_api_method(*params, &block)
|
|
61
|
+
method_api = generate_api_method_without_datadog(*params, &block)
|
|
62
|
+
proc do |*args|
|
|
63
|
+
::ActiveSupport::Notifications.instrument('endpoint_render.grape.start_render')
|
|
64
|
+
method_api.call(*args)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|