rails_semantic_logger 4.1.3 → 4.4.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 (25) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +13 -6
  3. data/Rakefile +2 -2
  4. data/lib/rails_semantic_logger/action_controller/log_subscriber.rb +114 -0
  5. data/lib/rails_semantic_logger/action_view/log_subscriber.rb +108 -0
  6. data/lib/rails_semantic_logger/active_record/log_subscriber.rb +186 -0
  7. data/lib/rails_semantic_logger/delayed_job/plugin.rb +11 -0
  8. data/lib/rails_semantic_logger/engine.rb +82 -151
  9. data/lib/rails_semantic_logger/extensions/action_controller/live.rb +5 -3
  10. data/lib/rails_semantic_logger/extensions/action_dispatch/debug_exceptions.rb +8 -6
  11. data/lib/rails_semantic_logger/extensions/action_view/streaming_template_renderer.rb +8 -5
  12. data/lib/rails_semantic_logger/extensions/active_job/logging.rb +129 -5
  13. data/lib/rails_semantic_logger/extensions/active_model_serializers/logging.rb +11 -8
  14. data/lib/rails_semantic_logger/extensions/rails/server.rb +2 -2
  15. data/lib/rails_semantic_logger/options.rb +117 -0
  16. data/lib/rails_semantic_logger/rack/logger.rb +103 -0
  17. data/lib/rails_semantic_logger/version.rb +2 -2
  18. data/lib/rails_semantic_logger.rb +37 -0
  19. metadata +16 -17
  20. data/lib/rails_semantic_logger/extensions/action_controller/log_subscriber.rb +0 -107
  21. data/lib/rails_semantic_logger/extensions/action_controller/log_subscriber_processing.rb +0 -28
  22. data/lib/rails_semantic_logger/extensions/action_view/log_subscriber.rb +0 -12
  23. data/lib/rails_semantic_logger/extensions/active_record/log_subscriber.rb +0 -44
  24. data/lib/rails_semantic_logger/extensions/rails/rack/logger.rb +0 -63
  25. 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
- SHA1:
3
- metadata.gz: 607046851ee5bfb0335e577fbb87f9c3ae6ab93f
4
- data.tar.gz: 3375c64b102e5461ba50412a3495c898524f63df
2
+ SHA256:
3
+ metadata.gz: c831151af372b8348f982154c5a02da3e3373f0156f36952dcebc421667f91fc
4
+ data.tar.gz: 82e796f801009b66c39daf81b9526d5be20f48ecf81cd5159a7d659ba64f0cdc
5
5
  SHA512:
6
- metadata.gz: 44f58b19256318c9fa3acb07fb08a862000acf7e15bfe27dda9fdb29052627da9c484da91fbefde02840cacdd8d7ec7556189a5297c898db39b9fde19fd1d491
7
- data.tar.gz: 860b06c8b1083e12befe6b074e1a8d0281186fa30a3f02f5342465bd44c50905a3703f90071b376a04db8c01b897d6273ab6b4fac4d81a0d6115cbd6ca5b5322
6
+ metadata.gz: 564d2e2b9a0bdb7140dd37a9be1aaaccbeed5c06f60cd7c4c31a7d886502d0e77433da3887e8262b4d614752c8a7f2b677fc8be8d9796e8e8af772252c84c2e2
7
+ data.tar.gz: 1a22dc7a52079a3845a5453f85eafda8edda153166afc44fe973cbe02f4e5d5b0f145c8bd506da972afcf942b0f9ccbbc802c1c18aab20424d54fa37b3bef685
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
 
@@ -11,10 +9,19 @@ Rails Semantic Logger replaces the Rails default logger with [Semantic Logger](h
11
9
 
12
10
  For complete documentation see: http://rocketjob.github.io/semantic_logger/rails
13
11
 
12
+ ## Upgrading to Semantic Logger v4.4
13
+
14
+ With some forking frameworks it is necessary to call `reopen` after the fork. With v4.4 the
15
+ workaround for Ruby 2.5 crashes is no longer needed.
16
+ I.e. Please remove the following line if being called anywhere:
17
+
18
+ ~~~ruby
19
+ SemanticLogger::Processor.instance.instance_variable_set(:@queue, Queue.new)
20
+ ~~~
21
+
14
22
  ## Supports
15
23
 
16
- - Ruby 1.9.3, 2.0, 2.1, 2.2 (or above) Or, JRuby 1.7, 9.0 (or above)
17
- - Rails 3.2, 4, 5 (or above)
24
+ - Rails 3.2, 4, 5
18
25
 
19
26
  ## Author
20
27
 
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
@@ -0,0 +1,114 @@
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
+ params = payload[:params]
45
+ if params
46
+ # When logging to JSON the entire tempfile is logged, so convert it to a string.
47
+ params['file'] = params['file'].inspect if params['file']
48
+ end
49
+
50
+ {
51
+ message: "Completed ##{payload[:action]}",
52
+ duration: event.duration,
53
+ payload: payload
54
+ }
55
+ end
56
+ end
57
+
58
+ def halted_callback(event)
59
+ controller_logger(event).info { "Filter chain halted as #{event.payload[:filter].inspect} rendered or redirected" }
60
+ end
61
+
62
+ def send_file(event)
63
+ controller_logger(event).info(message: 'Sent file', payload: {path: event.payload[:path]}, duration: event.duration)
64
+ end
65
+
66
+ def redirect_to(event)
67
+ controller_logger(event).info(message: 'Redirected to', payload: {location: event.payload[:location]})
68
+ end
69
+
70
+ def send_data(event)
71
+ controller_logger(event).info(message: 'Sent data', payload: {file_name: event.payload[:filename]}, duration: event.duration)
72
+ end
73
+
74
+ def unpermitted_parameters(event)
75
+ controller_logger(event).debug do
76
+ unpermitted_keys = event.payload[:keys]
77
+ "Unpermitted parameter#{'s' if unpermitted_keys.size > 1}: #{unpermitted_keys.join(', ')}"
78
+ end
79
+ end
80
+
81
+ %w[write_fragment read_fragment exist_fragment?
82
+ expire_fragment expire_page write_page].each do |method|
83
+ class_eval <<-METHOD, __FILE__, __LINE__ + 1
84
+ def #{method}(event)
85
+ # enable_fragment_cache_logging as of Rails 5
86
+ return if ::ActionController::Base.respond_to?(:enable_fragment_cache_logging) && !::ActionController::Base.enable_fragment_cache_logging
87
+ controller_logger(event).info do
88
+ key_or_path = event.payload[:key] || event.payload[:path]
89
+ {message: "#{method.to_s.humanize} \#{key_or_path}", duration: event.duration}
90
+ end
91
+ end
92
+ METHOD
93
+ end
94
+
95
+ private
96
+
97
+ # Returns the logger for the supplied event.
98
+ # Returns ActionController::Base.logger if no controller is present
99
+ def controller_logger(event)
100
+ controller = event.payload[:controller]
101
+ return ::ActionController::Base.logger unless controller
102
+
103
+ controller.constantize.logger || ::ActionController::Base.logger
104
+ rescue NameError
105
+ ::ActionController::Base.logger
106
+ end
107
+
108
+ def extract_path(path)
109
+ index = path.index('?')
110
+ index ? path[0, index] : path
111
+ end
112
+ end
113
+ end
114
+ 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
@@ -0,0 +1,11 @@
1
+ module RailsSemanticLogger
2
+ module DelayedJob
3
+ class Plugin < Delayed::Plugin
4
+ callbacks do |lifecycle|
5
+ lifecycle.before(:execute) do |job, &block|
6
+ ::SemanticLogger.reopen
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end