ezlog 0.2.2 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: af49b0170f9c53fe3f0b41ced3fd1afe3a420402bbb64b62318bda81144d8c23
4
- data.tar.gz: 6c85e8f81ee2848bba6ad407aafbf0ce8b567523801cf133ac3fa795fbb6b14c
3
+ metadata.gz: 93492a6b3f140b41d4aad461fcb7bd9017149c3bca1a0d19a9edf5e2ed9fc25d
4
+ data.tar.gz: bddac2fcd0e1ef426f228e97bb537a34704d102d8f480cee872be74e505aefcc
5
5
  SHA512:
6
- metadata.gz: a7917365ade7f63164081e865efbcbac0b3f71e26f77abd0a2f32e0c15f2ca4465aabb55db07c64ab20c05ed089525e31319e89ef946e91394a51d73f8dc98da
7
- data.tar.gz: 631f9ff0ef37d8fb1250e3713f8322e262d2e5366e1e46fa48da522b296cd3cf8445723fdc42f33ef039ad5ccdc2d32bebfaa1dd53749957b663d7f1206e06fd
6
+ metadata.gz: 22f5427eaa445d7189140bb98bf1206f2e5b0dd0b1df8d1f1ec12af01a2472dea1006422b69e50d28bf7c87dd9f2002ee29ba7a8dcdbccceea6cb3c65ff60080
7
+ data.tar.gz: 8c0c3f28b548609c667f7e4b1d610a50a9a44a114b05a66dfaef9901d6f252e564eb6458ae4808c5154c759e685dd44b368b984a076ad1b9b7a53a75a555ae89
@@ -1,3 +1,20 @@
1
+ ### 0.3.1 (2019-06-09)
2
+
3
+ [Full Changelog](https://github.com/emartech/ezlog/compare/v0.2.2...v0.3.1)
4
+
5
+ * Features & enhancements
6
+ * Unified access log for Rails
7
+ * 1 message per request
8
+ * Includes request ID, parameters, response code
9
+ * Non-verbose logging of uncaught exceptions in Rails apps
10
+ * 1 message per error
11
+ * Use ERROR level instead of FATAL
12
+ * [Rack::Timeout](https://github.com/heroku/rack-timeout) logging is now completely turned off, because Timeout errors
13
+ are handled by the application's error logger and we don't want duplicated log messages
14
+
15
+ * Bug fixes
16
+ * Fix bug where the application log level wasn't set to INFO by default but remained on DEBUG
17
+
1
18
  ### 0.2.2 (2019-05-19)
2
19
 
3
20
  [Full Changelog](https://github.com/emartech/ezlog/compare/v0.2.1...v0.2.2)
data/README.md CHANGED
@@ -3,31 +3,41 @@
3
3
  [![Gem Version](https://badge.fury.io/rb/ezlog.svg)](https://badge.fury.io/rb/ezlog)
4
4
  [![Build Status](https://travis-ci.com/emartech/ezlog.svg?branch=master)](https://travis-ci.com/emartech/ezlog)
5
5
 
6
- Ezlog is intended to be a zero-configuration logging setup for pure Ruby or Rails projects using
7
- [Sidekiq](https://github.com/mperham/sidekiq), [Rack::Timeout](https://github.com/heroku/rack-timeout),
8
- [Sequel](https://sequel.jeremyevans.net/), etc. It uses Tim Pease's wonderful [Logging](https://github.com/TwP/logging)
9
- gem for an all-purpose logging solution.
6
+ Ezlog is intended to be a zero-configuration structured logging setup for pure Ruby or [Ruby on Rails](https://rubyonrails.org/)
7
+ projects using any (or all) of the following libraries or frameworks:
8
+
9
+ * [Ruby on Rails](https://rubyonrails.org/)
10
+ * [Sidekiq](https://github.com/mperham/sidekiq)
11
+ * [Sequel](https://sequel.jeremyevans.net/)
12
+ * [Rack::Timeout](https://github.com/heroku/rack-timeout)
13
+
14
+ It uses Tim Pease's wonderful [Logging](https://github.com/TwP/logging) gem for an all-purpose structured logging solution.
10
15
 
11
16
  Ezlog's purpose is threefold:
12
- 1. Make sure that our applications are logging in a sensible manner; emitting no unnecessary "noise" but containing all
13
- relevant and necessary information (like timing).
17
+ 1. Make sure that our applications are logging in a concise and sensible manner; emitting no unnecessary "noise" but
18
+ containing all relevant and necessary information (like timing).
14
19
  2. Make sure that all log messages are written to STDOUT in a machine-processable format (JSON) across all of our projects.
15
- 3. Achieving the above goal should require no configuration in the projects where the library is used.
20
+ 3. Achieving the above goals should require no configuration in the projects where the library is used.
16
21
 
17
22
  ## Installation
18
23
 
24
+ #### Rails
25
+
19
26
  Add this line to your application's Gemfile:
20
27
 
21
28
  ```ruby
22
29
  gem 'ezlog'
23
30
  ```
24
31
 
32
+ That's it. Everything else is automatically configured.
33
+
25
34
  ## What it does
26
35
 
27
36
  * Initializes the [Logging](https://github.com/TwP/logging) library
28
37
  * Configures Rails logging
29
38
  * Configures Sidekiq logging
30
39
  * Configures Rack::Timeout logging
40
+ * Provides testing support for [RSpec](https://rspec.info/)
31
41
 
32
42
  #### Initializes the Logging library
33
43
 
@@ -64,8 +74,39 @@ logger.error ex
64
74
 
65
75
  Ezlog configures the `Rails.logger` to be an instance of a [Logging](https://github.com/TwP/logging) logger by the name
66
76
  of `Application`, behaving as described above. The logger uses the log level set in `application.rb` (if present) or
67
- uses INFO as a default log level. It also adds the environment (`Rails.env`) to the logger's initial context, meaning
68
- it will automatically be appended to all log messages emitted by the application.
77
+ uses INFO as a default log level.
78
+
79
+ In addition to this, Ezlog also does the following:
80
+ * It adds the environment (`Rails.env`) to the logger's initial context, so it will automatically be appended to all log messages
81
+ emitted by the application.
82
+ * It disables Rails's default (verbose) logging of uncaught errors and injects its own error logger into the application, which
83
+ * logs 1 line per error, including the error's name and context (stack trace, etc.),
84
+ * logs every error at ERROR level instead of the default FATAL.
85
+ * It disables Rails's default (verbose) request logging, which logs several lines per event during the processing of an action
86
+ and replaces the default Rack access log with its own access log middleware. The end result is an access log, which
87
+ * contains all relevant information (request ID, method, path, params, client IP, duration and response status code), and
88
+ * has 1 log line per request, logged at the end of the request.
89
+
90
+ Thanks to Mathias Meyer for writing [Lograge](https://github.com/roidrage/lograge), which inspired the solution.
91
+ If Ezlog's not your cup of tea but you're looking for a way to tame Rails's logging then be sure to check out
92
+ [Lograge](https://github.com/roidrage/lograge).
93
+
94
+ ```
95
+ GET /welcome?subsession_id=34ea8596f9764f475f81158667bc2654
96
+
97
+ With default Rails logging:
98
+
99
+ Started GET "/welcome?subsession_id=34ea8596f9764f475f81158667bc2654" for 127.0.0.1 at 2019-06-08 08:49:31 +0200
100
+ Processing by PagesController#welcome as HTML
101
+ Parameters: {"subsession_id"=>"34ea8596f9764f475f81158667bc2654"}
102
+ Rendering pages/welcome.html.haml within layouts/application
103
+ Rendered pages/welcome.html.haml within layouts/application (5.5ms)
104
+ Completed 200 OK in 31ms (Views: 27.3ms | ActiveRecord: 0.0ms)
105
+
106
+ With Ezlog:
107
+
108
+ {"logger":"AccessLog","timestamp":"2019-06-08T08:49:31+02:00","level":"INFO","hostname":"MacbookPro.local","pid":75463,"environment":"development","request_id":"9a43631b-284c-4677-9d08-9c1cc5c7d3a7","duration_sec":0.031,"message":"GET /welcome?subsession_id=34ea8596f9764f475f81158667bc2654 - 200 (OK)","remote_ip":"127.0.0.1","method":"GET","path":"/welcome?subsession_id=34ea8596f9764f475f81158667bc2654","params":{"subsession_id":"34ea8596f9764f475f81158667bc2654","controller":"pages","action":"welcome"},"response_status_code":200}
109
+ ```
69
110
 
70
111
  #### Configures Sidekiq logging
71
112
 
@@ -97,8 +138,38 @@ TestWorker.perform_async 42
97
138
  #### Configures Rack::Timeout logging
98
139
 
99
140
  [Rack::Timeout](https://github.com/heroku/rack-timeout) is a very useful tool for people running services on Heroku
100
- but it is way too verbose by default. What Ezlog does is simply reconfigure its logging to use Ezlog's logging
101
- mechanism and to only output messages at or above WARN level.
141
+ but it is way too verbose by default and all of its important messages (i.e. Timeout errors) are logged by the application
142
+ as well. For this reason, Ezlog turns off [Rack::Timeout](https://github.com/heroku/rack-timeout) logging completely.
143
+
144
+ #### Provides testing support for RSpec
145
+
146
+ Ezlog comes with built-in support for testing your logging activity using [RSpec](https://rspec.info/).
147
+ To enable spec support for Ezlog, put this line in your `spec_helper.rb` or `rails_helper.rb`:
148
+ ```ruby
149
+ require "ezlog/rspec"
150
+ ```
151
+
152
+ What you get:
153
+ * Helpers
154
+ * `log_output` provides access to the complete log output in your specs
155
+ * `log_output_is_expected` shorthand for writing expectations for the log output
156
+ * Matchers
157
+ * `include_log_message` matcher for expecting a certain message in the log output
158
+ * `log` matcher for expecting an operation to log a certain message
159
+
160
+ ```ruby
161
+ # Check that the log contains a certain message
162
+ expect(log_output).to include_log_message message: 'Test message'
163
+ log_output_is_expected.to include_log_message message: 'Test message'
164
+
165
+ # Check that the message is not present in the logs before the operation but is present after it
166
+ expect { operation }.to log message: 'Test message',
167
+ user_id: 123456
168
+
169
+ # Expect a certain log level
170
+ log_output_is_expected.to include_log_message(message: 'Test message').at_level(:info)
171
+ expect { operation }.to log(message: 'Test message').at_level(:info)
172
+ ```
102
173
 
103
174
  ## Disclaimer
104
175
 
@@ -23,10 +23,10 @@ Gem::Specification.new do |spec|
23
23
  spec.require_paths = ["lib"]
24
24
 
25
25
  spec.add_dependency "logging", "~> 2.0"
26
- spec.add_dependency "multi_json"
27
26
 
28
27
  spec.add_development_dependency "bundler", "~> 2.0"
29
28
  spec.add_development_dependency "rake", "~> 10.0"
30
29
  spec.add_development_dependency "rspec", "~> 3.0"
31
30
  spec.add_development_dependency "sidekiq", "~> 5.0"
31
+ spec.add_development_dependency "actionpack", "~> 5.0"
32
32
  end
@@ -6,9 +6,10 @@ require 'ezlog/railtie' if defined? Rails
6
6
  module Ezlog
7
7
  autoload :LogContextHelper, 'ezlog/log_context_helper'
8
8
  autoload :LoggingLayout, 'ezlog/logging_layout'
9
+ autoload :Rails, 'ezlog/rails'
9
10
  autoload :Sidekiq, 'ezlog/sidekiq'
10
11
 
11
12
  def self.logger(name)
12
- Logging::Logger[name]
13
+ ::Logging::Logger[name]
13
14
  end
14
15
  end
@@ -1,5 +1,5 @@
1
1
  require 'time'
2
- require 'multi_json'
2
+ require 'json'
3
3
 
4
4
  module Ezlog
5
5
  class LoggingLayout < ::Logging::Layout
@@ -12,7 +12,7 @@ module Ezlog
12
12
  add_initial_context_to log_entry
13
13
  add_logging_context_to log_entry
14
14
  add_event_information_to log_entry, event
15
- ::MultiJson.dump(log_entry) + "\n"
15
+ ::JSON.dump(log_entry) + "\n"
16
16
  end
17
17
 
18
18
  private
@@ -0,0 +1,12 @@
1
+ require "action_controller"
2
+ require "action_controller/log_subscriber"
3
+
4
+ module Ezlog
5
+ module Rails
6
+ autoload :AccessLog, 'ezlog/rails/access_log'
7
+ autoload :DebugExceptions, 'ezlog/rails/debug_exceptions'
8
+ autoload :LogExceptions, 'ezlog/rails/log_exceptions'
9
+ autoload :RequestLogContext, 'ezlog/rails/request_log_context'
10
+ autoload :LogSubscriber, 'ezlog/rails/log_subscriber'
11
+ end
12
+ end
@@ -0,0 +1,37 @@
1
+ module Ezlog
2
+ module Rails
3
+ class AccessLog
4
+ include LogContextHelper
5
+
6
+ def initialize(app, logger)
7
+ @app = app
8
+ @logger = logger
9
+ end
10
+
11
+ def call(env)
12
+ status, headers, body_lines = benchmark { @app.call(env) }
13
+ log_request ActionDispatch::Request.new(env), status
14
+ [status, headers, body_lines]
15
+ end
16
+
17
+ private
18
+
19
+ def benchmark
20
+ start_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
21
+ yield
22
+ ensure
23
+ end_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
24
+ add_to_log_context duration_sec: (end_time - start_time).round(3)
25
+ end
26
+
27
+ def log_request(request, status)
28
+ @logger.info message: '%s %s - %i (%s)' % [request.method, request.filtered_path, status, Rack::Utils::HTTP_STATUS_CODES[status]],
29
+ remote_ip: request.remote_ip,
30
+ method: request.method,
31
+ path: request.filtered_path,
32
+ params: request.filtered_parameters,
33
+ response_status_code: status
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,8 @@
1
+ module Ezlog
2
+ module Rails
3
+ class DebugExceptions < ::ActionDispatch::DebugExceptions
4
+ def log_error(_request, _wrapper)
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,17 @@
1
+ module Ezlog
2
+ module Rails
3
+ class LogExceptions
4
+ def initialize(app, logger)
5
+ @app = app
6
+ @logger = logger
7
+ end
8
+
9
+ def call(env)
10
+ @app.call(env)
11
+ rescue Exception => exception
12
+ @logger.error exception
13
+ raise
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ module Ezlog
2
+ module Rails
3
+ class LogSubscriber
4
+ def self.detach(subscriber_class)
5
+ subscriber = ::ActiveSupport::LogSubscriber.log_subscribers.find { |subscriber| subscriber.is_a? subscriber_class }
6
+ return unless subscriber
7
+
8
+ subscriber.patterns.each do |pattern|
9
+ ::ActiveSupport::Notifications.notifier.listeners_for(pattern).each do |listener|
10
+ ::ActiveSupport::Notifications.unsubscribe listener if listener.instance_variable_get('@delegate').is_a? subscriber_class
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ module Ezlog
2
+ module Rails
3
+ class RequestLogContext
4
+ include LogContextHelper
5
+
6
+ def initialize(app)
7
+ @app = app
8
+ end
9
+
10
+ def call(env)
11
+ within_log_context request_id: env['action_dispatch.request_id'] do
12
+ @app.call(env)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -2,8 +2,8 @@ module Ezlog
2
2
  class Railtie < Rails::Railtie
3
3
  initializer 'ezlog.configure_logging' do |app|
4
4
  ::Logging.logger.root.appenders = ::Logging.appenders.stdout 'stdout',
5
- layout: Ezlog::LoggingLayout.new(environment: Rails.env),
6
- level: app.config.log_level || :info
5
+ layout: Ezlog::LoggingLayout.new(environment: ::Rails.env),
6
+ level: app.config.log_level
7
7
  end
8
8
 
9
9
  initializer 'ezlog.configure_sidekiq_logging' do
@@ -11,11 +11,24 @@ module Ezlog
11
11
  end
12
12
 
13
13
  initializer 'ezlog.configure_rack_timeout_logging' do
14
- initialize_rack_timeout_logging if defined? ::Rack::Timeout
14
+ disable_rack_timeout_logging if defined? ::Rack::Timeout
15
+ end
16
+
17
+ initializer 'ezlog.configure_middlewares' do |app|
18
+ app.config.middleware.insert_after ::ActionDispatch::RequestId, Ezlog::Rails::RequestLogContext
19
+ app.config.middleware.swap ::Rails::Rack::Logger, Ezlog::Rails::AccessLog, Ezlog.logger('AccessLog')
20
+ app.config.middleware.swap ::ActionDispatch::DebugExceptions, Ezlog::Rails::DebugExceptions
21
+ app.config.middleware.insert_after Ezlog::Rails::DebugExceptions, Ezlog::Rails::LogExceptions, Ezlog.logger('Application')
22
+ end
23
+
24
+ config.after_initialize do
25
+ Ezlog::Rails::LogSubscriber.detach ::ActionController::LogSubscriber
26
+ Ezlog::Rails::LogSubscriber.detach ::ActionView::LogSubscriber
15
27
  end
16
28
 
17
29
  config.before_configuration do |app|
18
- app.config.logger = ::Logging.logger['Application']
30
+ app.config.logger = Ezlog.logger('Application')
31
+ app.config.log_level = :info
19
32
  end
20
33
 
21
34
  private
@@ -30,9 +43,8 @@ module Ezlog
30
43
  end
31
44
  end
32
45
 
33
- def initialize_rack_timeout_logging
34
- ::Rack::Timeout::Logger.logger = ::Logging.logger['rack-timeout']
35
- ::Rack::Timeout::Logger.logger.level = :warn
46
+ def disable_rack_timeout_logging
47
+ ::Rack::Timeout::Logger.logger = ::Logger.new(nil)
36
48
  end
37
49
  end
38
50
  end
@@ -5,7 +5,7 @@ module Ezlog
5
5
  class JobLogger
6
6
  include LogContextHelper
7
7
 
8
- def call(job_hash, queue)
8
+ def call(job_hash, _queue)
9
9
  within_log_context(JobContext.from_job_hash(job_hash)) do
10
10
  logger.info "#{job_hash['class']} started"
11
11
  benchmark { yield }
@@ -1,3 +1,3 @@
1
1
  module Ezlog
2
- VERSION = "0.2.2"
2
+ VERSION = '0.3.1'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ezlog
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zoltan Ormandi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-05-19 00:00:00.000000000 Z
11
+ date: 2019-06-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: logging
@@ -24,20 +24,6 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.0'
27
- - !ruby/object:Gem::Dependency
28
- name: multi_json
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: bundler
43
29
  requirement: !ruby/object:Gem::Requirement
@@ -94,6 +80,20 @@ dependencies:
94
80
  - - "~>"
95
81
  - !ruby/object:Gem::Version
96
82
  version: '5.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: actionpack
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '5.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '5.0'
97
97
  description:
98
98
  email:
99
99
  - zoltan.ormandi@emarsys.com
@@ -115,6 +115,12 @@ files:
115
115
  - lib/ezlog.rb
116
116
  - lib/ezlog/log_context_helper.rb
117
117
  - lib/ezlog/logging_layout.rb
118
+ - lib/ezlog/rails.rb
119
+ - lib/ezlog/rails/access_log.rb
120
+ - lib/ezlog/rails/debug_exceptions.rb
121
+ - lib/ezlog/rails/log_exceptions.rb
122
+ - lib/ezlog/rails/log_subscriber.rb
123
+ - lib/ezlog/rails/request_log_context.rb
118
124
  - lib/ezlog/railtie.rb
119
125
  - lib/ezlog/rspec.rb
120
126
  - lib/ezlog/rspec/helpers.rb