rails_semantic_logger 4.2.1 → 4.3.0

Sign up to get free protection for your applications and to get access to all the features.
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