logtail-rails 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/main.yml +144 -0
- data/.gitignore +23 -0
- data/.rspec +3 -0
- data/Gemfile +3 -0
- data/LICENSE.md +13 -0
- data/README.md +10 -0
- data/Rakefile +6 -0
- data/gemfiles/rails-3.0.gemfile +8 -0
- data/gemfiles/rails-3.1.gemfile +8 -0
- data/gemfiles/rails-3.2.gemfile +8 -0
- data/gemfiles/rails-4.0.gemfile +12 -0
- data/gemfiles/rails-4.1.gemfile +12 -0
- data/gemfiles/rails-4.2.gemfile +12 -0
- data/gemfiles/rails-5.0.gemfile +12 -0
- data/gemfiles/rails-5.1.gemfile +12 -0
- data/gemfiles/rails-5.2.gemfile +12 -0
- data/gemfiles/rails-6.0.gemfile +12 -0
- data/gemfiles/rails-6.1.gemfile +12 -0
- data/gemfiles/rails-edge.gemfile +10 -0
- data/lib/logtail-rails.rb +64 -0
- data/lib/logtail-rails/action_controller.rb +17 -0
- data/lib/logtail-rails/action_controller/log_subscriber.rb +25 -0
- data/lib/logtail-rails/action_controller/log_subscriber/logtail_log_subscriber.rb +46 -0
- data/lib/logtail-rails/action_dispatch.rb +20 -0
- data/lib/logtail-rails/action_dispatch/debug_exceptions.rb +51 -0
- data/lib/logtail-rails/action_view.rb +17 -0
- data/lib/logtail-rails/action_view/log_subscriber.rb +25 -0
- data/lib/logtail-rails/action_view/log_subscriber/logtail_log_subscriber.rb +84 -0
- data/lib/logtail-rails/active_record.rb +17 -0
- data/lib/logtail-rails/active_record/log_subscriber.rb +20 -0
- data/lib/logtail-rails/active_record/log_subscriber/logtail_log_subscriber.rb +52 -0
- data/lib/logtail-rails/active_support_log_subscriber.rb +39 -0
- data/lib/logtail-rails/config.rb +12 -0
- data/lib/logtail-rails/config/action_controller.rb +29 -0
- data/lib/logtail-rails/config/action_view.rb +29 -0
- data/lib/logtail-rails/config/active_record.rb +29 -0
- data/lib/logtail-rails/error_event.rb +62 -0
- data/lib/logtail-rails/logger.rb +20 -0
- data/lib/logtail-rails/overrides.rb +12 -0
- data/lib/logtail-rails/overrides/active_support_3_tagged_logging.rb +111 -0
- data/lib/logtail-rails/overrides/active_support_buffered_logger.rb +22 -0
- data/lib/logtail-rails/overrides/active_support_tagged_logging.rb +66 -0
- data/lib/logtail-rails/overrides/lograge.rb +18 -0
- data/lib/logtail-rails/overrides/rails_stdout_logging.rb +20 -0
- data/lib/logtail-rails/rack_logger.rb +59 -0
- data/lib/logtail-rails/railtie.rb +27 -0
- data/lib/logtail-rails/session_context.rb +37 -0
- data/lib/logtail-rails/version.rb +7 -0
- data/logtail-rails.gemspec +60 -0
- metadata +263 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
require "logtail-rails/action_controller/log_subscriber"
|
2
|
+
|
3
|
+
module Logtail
|
4
|
+
module Integrations
|
5
|
+
# Module for holding *all* ActionController integrations. See {Integration} for
|
6
|
+
# configuration details for all integrations.
|
7
|
+
module ActionController
|
8
|
+
extend Integration
|
9
|
+
|
10
|
+
def self.integrate!
|
11
|
+
return false if !enabled?
|
12
|
+
|
13
|
+
LogSubscriber.integrate!
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Logtail
|
2
|
+
module Integrations
|
3
|
+
module ActionController
|
4
|
+
# Responsible for removing the default ActionController::LogSubscriber and installing
|
5
|
+
# the LogtailLogSubscriber
|
6
|
+
#
|
7
|
+
# @private
|
8
|
+
class LogSubscriber < Integrator
|
9
|
+
def initialize
|
10
|
+
require "action_controller/log_subscriber"
|
11
|
+
require "logtail-rails/action_controller/log_subscriber/logtail_log_subscriber"
|
12
|
+
rescue LoadError => e
|
13
|
+
raise RequirementNotMetError.new(e.message)
|
14
|
+
end
|
15
|
+
|
16
|
+
def integrate!
|
17
|
+
return true if Logtail::Integrations::Rails::ActiveSupportLogSubscriber.subscribed?(:action_controller, LogtailLogSubscriber)
|
18
|
+
|
19
|
+
Logtail::Integrations::Rails::ActiveSupportLogSubscriber.unsubscribe!(:action_controller, ::ActionController::LogSubscriber)
|
20
|
+
LogtailLogSubscriber.attach_to(:action_controller)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Logtail
|
2
|
+
module Integrations
|
3
|
+
module ActionController
|
4
|
+
class LogSubscriber < Integrator
|
5
|
+
# The log subscriber that replaces the default `ActionController::LogSubscriber`.
|
6
|
+
# The intent of this subscriber is to, as transparently as possible, properly
|
7
|
+
# track events that are being logged here. This LogSubscriber will never change
|
8
|
+
# default behavior / log messages.
|
9
|
+
#
|
10
|
+
# @private
|
11
|
+
class LogtailLogSubscriber < ::ActionController::LogSubscriber
|
12
|
+
def start_processing(event)
|
13
|
+
return true if silence?
|
14
|
+
|
15
|
+
info do
|
16
|
+
payload = event.payload
|
17
|
+
params = payload[:params].except(*INTERNAL_PARAMS)
|
18
|
+
format = extract_format(payload)
|
19
|
+
format = format.to_s.upcase if format.is_a?(Symbol)
|
20
|
+
|
21
|
+
Events::ControllerCall.new(
|
22
|
+
controller: payload[:controller],
|
23
|
+
action: payload[:action],
|
24
|
+
format: format,
|
25
|
+
params: params
|
26
|
+
)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
def extract_format(payload)
|
32
|
+
if payload.key?(:format)
|
33
|
+
payload[:format] # rails > 4.X
|
34
|
+
elsif payload.key?(:formats)
|
35
|
+
payload[:formats].first # rails 3.X
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def silence?
|
40
|
+
ActionController.silence?
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require "logtail-rails/action_dispatch/debug_exceptions"
|
2
|
+
|
3
|
+
module Logtail
|
4
|
+
module Integrations
|
5
|
+
# Module for holding *all* ActionDispatch integrations. This
|
6
|
+
# module simply disables the exception tracking middleware so that our middleware
|
7
|
+
# works as expected.
|
8
|
+
module ActionDispatch
|
9
|
+
def self.enabled?
|
10
|
+
Rails::ErrorEvent.enabled?
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.integrate!
|
14
|
+
return false if !enabled?
|
15
|
+
|
16
|
+
DebugExceptions.integrate!
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Logtail
|
2
|
+
module Integrations
|
3
|
+
module ActionDispatch
|
4
|
+
# Responsible for disabled logging in the ActionDispatch::DebugExceptions
|
5
|
+
# Rack middleware. We cannot simply remove the middleware because it is
|
6
|
+
# coupled with displaying an exception debug screen if debug exceptions is enabled.
|
7
|
+
#
|
8
|
+
# @private
|
9
|
+
class DebugExceptions < Integrator
|
10
|
+
|
11
|
+
# Patch for disabling logging
|
12
|
+
#
|
13
|
+
# @private
|
14
|
+
module InstanceMethods
|
15
|
+
def self.included(klass)
|
16
|
+
klass.class_eval do
|
17
|
+
private
|
18
|
+
def logger(*args)
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize
|
26
|
+
begin
|
27
|
+
# Rails >= 3.1
|
28
|
+
require "action_dispatch/middleware/debug_exceptions"
|
29
|
+
rescue LoadError
|
30
|
+
# Rails < 3.1
|
31
|
+
require "action_dispatch/middleware/show_exceptions"
|
32
|
+
end
|
33
|
+
rescue LoadError => e
|
34
|
+
raise RequirementNotMetError.new(e.message)
|
35
|
+
end
|
36
|
+
|
37
|
+
def integrate!
|
38
|
+
if defined?(::ActionDispatch::DebugExceptions) && !::ActionDispatch::DebugExceptions.include?(InstanceMethods)
|
39
|
+
::ActionDispatch::DebugExceptions.send(:include, InstanceMethods)
|
40
|
+
end
|
41
|
+
|
42
|
+
if defined?(::ActionDispatch::ShowExceptions) && !::ActionDispatch::ShowExceptions.include?(InstanceMethods)
|
43
|
+
::ActionDispatch::ShowExceptions.send(:include, InstanceMethods)
|
44
|
+
end
|
45
|
+
|
46
|
+
true
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "logtail-rails/action_view/log_subscriber"
|
2
|
+
|
3
|
+
module Logtail
|
4
|
+
module Integrations
|
5
|
+
# Module for holding *all* ActionView integrations. See {Integration} for
|
6
|
+
# configuration details for all integrations.
|
7
|
+
module ActionView
|
8
|
+
extend Integration
|
9
|
+
|
10
|
+
def self.integrate!
|
11
|
+
return false if !enabled?
|
12
|
+
|
13
|
+
LogSubscriber.integrate!
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Logtail
|
2
|
+
module Integrations
|
3
|
+
module ActionView
|
4
|
+
# Responsible for uninstalling the default `ActionView::LogSubscriber` and installing
|
5
|
+
# the LogtailLogSubscriber.
|
6
|
+
#
|
7
|
+
# @private
|
8
|
+
class LogSubscriber < Integrator
|
9
|
+
def initialize
|
10
|
+
require "action_view/log_subscriber"
|
11
|
+
require "logtail-rails/action_view/log_subscriber/logtail_log_subscriber"
|
12
|
+
rescue LoadError => e
|
13
|
+
raise RequirementNotMetError.new(e.message)
|
14
|
+
end
|
15
|
+
|
16
|
+
def integrate!
|
17
|
+
return true if Logtail::Integrations::Rails::ActiveSupportLogSubscriber.subscribed?(:action_view, LogtailLogSubscriber)
|
18
|
+
|
19
|
+
Logtail::Integrations::Rails::ActiveSupportLogSubscriber.unsubscribe!(:action_view, ::ActionView::LogSubscriber)
|
20
|
+
LogtailLogSubscriber.attach_to(:action_view)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Logtail
|
2
|
+
module Integrations
|
3
|
+
module ActionView
|
4
|
+
class LogSubscriber < Integrator
|
5
|
+
|
6
|
+
# The log subscriber that replaces the default `ActionView::LogSubscriber`.
|
7
|
+
# The intent of this subscriber is to, as transparently as possible, properly
|
8
|
+
# track events that are being logged here.
|
9
|
+
#
|
10
|
+
# @private
|
11
|
+
class LogtailLogSubscriber < ::ActionView::LogSubscriber
|
12
|
+
def render_template(event)
|
13
|
+
return true if silence?
|
14
|
+
|
15
|
+
info do
|
16
|
+
full_name = from_rails_root(event.payload[:identifier])
|
17
|
+
message = " Rendered #{full_name}"
|
18
|
+
message << " within #{from_rails_root(event.payload[:layout])}" if event.payload[:layout]
|
19
|
+
message << " (#{event.duration.round(1)}ms)"
|
20
|
+
|
21
|
+
Events::TemplateRender.new(
|
22
|
+
name: full_name,
|
23
|
+
duration_ms: event.duration,
|
24
|
+
message: message
|
25
|
+
)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def render_partial(event)
|
30
|
+
return true if silence?
|
31
|
+
|
32
|
+
info do
|
33
|
+
full_name = from_rails_root(event.payload[:identifier])
|
34
|
+
message = " Rendered #{full_name}"
|
35
|
+
message << " within #{from_rails_root(event.payload[:layout])}" if event.payload[:layout]
|
36
|
+
message << " (#{event.duration.round(1)}ms)"
|
37
|
+
message << " #{cache_message(event.payload)}" if event.payload.key?(:cache_hit)
|
38
|
+
|
39
|
+
Events::TemplateRender.new(
|
40
|
+
name: full_name,
|
41
|
+
duration_ms: event.duration,
|
42
|
+
message: message
|
43
|
+
)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def render_collection(event)
|
48
|
+
return true if silence?
|
49
|
+
|
50
|
+
if respond_to?(:render_count, true)
|
51
|
+
info do
|
52
|
+
identifier = event.payload[:identifier] || "templates"
|
53
|
+
full_name = from_rails_root(identifier)
|
54
|
+
message = " Rendered collection of #{full_name}" \
|
55
|
+
" #{render_count(event.payload)} (#{event.duration.round(1)}ms)"
|
56
|
+
|
57
|
+
Events::TemplateRender.new(
|
58
|
+
name: full_name,
|
59
|
+
duration_ms: event.duration,
|
60
|
+
message: message
|
61
|
+
)
|
62
|
+
end
|
63
|
+
else
|
64
|
+
# Older versions of rails delegate this method to #render_template
|
65
|
+
render_template(event)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
def log_rendering_start(*args)
|
71
|
+
# Consolidates 2 template rendering events into 1. We don't need 2 events for
|
72
|
+
# rendering a template. If you disagree, please feel free to open a PR and we
|
73
|
+
# can make this an option.
|
74
|
+
# *args is to be future proof for Rails 6.1, which adds another method argument
|
75
|
+
end
|
76
|
+
|
77
|
+
def silence?
|
78
|
+
ActionView.silence?
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "logtail-rails/active_record/log_subscriber"
|
2
|
+
|
3
|
+
module Logtail
|
4
|
+
module Integrations
|
5
|
+
# Module for holding *all* ActiveRecord integrations. See {Integration} for
|
6
|
+
# configuration details for all integrations.
|
7
|
+
module ActiveRecord
|
8
|
+
extend Integration
|
9
|
+
|
10
|
+
def self.integrate!
|
11
|
+
return false if !enabled?
|
12
|
+
|
13
|
+
LogSubscriber.integrate!
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require "logtail-rails/active_record/log_subscriber/logtail_log_subscriber"
|
2
|
+
|
3
|
+
module Logtail
|
4
|
+
module Integrations
|
5
|
+
module ActiveRecord
|
6
|
+
# Responsible for uninstalling the default `ActiveRecord::LogSubscriber` and replacing it
|
7
|
+
# with the `LogtailLogSubscriber`.
|
8
|
+
#
|
9
|
+
# @private
|
10
|
+
class LogSubscriber < Integrator
|
11
|
+
def integrate!
|
12
|
+
return true if Logtail::Integrations::Rails::ActiveSupportLogSubscriber.subscribed?(:active_record, LogtailLogSubscriber)
|
13
|
+
|
14
|
+
Logtail::Integrations::Rails::ActiveSupportLogSubscriber.unsubscribe!(:active_record, ::ActiveRecord::LogSubscriber)
|
15
|
+
LogtailLogSubscriber.attach_to(:active_record)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# We require all of ActiveRecord because the #logger method in ::ActiveRecord::LogSubscriber
|
2
|
+
# uses ActiveRecord::Base. We can't require active_record/base directly because ActiveRecord
|
3
|
+
# does not require files properly and we receive unintialized constant errors.
|
4
|
+
require "active_record"
|
5
|
+
require "active_record/log_subscriber"
|
6
|
+
|
7
|
+
module Logtail
|
8
|
+
module Integrations
|
9
|
+
module ActiveRecord
|
10
|
+
class LogSubscriber < Integrator
|
11
|
+
# The log subscriber that replaces the default `ActiveRecord::LogSubscriber`.
|
12
|
+
# The intent of this subscriber is to, as transparently as possible, properly
|
13
|
+
# track events that are being logged here. This LogSubscriber will never change
|
14
|
+
# default behavior / log messages.
|
15
|
+
#
|
16
|
+
# @private
|
17
|
+
class LogtailLogSubscriber < ::ActiveRecord::LogSubscriber
|
18
|
+
def sql(event)
|
19
|
+
return true if silence?
|
20
|
+
|
21
|
+
r = super(event)
|
22
|
+
|
23
|
+
if @message
|
24
|
+
payload = event.payload
|
25
|
+
|
26
|
+
sql_event = Events::SQLQuery.new(
|
27
|
+
sql: payload[:sql],
|
28
|
+
duration_ms: event.duration,
|
29
|
+
message: @message,
|
30
|
+
)
|
31
|
+
|
32
|
+
logger.debug sql_event
|
33
|
+
|
34
|
+
@message = nil
|
35
|
+
end
|
36
|
+
|
37
|
+
r
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
def debug(message)
|
42
|
+
@message = message
|
43
|
+
end
|
44
|
+
|
45
|
+
def silence?
|
46
|
+
ActiveRecord.silence?
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Logtail
|
2
|
+
module Integrations
|
3
|
+
module Rails
|
4
|
+
# @private
|
5
|
+
module ActiveSupportLogSubscriber
|
6
|
+
extend self
|
7
|
+
|
8
|
+
def find(component, type)
|
9
|
+
::ActiveSupport::LogSubscriber.log_subscribers.find do |subscriber|
|
10
|
+
subscriber.class == type
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def subscribed?(component, type)
|
15
|
+
!find(component, type).nil?
|
16
|
+
end
|
17
|
+
|
18
|
+
# I don't know why this has to be so complicated, but it is. This code was taken from
|
19
|
+
# lograge :/
|
20
|
+
def unsubscribe!(component, type)
|
21
|
+
subscriber = find(component, type)
|
22
|
+
|
23
|
+
if !subscriber
|
24
|
+
raise "We could not find a log subscriber for #{component.inspect} of type #{type.inspect}"
|
25
|
+
end
|
26
|
+
|
27
|
+
events = subscriber.public_methods(false).reject { |method| method.to_s == 'call' }
|
28
|
+
events.each do |event|
|
29
|
+
::ActiveSupport::Notifications.notifier.listeners_for("#{event}.#{component}").each do |listener|
|
30
|
+
if listener.instance_variable_get('@delegate') == subscriber
|
31
|
+
::ActiveSupport::Notifications.unsubscribe listener
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'logtail/config'
|
2
|
+
require 'logtail-rack/config'
|
3
|
+
require 'logtail-rails/config/action_view'
|
4
|
+
require 'logtail-rails/config/active_record'
|
5
|
+
require 'logtail-rails/config/action_controller'
|
6
|
+
|
7
|
+
Logtail::Config.instance.define_singleton_method(:logrageify!) do
|
8
|
+
integrations.action_controller.silence = true
|
9
|
+
integrations.action_view.silence = true
|
10
|
+
integrations.active_record.silence = true
|
11
|
+
integrations.rack.http_events.collapse_into_single_event = true
|
12
|
+
end
|