rails_semantic_logger 4.2.1 → 4.3.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.
Files changed (24) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -6
  3. data/Rakefile +2 -2
  4. data/lib/rails_semantic_logger.rb +35 -0
  5. data/lib/rails_semantic_logger/action_controller/log_subscriber.rb +108 -0
  6. data/lib/rails_semantic_logger/action_view/log_subscriber.rb +108 -0
  7. data/lib/rails_semantic_logger/active_record/log_subscriber.rb +186 -0
  8. data/lib/rails_semantic_logger/delayed_job/plugin.rb +11 -0
  9. data/lib/rails_semantic_logger/engine.rb +80 -70
  10. data/lib/rails_semantic_logger/extensions/action_controller/live.rb +5 -3
  11. data/lib/rails_semantic_logger/extensions/action_dispatch/debug_exceptions.rb +8 -6
  12. data/lib/rails_semantic_logger/extensions/action_view/streaming_template_renderer.rb +8 -5
  13. data/lib/rails_semantic_logger/extensions/active_job/logging.rb +8 -5
  14. data/lib/rails_semantic_logger/extensions/active_model_serializers/logging.rb +11 -8
  15. data/lib/rails_semantic_logger/extensions/rails/server.rb +2 -2
  16. data/lib/rails_semantic_logger/rack/logger.rb +103 -0
  17. data/lib/rails_semantic_logger/version.rb +2 -2
  18. metadata +13 -14
  19. data/lib/rails_semantic_logger/extensions/action_controller/log_subscriber.rb +0 -111
  20. data/lib/rails_semantic_logger/extensions/action_controller/log_subscriber_processing.rb +0 -28
  21. data/lib/rails_semantic_logger/extensions/action_view/log_subscriber.rb +0 -12
  22. data/lib/rails_semantic_logger/extensions/active_record/log_subscriber.rb +0 -102
  23. data/lib/rails_semantic_logger/extensions/rails/rack/logger.rb +0 -63
  24. data/lib/rails_semantic_logger/extensions/rails/rack/logger_info_as_debug.rb +0 -30
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d56fd59e95eb5982a96ce3dd581a3249503c67e83751948648a50c575a357d24
4
- data.tar.gz: bbe41e7f698388fd7b14ea3096f62d0316ef51e2ee4fd961f0a5046fe46ad97c
3
+ metadata.gz: b63806087ae37b6ed3da41a1caf8414dddb0509b067cadf4583720fd2b397d0c
4
+ data.tar.gz: 04a84700b26831870361b5664332f7bcade1d1e07a4c1cc0b2d243148adc9fff
5
5
  SHA512:
6
- metadata.gz: fa8f0f7cd9da16e76a3c0803f249710185e1adda00475dc6b4f88605c3893064114f4d7d763a8638ea3dd83e054e42233f2736041b98a259f4f3a12d6df825cc
7
- data.tar.gz: 3a025e94a795aabcf96e612eb02ecec265656f5f8939a81908abb48464703693bdd862de6d5a5dc9cd0163b4bdc473d14c534ad2d6ceb2e09f3a4c9cfd210247
6
+ metadata.gz: 59e6c6bdf21d7587b20d3250a00d6f212c99a2ad58c018c832662cf468167dd64a88148d48d19b77b8ea73b4725650124b1e596adc043bec7d5b289919fe7f18
7
+ data.tar.gz: 9836a2ccdd1107f38303e1180a2d6a2fc28945a8f963115126fd833fb4ff62a833bc78dc2ffb6209ee76f4794f5dd01e922ec000d5ada966201a03bd43b1d23b
data/README.md CHANGED
@@ -1,7 +1,5 @@
1
- # rails_semantic_logger
2
- ![](https://img.shields.io/gem/v/rails_semantic_logger.svg) ![](https://img.shields.io/gem/dt/semantic_logger.svg) ![](https://img.shields.io/badge/status-production%20ready-blue.svg)
3
-
4
- Next generation logging system for Rails to support highly concurrent, high throughput, low latency systems
1
+ # Rails Semantic Logger
2
+ [![Gem Version](https://img.shields.io/gem/v/rails_semantic_logger.svg)](https://rubygems.org/gems/rails_semantic_logger) [![Build Status](https://travis-ci.org/rocketjob/rails_semantic_logger.svg?branch=master)](https://travis-ci.org/rocketjob/rails_semantic_logger) [![Downloads](https://img.shields.io/gem/dt/rails_semantic_logger.svg)](https://rubygems.org/gems/rails_semantic_logger) [![License](https://img.shields.io/badge/license-Apache%202.0-brightgreen.svg)](http://opensource.org/licenses/Apache-2.0) ![](https://img.shields.io/badge/status-Production%20Ready-blue.svg) [![Gitter chat](https://img.shields.io/badge/IRC%20(gitter)-Support-brightgreen.svg)](https://gitter.im/rocketjob/support)
5
3
 
6
4
  Rails Semantic Logger replaces the Rails default logger with [Semantic Logger](http://github.com/rocketjob/semantic_logger)
7
5
 
@@ -13,8 +11,7 @@ For complete documentation see: http://rocketjob.github.io/semantic_logger/rails
13
11
 
14
12
  ## Supports
15
13
 
16
- - Ruby 2.1, 2.2 (or above) Or, JRuby 9.0 (or above)
17
- - Rails 4, 5 (or above)
14
+ - Rails 3.2, 4, 5
18
15
 
19
16
  ## Author
20
17
 
data/Rakefile CHANGED
@@ -9,7 +9,7 @@ task :gem do
9
9
  system 'gem build rails_semantic_logger.gemspec'
10
10
  end
11
11
 
12
- task :publish => :gem do
12
+ task publish: :gem do
13
13
  system "git tag -a v#{RailsSemanticLogger::VERSION} -m 'Tagging #{RailsSemanticLogger::VERSION}'"
14
14
  system 'git push --tags'
15
15
  system "gem push rails_semantic_logger-#{RailsSemanticLogger::VERSION}.gem"
@@ -23,7 +23,7 @@ Rake::TestTask.new(:test) do |t|
23
23
  end
24
24
 
25
25
  # By default run tests against all appraisals
26
- if !ENV["APPRAISAL_INITIALIZED"] && !ENV["TRAVIS"]
26
+ if !ENV['APPRAISAL_INITIALIZED'] && !ENV['TRAVIS']
27
27
  require 'appraisal'
28
28
  task default: :appraisal
29
29
  else
@@ -3,4 +3,39 @@ require 'rails_semantic_logger/extensions/rails/server' if defined?(Rails::Serve
3
3
  require 'rails_semantic_logger/engine'
4
4
 
5
5
  module RailsSemanticLogger
6
+ module ActionController
7
+ autoload :LogSubscriber, 'rails_semantic_logger/action_controller/log_subscriber'
8
+ end
9
+ module ActionView
10
+ autoload :LogSubscriber, 'rails_semantic_logger/action_view/log_subscriber'
11
+ end
12
+ module ActiveRecord
13
+ autoload :LogSubscriber, 'rails_semantic_logger/active_record/log_subscriber'
14
+ end
15
+ module Rack
16
+ autoload :Logger, 'rails_semantic_logger/rack/logger'
17
+ end
18
+ module DelayedJob
19
+ autoload :Plugin, 'rails_semantic_logger/delayed_job/plugin.rb'
20
+ end
21
+
22
+ # Swap an existing subscriber with a new one
23
+ def self.swap_subscriber(old_class, new_class, notifier)
24
+ subscribers = ActiveSupport::LogSubscriber.subscribers.select { |s| s.is_a?(old_class) }
25
+ subscribers.each { |subscriber| unattach(subscriber) }
26
+
27
+ new_class.attach_to(notifier)
28
+ end
29
+
30
+ def self.unattach(subscriber)
31
+ subscriber.patterns.each do |event|
32
+ ActiveSupport::Notifications.notifier.listeners_for(event).each do |sub|
33
+ next unless sub.instance_variable_get(:@delegate) == subscriber
34
+ ActiveSupport::Notifications.unsubscribe(sub)
35
+ end
36
+ end
37
+
38
+ ActiveSupport::LogSubscriber.subscribers.delete(subscriber)
39
+ end
40
+ private_class_method :unattach
6
41
  end
@@ -0,0 +1,108 @@
1
+ module RailsSemanticLogger
2
+ module ActionController
3
+ class LogSubscriber < ActiveSupport::LogSubscriber
4
+ INTERNAL_PARAMS = %w[controller action format _method only_path].freeze
5
+
6
+ # Log as debug to hide Processing messages in production
7
+ def start_processing(event)
8
+ controller_logger(event).debug { "Processing ##{event.payload[:action]}" }
9
+ end
10
+
11
+ def process_action(event)
12
+ controller_logger(event).info do
13
+ payload = event.payload.dup
14
+
15
+ # Unused, but needed for Devise 401 status code monkey patch to still work.
16
+ ::ActionController::Base.log_process_action(payload)
17
+
18
+ # According to PR https://github.com/rocketjob/rails_semantic_logger/pull/37/files
19
+ # payload[:params] is not always a Hash.
20
+ payload[:params] = payload[:params].to_unsafe_h unless payload[:params].is_a?(Hash)
21
+ payload[:params].except!(*INTERNAL_PARAMS)
22
+ payload.delete(:params) if payload[:params].empty?
23
+
24
+ format = payload[:format]
25
+ payload[:format] = format.to_s.upcase if format.is_a?(Symbol)
26
+
27
+ payload[:path] = extract_path(payload[:path]) if payload.key?(:path)
28
+
29
+ exception = payload.delete(:exception)
30
+ if payload[:status].nil? && exception.present?
31
+ exception_class_name = exception.first
32
+ payload[:status] = ActionDispatch::ExceptionWrapper.status_code_for_exception(exception_class_name)
33
+ end
34
+
35
+ # Rounds off the runtimes. For example, :view_runtime, :mongo_runtime, etc.
36
+ payload.keys.each do |key|
37
+ payload[key] = payload[key].to_f.round(2) if key.to_s =~ /(.*)_runtime/
38
+ end
39
+
40
+ payload[:status_message] = ::Rack::Utils::HTTP_STATUS_CODES[payload[:status]] if payload[:status].present?
41
+ # Causes excessive log output with Rails 5 RC1
42
+ payload.delete(:headers)
43
+
44
+ {
45
+ message: "Completed ##{payload[:action]}",
46
+ duration: event.duration,
47
+ payload: payload
48
+ }
49
+ end
50
+ end
51
+
52
+ def halted_callback(event)
53
+ controller_logger(event).info { "Filter chain halted as #{event.payload[:filter].inspect} rendered or redirected" }
54
+ end
55
+
56
+ def send_file(event)
57
+ controller_logger(event).info(message: 'Sent file', payload: {path: event.payload[:path]}, duration: event.duration)
58
+ end
59
+
60
+ def redirect_to(event)
61
+ controller_logger(event).info(message: 'Redirected to', payload: {location: event.payload[:location]})
62
+ end
63
+
64
+ def send_data(event)
65
+ controller_logger(event).info(message: 'Sent data', payload: {file_name: event.payload[:filename]}, duration: event.duration)
66
+ end
67
+
68
+ def unpermitted_parameters(event)
69
+ controller_logger(event).debug do
70
+ unpermitted_keys = event.payload[:keys]
71
+ "Unpermitted parameter#{'s' if unpermitted_keys.size > 1}: #{unpermitted_keys.join(', ')}"
72
+ end
73
+ end
74
+
75
+ %w[write_fragment read_fragment exist_fragment?
76
+ expire_fragment expire_page write_page].each do |method|
77
+ class_eval <<-METHOD, __FILE__, __LINE__ + 1
78
+ def #{method}(event)
79
+ # enable_fragment_cache_logging as of Rails 5
80
+ return if ::ActionController::Base.respond_to?(:enable_fragment_cache_logging) && !::ActionController::Base.enable_fragment_cache_logging
81
+ controller_logger(event).info do
82
+ key_or_path = event.payload[:key] || event.payload[:path]
83
+ {message: "#{method.to_s.humanize} \#{key_or_path}", duration: event.duration}
84
+ end
85
+ end
86
+ METHOD
87
+ end
88
+
89
+ private
90
+
91
+ # Returns the logger for the supplied event.
92
+ # Returns ActionController::Base.logger if no controller is present
93
+ def controller_logger(event)
94
+ controller = event.payload[:controller]
95
+ return ::ActionController::Base.logger unless controller
96
+
97
+ controller.constantize.logger || ::ActionController::Base.logger
98
+ rescue NameError
99
+ ::ActionController::Base.logger
100
+ end
101
+
102
+ def extract_path(path)
103
+ index = path.index('?')
104
+ index ? path[0, index] : path
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,108 @@
1
+ require 'active_support/log_subscriber'
2
+
3
+ module RailsSemanticLogger
4
+ module ActionView
5
+ # Output Semantic logs from Action View.
6
+ class LogSubscriber < ActiveSupport::LogSubscriber
7
+ VIEWS_PATTERN = /^app\/views\//
8
+
9
+ class << self
10
+ attr_reader :logger
11
+ attr_accessor :rendered_log_level
12
+ end
13
+
14
+ def initialize
15
+ @rails_root = nil
16
+ super
17
+ end
18
+
19
+ def render_template(event)
20
+ return unless should_log?
21
+
22
+ payload = {
23
+ template: from_rails_root(event.payload[:identifier])
24
+ }
25
+ payload[:within] = from_rails_root(event.payload[:layout]) if event.payload[:layout]
26
+
27
+ logger.measure(
28
+ self.class.rendered_log_level,
29
+ 'Rendered',
30
+ payload: payload,
31
+ duration: event.duration
32
+ )
33
+ end
34
+
35
+ def render_partial(event)
36
+ return unless should_log?
37
+
38
+ payload = {
39
+ partial: from_rails_root(event.payload[:identifier])
40
+ }
41
+ payload[:within] = from_rails_root(event.payload[:layout]) if event.payload[:layout]
42
+ payload[:cache] = payload[:cache_hit] unless event.payload[:cache_hit].nil?
43
+
44
+ logger.measure(
45
+ self.class.rendered_log_level,
46
+ 'Rendered',
47
+ payload: payload,
48
+ duration: event.duration
49
+ )
50
+ end
51
+
52
+ def render_collection(event)
53
+ return unless should_log?
54
+
55
+ identifier = event.payload[:identifier] || 'templates'
56
+
57
+ payload = {
58
+ template: from_rails_root(identifier),
59
+ count: event.payload[:count]
60
+ }
61
+ payload[:cache_hits] = payload[:cache_hits] if payload[:cache_hits]
62
+
63
+ logger.measure(
64
+ self.class.rendered_log_level,
65
+ 'Rendered',
66
+ payload: payload,
67
+ duration: event.duration
68
+ )
69
+ end
70
+
71
+ def start(name, id, payload)
72
+ if (name == 'render_template.action_view') && should_log?
73
+ payload = {template: from_rails_root(payload[:identifier])}
74
+ payload[:within] = from_rails_root(payload[:layout]) if payload[:layout]
75
+
76
+ logger.send(self.class.rendered_log_level, message: 'Rendering', payload: payload)
77
+ end
78
+
79
+ super
80
+ end
81
+
82
+ private
83
+
84
+ @logger = SemanticLogger['ActionView']
85
+ @rendered_log_level = :debug
86
+
87
+ EMPTY = ''.freeze
88
+
89
+ def should_log?
90
+ logger.send("#{self.class.rendered_log_level}?")
91
+ end
92
+
93
+ def from_rails_root(string)
94
+ string = string.sub(rails_root, EMPTY)
95
+ string.sub!(VIEWS_PATTERN, EMPTY)
96
+ string
97
+ end
98
+
99
+ def rails_root
100
+ @rails_root ||= "#{Rails.root}/"
101
+ end
102
+
103
+ def logger
104
+ self.class.logger
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,186 @@
1
+ module RailsSemanticLogger
2
+ module ActiveRecord
3
+ class LogSubscriber < ActiveSupport::LogSubscriber
4
+ IGNORE_PAYLOAD_NAMES = %w[SCHEMA EXPLAIN].freeze
5
+
6
+ class << self
7
+ attr_reader :logger
8
+ end
9
+
10
+ def self.runtime=(value)
11
+ ::ActiveRecord::RuntimeRegistry.sql_runtime = value
12
+ end
13
+
14
+ def self.runtime
15
+ ::ActiveRecord::RuntimeRegistry.sql_runtime ||= 0
16
+ end
17
+
18
+ def self.reset_runtime
19
+ rt = runtime
20
+ self.runtime = 0
21
+ rt
22
+ end
23
+
24
+ def sql(event)
25
+ self.class.runtime += event.duration
26
+ return unless logger.debug?
27
+
28
+ payload = event.payload
29
+ name = payload[:name]
30
+ return if IGNORE_PAYLOAD_NAMES.include?(name)
31
+
32
+ log_payload = {sql: payload[:sql]}
33
+ log_payload[:binds] = bind_values(payload) unless (payload[:binds] || []).empty?
34
+
35
+ log = {
36
+ message: name,
37
+ payload: log_payload,
38
+ duration: event.duration
39
+ }
40
+
41
+ # Log the location of the query itself.
42
+ if logger.send(:level_index) >= SemanticLogger.backtrace_level_index
43
+ log[:backtrace] = SemanticLogger::Utils.strip_backtrace
44
+ end
45
+
46
+ logger.debug(log)
47
+ end
48
+
49
+ private
50
+
51
+ @logger = SemanticLogger['ActiveRecord']
52
+
53
+ # When multiple values are received for a single bound field, it is converted into an array
54
+ def add_bind_value(binds, key, value)
55
+ key = key.downcase.to_sym
56
+ value = (Array(binds[key]) << value) if binds.key?(key)
57
+ binds[key] = value
58
+ end
59
+
60
+ def logger
61
+ self.class.logger
62
+ end
63
+
64
+ #
65
+ # Rails 3,4,5 hell trying to get the bind values
66
+ #
67
+
68
+ def bind_values_v3(payload)
69
+ binds = {}
70
+ payload[:binds].each do |col, v|
71
+ if col
72
+ add_bind_value(binds, col.name, v)
73
+ else
74
+ binds[nil] = v
75
+ end
76
+ end
77
+ binds
78
+ end
79
+
80
+ def bind_values_v4(payload)
81
+ binds = {}
82
+ payload[:binds].each do |col, v|
83
+ attr_name, value = render_bind(col, v)
84
+ add_bind_value(binds, attr_name, value)
85
+ end
86
+ binds
87
+ end
88
+
89
+ def bind_values_v5_0_0(payload)
90
+ binds = {}
91
+ payload[:binds].each do |attr|
92
+ attr_name, value = render_bind(attr)
93
+ add_bind_value(binds, attr_name, value)
94
+ end
95
+ binds
96
+ end
97
+
98
+ def bind_values_v5_0_3(payload)
99
+ binds = {}
100
+ casted_params = type_casted_binds(payload[:binds], payload[:type_casted_binds])
101
+ payload[:binds].zip(casted_params).map do |attr, value|
102
+ attr_name, value = render_bind(attr, value)
103
+ add_bind_value(binds, attr_name, value)
104
+ end
105
+ binds
106
+ end
107
+
108
+ def bind_values_v5_1_5(payload)
109
+ binds = {}
110
+ casted_params = type_casted_binds(payload[:type_casted_binds])
111
+ payload[:binds].zip(casted_params).map do |attr, value|
112
+ attr_name, value = render_bind(attr, value)
113
+ add_bind_value(binds, attr_name, value)
114
+ end
115
+ binds
116
+ end
117
+
118
+ def render_bind_v4_2(column, value)
119
+ if column
120
+ if column.binary?
121
+ # This specifically deals with the PG adapter that casts bytea columns into a Hash.
122
+ value = value[:value] if value.is_a?(Hash)
123
+ value = value ? "<#{value.bytesize} bytes of binary data>" : '<NULL binary data>'
124
+ end
125
+
126
+ [column.name, value]
127
+ else
128
+ [nil, value]
129
+ end
130
+ end
131
+
132
+ def render_bind_v5_0_0(attribute)
133
+ value =
134
+ if attribute.type.binary? && attribute.value
135
+ if attribute.value.is_a?(Hash)
136
+ "<#{attribute.value_for_database.to_s.bytesize} bytes of binary data>"
137
+ else
138
+ "<#{attribute.value.bytesize} bytes of binary data>"
139
+ end
140
+ else
141
+ attribute.value_for_database
142
+ end
143
+
144
+ [attribute.name, value]
145
+ end
146
+
147
+ def render_bind_v5_0_3(attr, value)
148
+ if attr.is_a?(Array)
149
+ attr = attr.first
150
+ elsif attr.type.binary? && attr.value
151
+ value = "<#{attr.value_for_database.to_s.bytesize} bytes of binary data>"
152
+ end
153
+
154
+ [attr&.name, value]
155
+ end
156
+
157
+ def type_casted_binds_v5_0_3(binds, casted_binds)
158
+ casted_binds || ActiveRecord::Base.connection.type_casted_binds(binds)
159
+ end
160
+
161
+ def type_casted_binds_v5_1_5(casted_binds)
162
+ casted_binds.respond_to?(:call) ? casted_binds.call : casted_binds
163
+ end
164
+
165
+ if Rails::VERSION::MAJOR == 5 && Rails::VERSION::MINOR.zero? && Rails::VERSION::TINY <= 2 # 5.0.0 - 5.0.2
166
+ alias bind_values bind_values_v5_0_0
167
+ alias render_bind render_bind_v5_0_0
168
+ elsif Rails::VERSION::MAJOR >= 5 &&
169
+ ((Rails::VERSION::MINOR.zero? && Rails::VERSION::TINY <= 6) ||
170
+ (Rails::VERSION::MINOR == 1 && Rails::VERSION::TINY <= 4)) # 5.0.3 - 5.0.6 && 5.1.0 - 5.1.4
171
+ alias bind_values bind_values_v5_0_3
172
+ alias render_bind render_bind_v5_0_3
173
+ alias type_casted_binds type_casted_binds_v5_0_3
174
+ elsif Rails::VERSION::MAJOR >= 5 # ~> 5.1.5 && ~> 5.0.7
175
+ alias bind_values bind_values_v5_1_5
176
+ alias render_bind render_bind_v5_0_3
177
+ alias type_casted_binds type_casted_binds_v5_1_5
178
+ elsif Rails.version.to_i >= 4 # 4.x
179
+ alias bind_values bind_values_v4
180
+ alias render_bind render_bind_v4_2
181
+ else # 3.x
182
+ alias bind_values bind_values_v3
183
+ end
184
+ end
185
+ end
186
+ end