signalfx-rails-instrumentation 0.1.1 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +3 -7
  3. data/.rubocop.yml +42 -0
  4. data/Appraisals +16 -13
  5. data/Gemfile +3 -7
  6. data/Gemfile.lock +173 -0
  7. data/LICENSE +2 -2
  8. data/README.md +116 -162
  9. data/Rakefile +6 -6
  10. data/bin/console +1 -1
  11. data/lib/rails/instrumentation.rb +60 -0
  12. data/lib/rails/instrumentation/patch.rb +38 -0
  13. data/lib/rails/instrumentation/subscriber.rb +45 -0
  14. data/lib/rails/instrumentation/subscribers/action_cable_subscriber.rb +69 -0
  15. data/lib/rails/instrumentation/subscribers/action_controller_subscriber.rb +172 -0
  16. data/lib/rails/instrumentation/subscribers/action_mailer_subscriber.rb +63 -0
  17. data/lib/rails/instrumentation/subscribers/action_view_subscriber.rb +48 -0
  18. data/lib/rails/instrumentation/subscribers/active_job_subscriber.rb +58 -0
  19. data/lib/rails/instrumentation/subscribers/active_record_subscriber.rb +45 -0
  20. data/lib/rails/instrumentation/subscribers/active_storage_subscriber.rb +91 -0
  21. data/lib/rails/instrumentation/subscribers/active_support_subscriber.rb +74 -0
  22. data/lib/rails/instrumentation/utils.rb +51 -0
  23. data/lib/rails/instrumentation/version.rb +5 -0
  24. data/rails-instrumentation.gemspec +32 -0
  25. metadata +54 -192
  26. data/.rspec +0 -2
  27. data/.ruby-version +0 -1
  28. data/.travis.yml +0 -25
  29. data/CHANGELOG.md +0 -47
  30. data/docker-compose.yml +0 -4
  31. data/gemfiles/.bundle/config +0 -2
  32. data/gemfiles/rails_32.gemfile +0 -11
  33. data/gemfiles/rails_4.gemfile +0 -10
  34. data/gemfiles/rails_40.gemfile +0 -10
  35. data/gemfiles/rails_41.gemfile +0 -10
  36. data/gemfiles/rails_42.gemfile +0 -10
  37. data/gemfiles/rails_5.gemfile +0 -10
  38. data/gemfiles/rails_50.gemfile +0 -10
  39. data/gemfiles/rails_51.gemfile +0 -10
  40. data/lib/rails-tracer.rb +0 -1
  41. data/lib/rails/action_controller/tracer.rb +0 -100
  42. data/lib/rails/action_view/tracer.rb +0 -105
  43. data/lib/rails/active_record/tracer.rb +0 -89
  44. data/lib/rails/active_support/cache/core_ext.rb +0 -11
  45. data/lib/rails/active_support/cache/dalli_tracer.rb +0 -106
  46. data/lib/rails/active_support/cache/manual_tracer.rb +0 -24
  47. data/lib/rails/active_support/cache/subscriber.rb +0 -62
  48. data/lib/rails/active_support/cache/tracer.rb +0 -55
  49. data/lib/rails/defer_notifications.rb +0 -78
  50. data/lib/rails/rack/tracer.rb +0 -61
  51. data/lib/rails/span_helpers.rb +0 -24
  52. data/lib/rails/tracer.rb +0 -38
  53. 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
@@ -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
@@ -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
@@ -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