signalfx-rails-instrumentation 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +2 -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 +118 -164
- 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 +44 -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
|