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.
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