signalfx-rails-instrumentation 0.1.1 → 0.2.1
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 +5 -5
- data/.gitignore +3 -7
- data/.rubocop.yml +42 -0
- data/Appraisals +16 -13
- data/Gemfile +3 -7
- data/Gemfile.lock +173 -0
- data/LICENSE +2 -2
- data/README.md +116 -162
- data/Rakefile +6 -6
- data/bin/console +1 -1
- data/lib/rails/instrumentation.rb +60 -0
- data/lib/rails/instrumentation/patch.rb +38 -0
- data/lib/rails/instrumentation/subscriber.rb +45 -0
- data/lib/rails/instrumentation/subscribers/action_cable_subscriber.rb +69 -0
- data/lib/rails/instrumentation/subscribers/action_controller_subscriber.rb +172 -0
- data/lib/rails/instrumentation/subscribers/action_mailer_subscriber.rb +63 -0
- data/lib/rails/instrumentation/subscribers/action_view_subscriber.rb +48 -0
- data/lib/rails/instrumentation/subscribers/active_job_subscriber.rb +58 -0
- data/lib/rails/instrumentation/subscribers/active_record_subscriber.rb +45 -0
- data/lib/rails/instrumentation/subscribers/active_storage_subscriber.rb +91 -0
- data/lib/rails/instrumentation/subscribers/active_support_subscriber.rb +74 -0
- data/lib/rails/instrumentation/utils.rb +51 -0
- data/lib/rails/instrumentation/version.rb +5 -0
- data/rails-instrumentation.gemspec +32 -0
- metadata +54 -192
- data/.rspec +0 -2
- data/.ruby-version +0 -1
- data/.travis.yml +0 -25
- data/CHANGELOG.md +0 -47
- data/docker-compose.yml +0 -4
- data/gemfiles/.bundle/config +0 -2
- data/gemfiles/rails_32.gemfile +0 -11
- data/gemfiles/rails_4.gemfile +0 -10
- data/gemfiles/rails_40.gemfile +0 -10
- data/gemfiles/rails_41.gemfile +0 -10
- data/gemfiles/rails_42.gemfile +0 -10
- data/gemfiles/rails_5.gemfile +0 -10
- data/gemfiles/rails_50.gemfile +0 -10
- data/gemfiles/rails_51.gemfile +0 -10
- data/lib/rails-tracer.rb +0 -1
- data/lib/rails/action_controller/tracer.rb +0 -100
- data/lib/rails/action_view/tracer.rb +0 -105
- data/lib/rails/active_record/tracer.rb +0 -89
- data/lib/rails/active_support/cache/core_ext.rb +0 -11
- data/lib/rails/active_support/cache/dalli_tracer.rb +0 -106
- data/lib/rails/active_support/cache/manual_tracer.rb +0 -24
- data/lib/rails/active_support/cache/subscriber.rb +0 -62
- data/lib/rails/active_support/cache/tracer.rb +0 -55
- data/lib/rails/defer_notifications.rb +0 -78
- data/lib/rails/rack/tracer.rb +0 -61
- data/lib/rails/span_helpers.rb +0 -24
- data/lib/rails/tracer.rb +0 -38
- data/rails-tracer.gemspec +0 -44
@@ -1,11 +0,0 @@
|
|
1
|
-
module ActiveSupport
|
2
|
-
module Cache
|
3
|
-
class Store
|
4
|
-
# See the PR https://github.com/rails/rails/pull/15943/files
|
5
|
-
# In order to make the instrumentation to work we need to override the original implementation
|
6
|
-
def self.instrument
|
7
|
-
true
|
8
|
-
end
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
@@ -1,106 +0,0 @@
|
|
1
|
-
require "method/tracer"
|
2
|
-
|
3
|
-
module Dalli
|
4
|
-
class Tracer
|
5
|
-
class << self
|
6
|
-
def instrument(tracer: OpenTracing.global_tracer, active_span: nil)
|
7
|
-
::Dalli::Server.class_eval do
|
8
|
-
@tracer = tracer
|
9
|
-
@active_span = active_span
|
10
|
-
|
11
|
-
class << self
|
12
|
-
attr_reader :tracer, :active_span
|
13
|
-
end
|
14
|
-
|
15
|
-
def tracer
|
16
|
-
self.class.tracer
|
17
|
-
end
|
18
|
-
|
19
|
-
def active_span
|
20
|
-
self.class.active_span
|
21
|
-
end
|
22
|
-
|
23
|
-
alias_method :request_without_instrumentation, :request
|
24
|
-
|
25
|
-
def request(op, *args)
|
26
|
-
tags = {
|
27
|
-
'component' => 'Dalli::Server',
|
28
|
-
'span.kind' => 'client',
|
29
|
-
'db.statement' => op.to_s,
|
30
|
-
'db.type' => 'memcached',
|
31
|
-
'peer.hostname' => hostname,
|
32
|
-
'peer.port' => port,
|
33
|
-
'peer.weight' => weight
|
34
|
-
}
|
35
|
-
# Method::Tracer.trace("Dalli::Server#request", tracer: tracer, child_of: active_span, tags: tags) do
|
36
|
-
# request_without_instrumentation(op, *args)
|
37
|
-
# end
|
38
|
-
parent_span = active_span.respond_to?(:call) ? active_span.call : active_span
|
39
|
-
span = tracer.start_span("Dalli::Server#request", child_of: parent_span, tags: tags)
|
40
|
-
|
41
|
-
begin
|
42
|
-
request_without_instrumentation(op, *args)
|
43
|
-
rescue => e
|
44
|
-
if span
|
45
|
-
span.set_tag("error", true)
|
46
|
-
span.log_kv(key: "message", value: error.message)
|
47
|
-
end
|
48
|
-
ensure
|
49
|
-
span.finish() if span
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
::Dalli::Client.class_eval do
|
55
|
-
@tracer = tracer
|
56
|
-
@active_span = active_span
|
57
|
-
|
58
|
-
class << self
|
59
|
-
attr_reader :tracer, :active_span
|
60
|
-
end
|
61
|
-
|
62
|
-
def tracer
|
63
|
-
self.class.tracer
|
64
|
-
end
|
65
|
-
|
66
|
-
def active_span
|
67
|
-
self.class.active_span
|
68
|
-
end
|
69
|
-
|
70
|
-
alias_method :perform_without_instrumentation, :perform
|
71
|
-
|
72
|
-
def perform(*args)
|
73
|
-
parent_span = active_span.respond_to?(:call) ? active_span.call : active_span
|
74
|
-
span = tracer.start_span("Dalli::Client#perform", child_of: active_span, tags: {})
|
75
|
-
|
76
|
-
begin
|
77
|
-
perform_without_instrumentation(*args)
|
78
|
-
rescue => error
|
79
|
-
if span
|
80
|
-
span.set_tag("error", true)
|
81
|
-
span.log_kv(key: "message", value: error.message)
|
82
|
-
end
|
83
|
-
ensure
|
84
|
-
span.finish() if span
|
85
|
-
end
|
86
|
-
# Method::Tracer.trace("Dalli::Client#perform", tracer: tracer, child_of: active_span) do
|
87
|
-
# perform_without_instrumentation(*args)
|
88
|
-
# end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
def remove_instrumentation
|
94
|
-
::Dalli::Server.class_eval do
|
95
|
-
alias_method :request, :request_without_instrumentation
|
96
|
-
remove_method :request_without_instrumentation
|
97
|
-
end
|
98
|
-
|
99
|
-
::Dalli::Client.class_eval do
|
100
|
-
alias_method :perform, :perform_without_instrumentation
|
101
|
-
remove_method :perform_without_instrumentation
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
module ActiveSupport
|
2
|
-
module Cache
|
3
|
-
module Tracer
|
4
|
-
class << self
|
5
|
-
def start_span(operation_name, tracer: OpenTracing.global_tracer, active_span: nil, start_time: Time.now, event:, **fields)
|
6
|
-
span = tracer.start_span(operation_name,
|
7
|
-
child_of: active_span.respond_to?(:call) ? active_span.call : active_span,
|
8
|
-
start_time: start_time,
|
9
|
-
tags: {
|
10
|
-
'component' => 'ActiveSupport::Cache',
|
11
|
-
'span.kind' => 'client',
|
12
|
-
'cache.key' => fields.fetch(:key, 'unknown')
|
13
|
-
})
|
14
|
-
|
15
|
-
if event == 'read'
|
16
|
-
span.set_tag('cache.hit', fields.fetch(:hit, false))
|
17
|
-
end
|
18
|
-
|
19
|
-
span
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
@@ -1,62 +0,0 @@
|
|
1
|
-
module ActiveSupport
|
2
|
-
module Cache
|
3
|
-
module Tracer
|
4
|
-
class Subscriber
|
5
|
-
attr_reader :tracer, :active_span, :event, :operation_name
|
6
|
-
|
7
|
-
def initialize(tracer: OpenTracing.global_tracer, active_span: nil, event:)
|
8
|
-
@tracer = tracer
|
9
|
-
@active_span = active_span
|
10
|
-
@event = event
|
11
|
-
@operation_name = "cache.#{event}"
|
12
|
-
end
|
13
|
-
|
14
|
-
# For compatibility with Rails 3.2
|
15
|
-
def call(*args)
|
16
|
-
_, start, finish, _, payload = *args
|
17
|
-
|
18
|
-
span = Tracer.start_span(operation_name,
|
19
|
-
event: event,
|
20
|
-
tracer: tracer,
|
21
|
-
active_span: active_span,
|
22
|
-
start_time: start,
|
23
|
-
**payload)
|
24
|
-
|
25
|
-
if payload[:exception]
|
26
|
-
Rails::Tracer::SpanHelpers.set_error(span, payload[:exception_object] || payload[:exception])
|
27
|
-
end
|
28
|
-
|
29
|
-
span.finish(end_time: finish)
|
30
|
-
end
|
31
|
-
|
32
|
-
def start(name, _, payload)
|
33
|
-
span = tracer.start_span(operation_name,
|
34
|
-
child_of: active_span.respond_to?(:call) ? active_span.call : active_span,
|
35
|
-
tags: {
|
36
|
-
'component' => 'ActiveSupport::Cache',
|
37
|
-
'span.kind' => 'client'
|
38
|
-
})
|
39
|
-
|
40
|
-
payload[:__OT_SPAN__] = span
|
41
|
-
end
|
42
|
-
|
43
|
-
def finish(name, _, payload)
|
44
|
-
span = payload[:__OT_SPAN__]
|
45
|
-
return unless span
|
46
|
-
|
47
|
-
span.set_tag('cache.key', payload.fetch(:key, 'unknown'))
|
48
|
-
|
49
|
-
if event == 'read'
|
50
|
-
span.set_tag('cache.hit', payload.fetch(:hit, false))
|
51
|
-
end
|
52
|
-
|
53
|
-
if payload[:exception]
|
54
|
-
Rails::Tracer::SpanHelpers.set_error(span, payload[:exception_object] || payload[:exception])
|
55
|
-
end
|
56
|
-
|
57
|
-
span.finish
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
@@ -1,55 +0,0 @@
|
|
1
|
-
require 'rails/active_support/cache/core_ext'
|
2
|
-
require 'rails/active_support/cache/manual_tracer'
|
3
|
-
require 'rails/active_support/cache/subscriber'
|
4
|
-
|
5
|
-
module ActiveSupport
|
6
|
-
module Cache
|
7
|
-
module Tracer
|
8
|
-
class << self
|
9
|
-
def instrument(tracer: OpenTracing.global_tracer, active_span: nil, dalli: false)
|
10
|
-
clear_subscribers
|
11
|
-
events = %w(read write generate delete clear)
|
12
|
-
@subscribers = events.map do |event|
|
13
|
-
subscriber = ActiveSupport::Cache::Tracer::Subscriber.new(tracer: tracer,
|
14
|
-
active_span: active_span,
|
15
|
-
event: event)
|
16
|
-
ActiveSupport::Notifications.subscribe("cache_#{event}.active_support", subscriber)
|
17
|
-
end
|
18
|
-
|
19
|
-
instrument_dalli(tracer: tracer, active_span: active_span) if dalli
|
20
|
-
|
21
|
-
self
|
22
|
-
end
|
23
|
-
|
24
|
-
def disable
|
25
|
-
if @subscribers
|
26
|
-
@subscribers.each { |subscriber| ActiveSupport::Notifications.unsubscribe(subscriber) }
|
27
|
-
@subscribers.clear
|
28
|
-
end
|
29
|
-
|
30
|
-
self
|
31
|
-
end
|
32
|
-
|
33
|
-
alias :clear_subscribers :disable
|
34
|
-
|
35
|
-
def instrument_dalli(tracer:, active_span:)
|
36
|
-
return unless defined?(ActiveSupport::Cache::DalliStore)
|
37
|
-
require 'rails/active_support/cache/dalli_tracer'
|
38
|
-
|
39
|
-
Dalli::Tracer.instrument(tracer: tracer, active_span: active_span)
|
40
|
-
instrument_dalli_logger(active_span: active_span)
|
41
|
-
end
|
42
|
-
|
43
|
-
def instrument_dalli_logger(active_span:, level: Logger::ERROR)
|
44
|
-
return unless defined?(Tracing::Logger)
|
45
|
-
return unless active_span
|
46
|
-
return if [Tracing::Logger, Tracing::CompositeLogger].any? { |t| Dalli.logger.is_a?(t) }
|
47
|
-
|
48
|
-
tracing_logger = Tracing::Logger.new(active_span: active_span, level: level)
|
49
|
-
loggers = [tracing_logger, Dalli.logger].compact
|
50
|
-
Dalli.logger = Tracing::CompositeLogger.new(*loggers)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
@@ -1,78 +0,0 @@
|
|
1
|
-
|
2
|
-
module Rails
|
3
|
-
module Tracer
|
4
|
-
module Defer
|
5
|
-
class << self
|
6
|
-
attr_reader :enabled
|
7
|
-
|
8
|
-
def enable
|
9
|
-
@enabled = true
|
10
|
-
@requests = {}
|
11
|
-
@parent_spans = {}
|
12
|
-
end
|
13
|
-
|
14
|
-
def requests
|
15
|
-
@requests
|
16
|
-
end
|
17
|
-
|
18
|
-
def add_parent(id, span)
|
19
|
-
@parent_spans[id] = span
|
20
|
-
end
|
21
|
-
|
22
|
-
def defer_span(id:, spaninfo:, tracer: OpenTracing.global_tracer)
|
23
|
-
if @requests[id].nil?
|
24
|
-
@requests[id] = []
|
25
|
-
end
|
26
|
-
|
27
|
-
# if this is a process_action then the request is complete, so we can write out the span
|
28
|
-
if spaninfo['event'] == 'process_action.action_controller'
|
29
|
-
|
30
|
-
# check if we've registered a parent span
|
31
|
-
# at this point, only a rack span
|
32
|
-
parent_span = @parent_spans[id]
|
33
|
-
|
34
|
-
if parent_span.nil?
|
35
|
-
# use process_action as the parent span for this request
|
36
|
-
parent_span = tracer.start_span(spaninfo['name'],
|
37
|
-
start_time: spaninfo['start'],
|
38
|
-
tags: spaninfo['tags'])
|
39
|
-
else
|
40
|
-
# if we have another parent span and process_action will
|
41
|
-
# not need to be used as a parent span, add it to the list
|
42
|
-
# to write out with all the others
|
43
|
-
@requests[id] << spaninfo
|
44
|
-
end
|
45
|
-
|
46
|
-
# each of the stored notifications with the current request id will
|
47
|
-
# be written out as spans
|
48
|
-
write_spans(notifications: @requests[id], parent_span: parent_span)
|
49
|
-
|
50
|
-
# the rack span will finish on its own, but we need to finish if we
|
51
|
-
# started a parent span using the process_action notification
|
52
|
-
parent_span.finish(end_time: spaninfo['finish']) if @parent_spans[id].nil?
|
53
|
-
|
54
|
-
# now that all spans are written, these can be deleted to free up space
|
55
|
-
@requests.delete(id)
|
56
|
-
@parent_spans.delete(id)
|
57
|
-
else
|
58
|
-
# this isn't a span that specifically means anything, so
|
59
|
-
# just save the span info
|
60
|
-
@requests[id] << spaninfo
|
61
|
-
end
|
62
|
-
|
63
|
-
end
|
64
|
-
|
65
|
-
def write_spans(notifications: [], parent_span: nil, tracer: OpenTracing.global_tracer)
|
66
|
-
notifications.each do |spaninfo|
|
67
|
-
span = tracer.start_span(spaninfo['name'],
|
68
|
-
child_of: parent_span,
|
69
|
-
start_time: spaninfo['start'],
|
70
|
-
tags: spaninfo['tags'])
|
71
|
-
|
72
|
-
span.finish(end_time: spaninfo['finish'])
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
data/lib/rails/rack/tracer.rb
DELETED
@@ -1,61 +0,0 @@
|
|
1
|
-
module Rails
|
2
|
-
module Rack
|
3
|
-
class Tracer
|
4
|
-
class << self
|
5
|
-
def instrument(tracer: OpenTracing.global_tracer, middlewares: Rails.configuration.middleware)
|
6
|
-
return unless defined?(::Rack::Tracer)
|
7
|
-
@owns_all_middlewares = false
|
8
|
-
unless middlewares.include?(::Rack::Tracer)
|
9
|
-
middlewares.use(::Rack::Tracer, tracer: tracer)
|
10
|
-
@owns_all_middlewares = true
|
11
|
-
end
|
12
|
-
middlewares.insert_after(::Rack::Tracer, Rails::Rack::Tracer)
|
13
|
-
end
|
14
|
-
|
15
|
-
def disable(middlewares: Rails.configuration.middleware)
|
16
|
-
middlewares.delete(Rails::Rack::Tracer)
|
17
|
-
if @owns_all_middlewares
|
18
|
-
middlewares.delete(::Rack::Tracer)
|
19
|
-
@owns_all_middlewares = false
|
20
|
-
end
|
21
|
-
rescue
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def initialize(app)
|
26
|
-
@app = app
|
27
|
-
end
|
28
|
-
|
29
|
-
def call(env)
|
30
|
-
@app.call(env)
|
31
|
-
ensure
|
32
|
-
enhance_rack_span(env)
|
33
|
-
end
|
34
|
-
|
35
|
-
private
|
36
|
-
|
37
|
-
def enhance_rack_span(env)
|
38
|
-
span = extract_span(env)
|
39
|
-
if span && route_found?(env)
|
40
|
-
span.operation_name = operation_name(env)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def extract_span(env)
|
45
|
-
env['rack.span']
|
46
|
-
end
|
47
|
-
|
48
|
-
def route_found?(env)
|
49
|
-
env["action_dispatch.request.path_parameters"]
|
50
|
-
end
|
51
|
-
|
52
|
-
def operation_name(env)
|
53
|
-
path_parameters = env["action_dispatch.request.path_parameters"]
|
54
|
-
action_controller = env["action_controller.instance"]
|
55
|
-
controller = action_controller ? action_controller.class.to_s : path_parameters[:controller]
|
56
|
-
action = path_parameters[:action]
|
57
|
-
"#{controller}##{action}"
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
data/lib/rails/span_helpers.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
module Rails
|
2
|
-
module Tracer
|
3
|
-
module SpanHelpers
|
4
|
-
class << self
|
5
|
-
def set_error(span, exception)
|
6
|
-
span.set_tag('error', true)
|
7
|
-
|
8
|
-
case exception
|
9
|
-
when Array
|
10
|
-
exception_class, exception_message = exception
|
11
|
-
span.log(event: 'error', :'error.kind' => exception_class, message: exception_message)
|
12
|
-
when Exception
|
13
|
-
span.log(event: 'error', :'error.object' => exception)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
def rack_span(payload)
|
17
|
-
# if rack tracing is disabled, this will just be nil
|
18
|
-
headers = payload.fetch(:headers, nil)
|
19
|
-
headers.env['rack.span'] if !headers.nil?
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
data/lib/rails/tracer.rb
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
require "rails/span_helpers"
|
2
|
-
require "rails/defer_notifications"
|
3
|
-
require "rails/rack/tracer"
|
4
|
-
require "rails/active_record/tracer"
|
5
|
-
require "rails/active_support/cache/tracer"
|
6
|
-
require "rails/action_controller/tracer"
|
7
|
-
require "rails/action_view/tracer"
|
8
|
-
|
9
|
-
module Rails
|
10
|
-
module Tracer
|
11
|
-
class << self
|
12
|
-
def instrument(tracer: OpenTracing.global_tracer, active_span: nil,
|
13
|
-
rack: false, middlewares: Rails.configuration.middleware,
|
14
|
-
active_record: true,
|
15
|
-
active_support_cache: true, dalli: false,
|
16
|
-
action_controller: true,
|
17
|
-
action_view: true,
|
18
|
-
full_trace: false)
|
19
|
-
Rails::Rack::Tracer.instrument(tracer: tracer, middlewares: middlewares) if rack
|
20
|
-
ActiveRecord::Tracer.instrument(tracer: tracer, active_span: active_span) if active_record
|
21
|
-
ActiveSupport::Cache::Tracer.instrument(tracer: tracer, active_span: active_span, dalli: dalli) if active_support_cache
|
22
|
-
ActionController::Tracer.instrument(tracer: tracer, active_span: active_span) if action_controller
|
23
|
-
ActionView::Tracer.instrument(tracer: tracer, active_span: active_span) if action_view
|
24
|
-
|
25
|
-
# hold the requests until they can be written
|
26
|
-
Rails::Tracer::Defer.enable if full_trace
|
27
|
-
end
|
28
|
-
|
29
|
-
def disable
|
30
|
-
ActiveRecord::Tracer.disable
|
31
|
-
ActiveSupport::Cache::Tracer.disable
|
32
|
-
Rails::Rack::Tracer.disable
|
33
|
-
ActionController::Tracer.disable
|
34
|
-
ActionView::Tracer.disable
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|