ddtrace 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.env +11 -0
- data/.gitignore +56 -0
- data/.rubocop.yml +43 -0
- data/Appraisals +65 -0
- data/Gemfile +3 -0
- data/LICENSE +24 -0
- data/README.md +119 -0
- data/Rakefile +103 -0
- data/circle.yml +68 -0
- data/ddtrace.gemspec +41 -0
- data/docker-compose.yml +33 -0
- data/docs/GettingStarted +352 -0
- data/gemfiles/contrib.gemfile +9 -0
- data/gemfiles/rails3_mysql2.gemfile +11 -0
- data/gemfiles/rails3_postgres.gemfile +10 -0
- data/gemfiles/rails3_postgres_redis.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/rails5_mysql2.gemfile +8 -0
- data/gemfiles/rails5_postgres.gemfile +8 -0
- data/gemfiles/rails5_postgres_redis.gemfile +9 -0
- data/lib/ddtrace.rb +63 -0
- data/lib/ddtrace/buffer.rb +77 -0
- data/lib/ddtrace/contrib/elasticsearch/core.rb +56 -0
- data/lib/ddtrace/contrib/elasticsearch/patcher.rb +35 -0
- data/lib/ddtrace/contrib/elasticsearch/quantize.rb +22 -0
- data/lib/ddtrace/contrib/rails/action_controller.rb +75 -0
- data/lib/ddtrace/contrib/rails/action_view.rb +121 -0
- data/lib/ddtrace/contrib/rails/active_record.rb +44 -0
- data/lib/ddtrace/contrib/rails/active_support.rb +115 -0
- data/lib/ddtrace/contrib/rails/core_extensions.rb +89 -0
- data/lib/ddtrace/contrib/rails/framework.rb +107 -0
- data/lib/ddtrace/contrib/rails/utils.rb +42 -0
- data/lib/ddtrace/contrib/redis/core.rb +72 -0
- data/lib/ddtrace/contrib/redis/patcher.rb +36 -0
- data/lib/ddtrace/contrib/redis/quantize.rb +30 -0
- data/lib/ddtrace/contrib/redis/tags.rb +19 -0
- data/lib/ddtrace/encoding.rb +65 -0
- data/lib/ddtrace/ext/app_types.rb +9 -0
- data/lib/ddtrace/ext/cache.rb +7 -0
- data/lib/ddtrace/ext/errors.rb +9 -0
- data/lib/ddtrace/ext/http.rb +11 -0
- data/lib/ddtrace/ext/net.rb +8 -0
- data/lib/ddtrace/ext/redis.rb +16 -0
- data/lib/ddtrace/ext/sql.rb +8 -0
- data/lib/ddtrace/monkey.rb +60 -0
- data/lib/ddtrace/pin.rb +62 -0
- data/lib/ddtrace/span.rb +163 -0
- data/lib/ddtrace/tracer.rb +180 -0
- data/lib/ddtrace/transport.rb +149 -0
- data/lib/ddtrace/utils.rb +9 -0
- data/lib/ddtrace/version.rb +9 -0
- data/lib/ddtrace/workers.rb +109 -0
- data/lib/ddtrace/writer.rb +119 -0
- metadata +187 -0
@@ -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 "pg", :platform => :ruby
|
8
|
+
gem "activerecord-jdbcpostgresql-adapter", :platform => :jruby
|
9
|
+
gem "redis-rails"
|
10
|
+
|
11
|
+
gemspec :path => "../"
|
data/lib/ddtrace.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'ddtrace/monkey'
|
2
|
+
require 'ddtrace/pin'
|
3
|
+
require 'ddtrace/tracer'
|
4
|
+
|
5
|
+
# \Datadog global namespace that includes all tracing functionality for Tracer and Span classes.
|
6
|
+
module Datadog
|
7
|
+
@tracer = Datadog::Tracer.new()
|
8
|
+
|
9
|
+
# Default tracer that can be used as soon as +ddtrace+ is required:
|
10
|
+
#
|
11
|
+
# require 'ddtrace'
|
12
|
+
#
|
13
|
+
# span = Datadog.tracer.trace('web.request')
|
14
|
+
# span.finish()
|
15
|
+
#
|
16
|
+
# If you want to override the default tracer, the recommended way
|
17
|
+
# is to "pin" your own tracer onto your traced component:
|
18
|
+
#
|
19
|
+
# tracer = Datadog::Tracer.new
|
20
|
+
# pin = Datadog::Pin.get_from(mypatchcomponent)
|
21
|
+
# pin.tracer = tracer
|
22
|
+
|
23
|
+
def self.tracer
|
24
|
+
@tracer
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Datadog auto instrumentation for frameworks
|
29
|
+
if defined?(Rails::VERSION)
|
30
|
+
if Rails::VERSION::MAJOR.to_i >= 3
|
31
|
+
begin
|
32
|
+
# We include 'redis-rails' here if it's available, doing it later
|
33
|
+
# (typically in initialize callback) does not work, it does not
|
34
|
+
# get loaded in the right context.
|
35
|
+
require 'redis-rails'
|
36
|
+
Datadog::Tracer.log.info("'redis-rails' module found, datadog redis integration is available")
|
37
|
+
rescue LoadError
|
38
|
+
Datadog::Tracer.log.info("no 'redis-rails' module found, datadog redis integration is not available")
|
39
|
+
end
|
40
|
+
require 'ddtrace/contrib/rails/framework'
|
41
|
+
|
42
|
+
Datadog::Monkey.patch_module(:redis) # does nothing if redis is not loaded
|
43
|
+
Datadog::RailsPatcher.patch_renderer()
|
44
|
+
Datadog::RailsPatcher.patch_cache_store()
|
45
|
+
|
46
|
+
module Datadog
|
47
|
+
# Run the auto instrumentation directly after the initialization of the application and
|
48
|
+
# after the application initializers in config/initializers are run
|
49
|
+
class Railtie < Rails::Railtie
|
50
|
+
config.after_initialize do |app|
|
51
|
+
Datadog::Contrib::Rails::Framework.configure(config: app.config)
|
52
|
+
Datadog::Contrib::Rails::Framework.auto_instrument()
|
53
|
+
Datadog::Contrib::Rails::Framework.auto_instrument_redis()
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
else
|
58
|
+
logger = Logger.new(STDOUT)
|
59
|
+
logger.warn 'Detected a Rails version < 3.x.'\
|
60
|
+
'This version is not supported yet and the'\
|
61
|
+
'auto-instrumentation for core components will be disabled.'
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
# Buffer used to store active spans
|
5
|
+
class SpanBuffer
|
6
|
+
# ensure that a new SpanBuffer clears the thread spans
|
7
|
+
def initialize
|
8
|
+
Thread.current[:datadog_span] = nil
|
9
|
+
end
|
10
|
+
|
11
|
+
# Set the current active span.
|
12
|
+
def set(span)
|
13
|
+
Thread.current[:datadog_span] = span
|
14
|
+
end
|
15
|
+
|
16
|
+
# Return the current active span or nil.
|
17
|
+
def get
|
18
|
+
Thread.current[:datadog_span]
|
19
|
+
end
|
20
|
+
|
21
|
+
# Pop the current active span.
|
22
|
+
def pop
|
23
|
+
span = get()
|
24
|
+
set(nil)
|
25
|
+
span
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Trace buffer that stores application traces. The buffer has a maximum size and when
|
30
|
+
# the buffer is full, a random trace is discarded. This class is thread-safe and is used
|
31
|
+
# automatically by the ``Tracer`` instance when a ``Span`` is finished.
|
32
|
+
class TraceBuffer
|
33
|
+
def initialize(max_size)
|
34
|
+
@max_size = max_size
|
35
|
+
|
36
|
+
@mutex = Mutex.new()
|
37
|
+
@traces = []
|
38
|
+
end
|
39
|
+
|
40
|
+
# Add a new ``trace`` in the local queue. This method doesn't block the execution
|
41
|
+
# even if the buffer is full. In that case, a random trace is discarded.
|
42
|
+
def push(trace)
|
43
|
+
@mutex.synchronize do
|
44
|
+
len = @traces.length
|
45
|
+
if len < @max_size || @max_size <= 0
|
46
|
+
@traces << trace
|
47
|
+
else
|
48
|
+
# we should replace a random trace with the new one
|
49
|
+
@traces[rand(len)] = trace
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Return the current number of stored traces.
|
55
|
+
def length
|
56
|
+
@mutex.synchronize do
|
57
|
+
return @traces.length
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Return if the buffer is empty.
|
62
|
+
def empty?
|
63
|
+
@mutex.synchronize do
|
64
|
+
return @traces.empty?
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Stored traces are returned and the local buffer is reset
|
69
|
+
def pop
|
70
|
+
@mutex.synchronize do
|
71
|
+
traces = @traces
|
72
|
+
@traces = []
|
73
|
+
return traces
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'ddtrace/pin'
|
3
|
+
require 'ddtrace/ext/app_types'
|
4
|
+
require 'json'
|
5
|
+
require 'ddtrace/contrib/elasticsearch/quantize'
|
6
|
+
|
7
|
+
module Datadog
|
8
|
+
module Contrib
|
9
|
+
module Elasticsearch
|
10
|
+
URL = 'elasticsearch.url'.freeze
|
11
|
+
METHOD = 'elasticsearch.method'.freeze
|
12
|
+
PARAMS = 'elasticsearch.params'.freeze
|
13
|
+
BODY = 'elasticsearch.body'.freeze
|
14
|
+
|
15
|
+
SERVICE = 'elasticsearch'.freeze
|
16
|
+
SPAN_TYPE = 'elasticsearch'.freeze
|
17
|
+
|
18
|
+
# Datadog APM Elastic Search integration.
|
19
|
+
module TracedClient
|
20
|
+
def initialize(*args)
|
21
|
+
pin = Datadog::Pin.new(SERVICE, app: 'elasticsearch', app_type: Datadog::Ext::AppTypes::DB)
|
22
|
+
pin.onto(self)
|
23
|
+
super(*args)
|
24
|
+
end
|
25
|
+
|
26
|
+
def perform_request(*args)
|
27
|
+
pin = Datadog::Pin.get_from(self)
|
28
|
+
method = args[0]
|
29
|
+
path = args[1]
|
30
|
+
params = args[2]
|
31
|
+
body = args[3]
|
32
|
+
full_url = URI.parse(path)
|
33
|
+
|
34
|
+
url = full_url.path
|
35
|
+
response = nil
|
36
|
+
pin.tracer.trace('elasticsearch.query') do |span|
|
37
|
+
span.service = pin.service
|
38
|
+
span.span_type = SPAN_TYPE
|
39
|
+
|
40
|
+
span.set_tag(METHOD, method)
|
41
|
+
span.set_tag(URL, url)
|
42
|
+
span.set_tag(PARAMS, JSON.generate(params)) if params
|
43
|
+
span.set_tag(BODY, JSON.generate(body)) if body
|
44
|
+
|
45
|
+
quantized_url = Datadog::Contrib::Elasticsearch::Quantize.format_url(url)
|
46
|
+
span.resource = "#{method} #{quantized_url}"
|
47
|
+
|
48
|
+
response = super(*args)
|
49
|
+
end
|
50
|
+
|
51
|
+
response
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# requirements should be kept minimal as Patcher is a shared requirement.
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module Contrib
|
5
|
+
module Elasticsearch
|
6
|
+
# Patcher enables patching of 'elasticsearch/transport' module.
|
7
|
+
# This is used in monkey.rb to automatically apply patches
|
8
|
+
module Patcher
|
9
|
+
@patched = false
|
10
|
+
|
11
|
+
module_function
|
12
|
+
|
13
|
+
# patch applies our patch if needed
|
14
|
+
def patch
|
15
|
+
if !@patched && (defined?(::Elasticsearch::Transport::VERSION) && \
|
16
|
+
Gem::Version.new(::Elasticsearch::Transport::VERSION) >= Gem::Version.new('1.0.0'))
|
17
|
+
begin
|
18
|
+
require 'ddtrace/contrib/elasticsearch/core'
|
19
|
+
::Elasticsearch::Transport::Client.prepend Datadog::Contrib::Elasticsearch::TracedClient
|
20
|
+
@patched = true
|
21
|
+
rescue StandardError => e
|
22
|
+
Datadog::Tracer.log.error("Unable to apply Elastic Search integration: #{e}")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
@patched
|
26
|
+
end
|
27
|
+
|
28
|
+
# patched? tells wether patch has been successfully applied
|
29
|
+
def patched?
|
30
|
+
@patched
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
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,75 @@
|
|
1
|
+
require 'ddtrace/ext/http'
|
2
|
+
require 'ddtrace/ext/errors'
|
3
|
+
|
4
|
+
module Datadog
|
5
|
+
module Contrib
|
6
|
+
module Rails
|
7
|
+
# TODO[manu]: write docs
|
8
|
+
module ActionController
|
9
|
+
KEY = 'datadog_actioncontroller'.freeze
|
10
|
+
|
11
|
+
def self.instrument
|
12
|
+
# subscribe when the request processing starts
|
13
|
+
::ActiveSupport::Notifications.subscribe('start_processing.action_controller') do |*args|
|
14
|
+
start_processing(*args)
|
15
|
+
end
|
16
|
+
|
17
|
+
# subscribe when the request processing has been completed
|
18
|
+
::ActiveSupport::Notifications.subscribe('process_action.action_controller') do |*args|
|
19
|
+
process_action(*args)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.start_processing(*)
|
24
|
+
return if Thread.current[KEY]
|
25
|
+
|
26
|
+
tracer = ::Rails.configuration.datadog_trace.fetch(:tracer)
|
27
|
+
service = ::Rails.configuration.datadog_trace.fetch(:default_service)
|
28
|
+
type = Datadog::Ext::HTTP::TYPE
|
29
|
+
tracer.trace('rails.request', service: service, span_type: type)
|
30
|
+
|
31
|
+
Thread.current[KEY] = true
|
32
|
+
rescue StandardError => e
|
33
|
+
Datadog::Tracer.log.error(e.message)
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.process_action(_name, start, finish, _id, payload)
|
37
|
+
return unless Thread.current[KEY]
|
38
|
+
Thread.current[KEY] = false
|
39
|
+
|
40
|
+
tracer = ::Rails.configuration.datadog_trace.fetch(:tracer)
|
41
|
+
span = tracer.active_span()
|
42
|
+
return unless span
|
43
|
+
|
44
|
+
begin
|
45
|
+
span.resource = "#{payload.fetch(:controller)}##{payload.fetch(:action)}"
|
46
|
+
span.set_tag(Datadog::Ext::HTTP::URL, payload.fetch(:path))
|
47
|
+
span.set_tag(Datadog::Ext::HTTP::METHOD, payload.fetch(:method))
|
48
|
+
span.set_tag('rails.route.action', payload.fetch(:action))
|
49
|
+
span.set_tag('rails.route.controller', payload.fetch(:controller))
|
50
|
+
|
51
|
+
if payload[:exception].nil?
|
52
|
+
# [christian] in some cases :status is not defined,
|
53
|
+
# rather than firing an error, simply acknowledge we don't know it.
|
54
|
+
span.set_tag(Datadog::Ext::HTTP::STATUS_CODE, payload.fetch(:status, '?').to_s)
|
55
|
+
else
|
56
|
+
error = payload[:exception]
|
57
|
+
# TODO[manu]: it's right to have a 500? there are cases in Rails that let
|
58
|
+
# user to recover the error after this point?
|
59
|
+
span.status = 1
|
60
|
+
span.set_tag(Datadog::Ext::Errors::TYPE, error[0])
|
61
|
+
span.set_tag(Datadog::Ext::Errors::MSG, error[1])
|
62
|
+
span.set_tag(Datadog::Ext::HTTP::STATUS_CODE, '500')
|
63
|
+
end
|
64
|
+
|
65
|
+
ensure
|
66
|
+
span.start_time = start
|
67
|
+
span.finish_at(finish)
|
68
|
+
end
|
69
|
+
rescue StandardError => e
|
70
|
+
Datadog::Tracer.log.error(e.message)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'ddtrace/contrib/rails/utils'
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module Contrib
|
5
|
+
module Rails
|
6
|
+
# TODO[manu]: write docs
|
7
|
+
module ActionView
|
8
|
+
def self.instrument
|
9
|
+
# subscribe when the template rendering starts
|
10
|
+
::ActiveSupport::Notifications.subscribe('start_render_template.action_view') do |*args|
|
11
|
+
start_render_template(*args)
|
12
|
+
end
|
13
|
+
|
14
|
+
# subscribe when the partial rendering starts
|
15
|
+
::ActiveSupport::Notifications.subscribe('start_render_partial.action_view') do |*args|
|
16
|
+
start_render_partial(*args)
|
17
|
+
end
|
18
|
+
|
19
|
+
# subscribe when the template rendering has been processed
|
20
|
+
::ActiveSupport::Notifications.subscribe('render_template.action_view') do |*args|
|
21
|
+
render_template(*args)
|
22
|
+
end
|
23
|
+
|
24
|
+
# subscribe when the partial rendering has been processed
|
25
|
+
::ActiveSupport::Notifications.subscribe('render_partial.action_view') do |*args|
|
26
|
+
render_partial(*args)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.get_key(f)
|
31
|
+
'datadog_actionview_' + f
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.start_render_template(*)
|
35
|
+
key = get_key('render_template')
|
36
|
+
return if Thread.current[key]
|
37
|
+
|
38
|
+
tracer = ::Rails.configuration.datadog_trace.fetch(:tracer)
|
39
|
+
type = Datadog::Ext::HTTP::TEMPLATE
|
40
|
+
tracer.trace('rails.render_template', span_type: type)
|
41
|
+
|
42
|
+
Thread.current[key] = true
|
43
|
+
rescue StandardError => e
|
44
|
+
Datadog::Tracer.log.error(e.message)
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.start_render_partial(*)
|
48
|
+
key = get_key('render_partial')
|
49
|
+
return if Thread.current[key]
|
50
|
+
|
51
|
+
tracer = ::Rails.configuration.datadog_trace.fetch(:tracer)
|
52
|
+
type = Datadog::Ext::HTTP::TEMPLATE
|
53
|
+
tracer.trace('rails.render_partial', span_type: type)
|
54
|
+
|
55
|
+
Thread.current[key] = true
|
56
|
+
rescue StandardError => e
|
57
|
+
Datadog::Tracer.log.error(e.message)
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.render_template(_name, start, finish, _id, payload)
|
61
|
+
key = get_key('render_template')
|
62
|
+
return unless Thread.current[key]
|
63
|
+
Thread.current[key] = false
|
64
|
+
|
65
|
+
# finish the tracing and update the execution time
|
66
|
+
tracer = ::Rails.configuration.datadog_trace.fetch(:tracer)
|
67
|
+
span = tracer.active_span()
|
68
|
+
return unless span
|
69
|
+
|
70
|
+
begin
|
71
|
+
template_name = Datadog::Contrib::Rails::Utils.normalize_template_name(payload.fetch(:identifier))
|
72
|
+
span.set_tag('rails.template_name', template_name)
|
73
|
+
span.set_tag('rails.layout', payload.fetch(:layout))
|
74
|
+
|
75
|
+
if payload[:exception]
|
76
|
+
error = payload[:exception]
|
77
|
+
span.status = 1
|
78
|
+
span.set_tag(Datadog::Ext::Errors::TYPE, error[0])
|
79
|
+
span.set_tag(Datadog::Ext::Errors::MSG, error[1])
|
80
|
+
end
|
81
|
+
|
82
|
+
ensure
|
83
|
+
span.start_time = start
|
84
|
+
span.finish_at(finish)
|
85
|
+
end
|
86
|
+
rescue StandardError => e
|
87
|
+
Datadog::Tracer.log.error(e.message)
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.render_partial(_name, start, finish, _id, payload)
|
91
|
+
key = get_key('render_partial')
|
92
|
+
return unless Thread.current[key]
|
93
|
+
Thread.current[key] = false
|
94
|
+
|
95
|
+
# finish the tracing and update the execution time
|
96
|
+
tracer = ::Rails.configuration.datadog_trace.fetch(:tracer)
|
97
|
+
span = tracer.active_span()
|
98
|
+
return unless span
|
99
|
+
|
100
|
+
begin
|
101
|
+
template_name = Datadog::Contrib::Rails::Utils.normalize_template_name(payload.fetch(:identifier))
|
102
|
+
span.set_tag('rails.template_name', template_name)
|
103
|
+
|
104
|
+
if payload[:exception]
|
105
|
+
error = payload[:exception]
|
106
|
+
span.status = 1
|
107
|
+
span.set_tag(Datadog::Ext::Errors::TYPE, error[0])
|
108
|
+
span.set_tag(Datadog::Ext::Errors::MSG, error[1])
|
109
|
+
end
|
110
|
+
|
111
|
+
ensure
|
112
|
+
span.start_time = start
|
113
|
+
span.finish_at(finish)
|
114
|
+
end
|
115
|
+
rescue StandardError => e
|
116
|
+
Datadog::Tracer.log.error(e.message)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|