logtail-rails 0.1.0
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 +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
|