superlogger 1.0.1 → 1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '082cbc716a6f0432e73617a883fd03584bd8f3de5a1f3f32afd6a48882d05f76'
4
- data.tar.gz: c85c50a9e182a78c3c281a427b5fd351c4c01b9181dbeffe81a6831bc51f7b39
3
+ metadata.gz: 31133b660d9663478b8feabfa3bfc2f38431485648ef434230ae56e778b9a65c
4
+ data.tar.gz: 7c2bf630ad96997d64a6ac7224a3635fe3dd6246b79ab289305498bdf68a5ac8
5
5
  SHA512:
6
- metadata.gz: 7f5eb670792f8cb1abf4a4b3830b7b0e415b9f0849d9339bf8ddce091dc71dd7f2cc455813f7c6ca64fafba40ab8de59f32c6fd1a6c5cec74d24968caecc3624
7
- data.tar.gz: bc3c65ddb32e7e5eec96de1028d86a12557fda30643797eb71e863db4dac24fcf82dd5434a8c72639a9eb78b1168e60fc4c2dc3fbbd71fffb6a0dcbf08cc3f13
6
+ metadata.gz: 29ca48eafa2e7e648cb852e6e2142aa4092f95b5e1b86a9cd0eb432ac180616b9af0c2746c6cfa161ec997038fe7e38b3b5552bb8bf01b0a55ae7003211bad0b
7
+ data.tar.gz: b554d0898a26c4b32936754cec07cc557faafa74c719e918c789d20b7f11110e98915ff62476d2de199d2bc0a0a445011c7531f02642b5acbaf4e1caa5382142
data/README.md CHANGED
@@ -72,3 +72,34 @@ Rails.logger.info "Meatball"
72
72
  - `request_id` = 32 characters
73
73
  - `msg` = If values given is not a hash, it is treated as `{"msg":<value>"}`
74
74
  - All duration related fields are in milliseconds
75
+
76
+ To log additional fields that are available on the `ActionDispatch::Request` object, set in `config/application.rb`:
77
+ ```ruby
78
+ Superlogger.include_log_fields = lambda do |request|
79
+ # Return a hash of extra fields to log.
80
+ {
81
+ user_id: request.session[:current_user].id,
82
+ ip: request.ip
83
+ }
84
+ end
85
+ ```
86
+
87
+ ## Testing ##
88
+
89
+ To run the tests for Superlogger:
90
+
91
+ ```sh
92
+ rake test
93
+ ```
94
+
95
+ ## Publishing a New Release ##
96
+
97
+ 1. Bump the version in `lib/superlogger/version.rb`.
98
+ 1. Run `bundle install` to update the version of Superlogger in `Gemfile.lock`.
99
+ 1. Open a pull request with the changes from the above steps.
100
+ 1. After the pull request is merged, publish a new release on GitHub with the same version tag.
101
+ 1. Clear all temporary files to prevent them from being bundled into the gem.
102
+ This is most easily achieved by building from a new clone of the repository.
103
+ 1. Run `gem build superlogger.gemspec` to build the gem.
104
+ 1. Run `gem push superlogger-x.x.x.gem` to publish the gem to RubyGems.
105
+ You will be prompted for credentials if this is your first time publishing the gem on your machine.
@@ -1,7 +1,10 @@
1
1
  module Superlogger
2
2
  class SuperloggerMiddleware
3
- def initialize(app)
3
+ def initialize(app, options = {})
4
4
  @app = app
5
+ @options = {
6
+ include_log_fields: ->(_request) { {} }
7
+ }.merge(options)
5
8
  end
6
9
 
7
10
  def call(env)
@@ -15,7 +18,8 @@ module Superlogger
15
18
  end
16
19
 
17
20
  def process_request(request)
18
- setup_logging(request)
21
+ setup_request_id_for_logging(request)
22
+ setup_session_id_for_logging(request)
19
23
 
20
24
  # Start of request
21
25
  Rails.logger.info method: request.method, path: request.fullpath
@@ -27,20 +31,24 @@ module Superlogger
27
31
 
28
32
  # End of request
29
33
  duration = ((t2 - t1) * 1000).to_f.round(2)
30
- Rails.logger.info method: request.method, path: request.fullpath, response_time: duration, status: status
34
+
35
+ # After the request has been processed, the session ID can change from what it was before the request
36
+ # was processed. As such, we need to setup the session ID again.
37
+ setup_session_id_for_logging(request)
38
+
39
+ Rails.logger.info method: request.method, path: request.fullpath, response_time: duration, status: status, **@options[:include_log_fields].call(request)
31
40
 
32
41
  [status, _headers, _response]
33
42
  end
34
43
 
35
- def setup_logging(request)
36
- if request.env['rack.session']
37
- # Store session id before any actual logging is done
38
- if request.env['rack.session'].id
39
- Superlogger.session_id = request.env['rack.session'].id.to_s
40
- end
41
- end
42
-
44
+ def setup_request_id_for_logging(request)
43
45
  Superlogger.request_id = request.uuid.try(:gsub, '-', '')
44
46
  end
47
+
48
+ def setup_session_id_for_logging(request)
49
+ return unless request.env['rack.session']&.id
50
+
51
+ Superlogger.session_id = request.env['rack.session'].id.to_s
52
+ end
45
53
  end
46
54
  end
@@ -1,3 +1,3 @@
1
1
  module Superlogger
2
- VERSION = '1.0.1'
2
+ VERSION = '1.1.0'
3
3
  end
data/lib/superlogger.rb CHANGED
@@ -3,6 +3,7 @@ require 'superlogger/logger'
3
3
 
4
4
  module Superlogger
5
5
  @@enabled = false
6
+ @@include_log_fields = nil
6
7
 
7
8
  module_function
8
9
 
@@ -18,7 +19,9 @@ module Superlogger
18
19
  require 'superlogger/superlogger_middleware'
19
20
 
20
21
  # important to insert after session middleware so we can get the session id
21
- app.middleware.use Superlogger::SuperloggerMiddleware
22
+ app.middleware.use Superlogger::SuperloggerMiddleware, {
23
+ include_log_fields: @@include_log_fields
24
+ }.compact
22
25
  end
23
26
 
24
27
  def detach_existing_log_subscribers
@@ -74,6 +77,14 @@ module Superlogger
74
77
  def enabled
75
78
  @@enabled
76
79
  end
80
+
81
+ def include_log_fields=(include_log_fields)
82
+ @@include_log_fields=include_log_fields
83
+ end
84
+
85
+ def include_log_fields
86
+ @@include_log_fields
87
+ end
77
88
  end
78
89
 
79
90
  require 'superlogger/railtie' if defined?(Rails)
@@ -2,4 +2,10 @@ class HomeController < ApplicationController
2
2
  def index
3
3
  Something.where(paper: '123', stone: '456').first
4
4
  end
5
+
6
+ def index_with_session
7
+ # Force load session by writing to it.
8
+ session[:current_time] = Time.now
9
+ redirect_to action: :index
10
+ end
5
11
  end
@@ -23,5 +23,13 @@ module Dummy
23
23
 
24
24
  Superlogger.enabled = true
25
25
  config.logger = Superlogger::Logger.new(STDOUT)
26
+
27
+ Superlogger.include_log_fields = lambda do |request|
28
+ session = request.session
29
+ {
30
+ current_time: session[:current_time],
31
+ hello: 'world'
32
+ }
33
+ end
26
34
  end
27
35
  end
@@ -1,3 +1,4 @@
1
1
  Rails.application.routes.draw do
2
2
  get 'home/index'
3
+ get 'home/index_with_session'
3
4
  end
@@ -33,10 +33,30 @@ class SuperloggerTest < ActiveSupport::TestCase
33
33
  assert_not_nil Superlogger::VERSION
34
34
  end
35
35
 
36
- test 'log format' do
36
+ test 'log format when session is not loaded' do
37
37
  request('home/index')
38
38
 
39
- fields = output.first
39
+ fields = output[4]
40
+ assert fields.key?("level")
41
+ assert fields.key?("ts")
42
+ assert fields.key?("caller")
43
+ assert_equal fields.key?("session_id"), false
44
+ assert fields.key?("request_id")
45
+ end
46
+
47
+ test 'log format when session is loaded' do
48
+ request('home/index_with_session')
49
+
50
+ # Session is not loaded before the request is processed.
51
+ fields = output[0]
52
+ assert fields.key?("level")
53
+ assert fields.key?("ts")
54
+ assert fields.key?("caller")
55
+ assert_equal fields.key?("session_id"), false
56
+ assert fields.key?("request_id")
57
+
58
+ # Session is loaded after the request is processed.
59
+ fields = output[4]
40
60
  assert fields.key?("level")
41
61
  assert fields.key?("ts")
42
62
  assert fields.key?("caller")
@@ -44,14 +64,49 @@ class SuperloggerTest < ActiveSupport::TestCase
44
64
  assert fields.key?("request_id")
45
65
  end
46
66
 
67
+ # The additional fields to log are defined in `/test/dummy/config/application.rb`.
68
+ # Unfortunately, because `Superlogger::SuperloggerMiddleware` is initialised
69
+ # together with the Rails application, and because we cannot programmatically
70
+ # reinitialise the Rails application or run multiple instances of it, we are
71
+ # only able to test a single Superlogger configuration. Once the Rails
72
+ # application is initialised, the middleware stack cannot be changed.
73
+ #
74
+ # This effectively means that we are unable to change the Superlogger settings
75
+ # in the Rails application configuration on a per-test basis. For the sake of
76
+ # testing, we choose the Superlogger settings that let us test the presence of
77
+ # behaviours and set the additional fields to log.
78
+ test 'log format when logging additional fields' do
79
+ request('home/index_with_session')
80
+
81
+ # Additional fields are not logged before the request is processed.
82
+ fields = output[0]
83
+ assert fields.key?("level")
84
+ assert fields.key?("ts")
85
+ assert fields.key?("caller")
86
+ assert_equal fields.key?("session_id"), false
87
+ assert fields.key?("request_id")
88
+ assert_equal fields.key?("current_time"), false
89
+ assert_equal fields.key?("hello"), false
90
+
91
+ # Additional fields are logged after the request is processed.
92
+ fields = output[4]
93
+ assert fields.key?("level")
94
+ assert fields.key?("ts")
95
+ assert fields.key?("caller")
96
+ assert fields.key?("session_id")
97
+ assert fields.key?("request_id")
98
+ assert fields.key?("current_time")
99
+ assert fields.key?("hello")
100
+ end
101
+
47
102
  test 'timestamp' do
48
103
  request('home/index')
49
104
  assert_equal Time.at(output[0]["ts"]).to_date, Date.today
50
105
  end
51
106
 
52
107
  test 'with session_id' do
53
- env = request('home/index')
54
- assert_match env['rack.session'].id.to_s[0..11], output[0]["session_id"]
108
+ env = request('home/index_with_session')
109
+ assert_match env['rack.session'].id.to_s[0..11], output[4]["session_id"]
55
110
  end
56
111
 
57
112
  test 'without session_id' do
@@ -108,7 +163,7 @@ class SuperloggerTest < ActiveSupport::TestCase
108
163
  test 'action_controller_log_subscriber.process_action' do
109
164
  request('home/index')
110
165
 
111
- fields = output[5]
166
+ fields = output[7]
112
167
  assert_operator fields["view_duration"], :>, 0
113
168
  assert_operator fields["db_duration"], :>, 0
114
169
  end
@@ -116,11 +171,11 @@ class SuperloggerTest < ActiveSupport::TestCase
116
171
  test 'action_view_log_subscriber.render_template.render_partial.render_collection' do
117
172
  request('home/index')
118
173
 
119
- fields = output[3]
174
+ fields = output[4]
120
175
  assert_match 'partial.html.erb', fields["view"]
121
176
  assert fields.key?("duration")
122
177
 
123
- fields = output[4]
178
+ fields = output[5]
124
179
  assert_match 'index.html.erb', fields["view"]
125
180
  assert fields.key?("duration")
126
181
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: superlogger
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Soh Yu Ming
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-04-04 00:00:00.000000000 Z
11
+ date: 2024-05-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -117,7 +117,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
117
117
  - !ruby/object:Gem::Version
118
118
  version: '0'
119
119
  requirements: []
120
- rubygems_version: 3.2.33
120
+ rubygems_version: 3.5.9
121
121
  signing_key:
122
122
  specification_version: 4
123
123
  summary: Machine-readable logging for Rails