lumberjack_rails 1.0.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 +7 -0
- data/.github/dependabot.yml +12 -0
- data/.github/workflows/continuous_integration.yml +70 -0
- data/.standard.yml +9 -0
- data/.yardopts +1 -0
- data/CHANGE_LOG.md +11 -0
- data/MIT_LICENSE.txt +20 -0
- data/README.md +329 -0
- data/VERSION +1 -0
- data/lib/lumberjack/rails/action_cable_extension.rb +19 -0
- data/lib/lumberjack/rails/action_controller_extension.rb +19 -0
- data/lib/lumberjack/rails/action_controller_log_subscriber_extension.rb +103 -0
- data/lib/lumberjack/rails/action_mailbox_extension.rb +19 -0
- data/lib/lumberjack/rails/action_mailer_extension.rb +19 -0
- data/lib/lumberjack/rails/active_job_extension.rb +19 -0
- data/lib/lumberjack/rails/apply_patches.rb +86 -0
- data/lib/lumberjack/rails/broadcast_logger_extension.rb +302 -0
- data/lib/lumberjack/rails/context_middleware.rb +23 -0
- data/lib/lumberjack/rails/log_at_level.rb +19 -0
- data/lib/lumberjack/rails/log_subscriber_extension.rb +97 -0
- data/lib/lumberjack/rails/rack_logger_extension.rb +13 -0
- data/lib/lumberjack/rails/railtie.rb +174 -0
- data/lib/lumberjack/rails/request_attributes_middleware.rb +42 -0
- data/lib/lumberjack/rails/tagged_forked_logger.rb +22 -0
- data/lib/lumberjack/rails/tagged_logging_formatter.rb +28 -0
- data/lib/lumberjack/rails.rb +106 -0
- data/lib/lumberjack_rails.rb +3 -0
- data/lumberjack_rails.gemspec +40 -0
- metadata +97 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 9e2d5624bd1b1c1c67487fde54b2ebd11def32b5e715e4d8ff7c7e7ece1d3253
|
|
4
|
+
data.tar.gz: d3bf91601bf2380602e887d71c863cf631968b910655db9020aee66377882fc7
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: '08425991455694b32dbccf992ad8448b003a94a09b5a2971f27aa2d056c186d70fa5793715a28b83d43b22696ae0401833c84af8ec83a098832a3950811014db'
|
|
7
|
+
data.tar.gz: 6c17517e84a4e0520a50da6199632403f1e4b4899c203a1688d4f1ae5d92361030d535375f6add1f4ab663fe37c5708b16343b54d61d8f36660053b5a52e1ace
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Dependabot update strategy
|
|
2
|
+
version: 2
|
|
3
|
+
updates:
|
|
4
|
+
- package-ecosystem: bundler
|
|
5
|
+
directory: "/"
|
|
6
|
+
schedule:
|
|
7
|
+
interval: weekly
|
|
8
|
+
allow:
|
|
9
|
+
# Automatically keep all runtime dependencies updated
|
|
10
|
+
- dependency-name: "*"
|
|
11
|
+
dependency-type: "production"
|
|
12
|
+
versioning-strategy: lockfile-only
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
name: Continuous Integration
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
- actions-*
|
|
8
|
+
pull_request:
|
|
9
|
+
branches-ignore:
|
|
10
|
+
- actions-*
|
|
11
|
+
workflow_dispatch:
|
|
12
|
+
|
|
13
|
+
env:
|
|
14
|
+
BUNDLE_CLEAN: "true"
|
|
15
|
+
BUNDLE_PATH: vendor/bundle
|
|
16
|
+
BUNDLE_JOBS: 3
|
|
17
|
+
BUNDLE_RETRY: 3
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
build:
|
|
21
|
+
name: build ruby-${{ matrix.ruby }} ${{ matrix.appraisal }}
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
strategy:
|
|
24
|
+
fail-fast: false
|
|
25
|
+
matrix:
|
|
26
|
+
include:
|
|
27
|
+
- ruby: "ruby"
|
|
28
|
+
standardrb: true
|
|
29
|
+
yard: true
|
|
30
|
+
- ruby: "3.4"
|
|
31
|
+
appraisal: rails_8
|
|
32
|
+
- ruby: "3.3"
|
|
33
|
+
appraisal: rails_8.0
|
|
34
|
+
- ruby: "3.1"
|
|
35
|
+
appraisal: rails_7
|
|
36
|
+
- ruby: "3.0"
|
|
37
|
+
appraisal: rails_7.1
|
|
38
|
+
- ruby: "ruby"
|
|
39
|
+
appraisal: no_rails
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/checkout@v4
|
|
42
|
+
- name: Set up Ruby ${{ matrix.ruby }}
|
|
43
|
+
uses: ruby/setup-ruby@v1
|
|
44
|
+
with:
|
|
45
|
+
ruby-version: "${{ matrix.ruby }}"
|
|
46
|
+
- name: Install packages
|
|
47
|
+
run: |
|
|
48
|
+
sudo apt-get update
|
|
49
|
+
sudo apt-get install libsqlite3-dev
|
|
50
|
+
- name: Setup bundler
|
|
51
|
+
if: matrix.bundler != ''
|
|
52
|
+
run: |
|
|
53
|
+
gem uninstall bundler --all
|
|
54
|
+
gem install bundler --no-document --version ${{ matrix.bundler }}
|
|
55
|
+
- name: Set Appraisal bundle
|
|
56
|
+
if: matrix.appraisal != ''
|
|
57
|
+
run: |
|
|
58
|
+
echo "using gemfile gemfiles/${{ matrix.appraisal }}.gemfile"
|
|
59
|
+
bundle config set gemfile "gemfiles/${{ matrix.appraisal }}.gemfile"
|
|
60
|
+
- name: Install gems
|
|
61
|
+
run: |
|
|
62
|
+
bundle update
|
|
63
|
+
- name: Run Tests
|
|
64
|
+
run: bundle exec rake
|
|
65
|
+
- name: standardrb
|
|
66
|
+
if: matrix.standardrb == true
|
|
67
|
+
run: bundle exec standardrb
|
|
68
|
+
- name: yard
|
|
69
|
+
if: matrix.yard == true
|
|
70
|
+
run: bundle exec yard --fail-on-warning
|
data/.standard.yml
ADDED
data/.yardopts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
--exclude lib/lumberjack/rails/apply_patches.rb
|
data/CHANGE_LOG.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
All notable changes to this project will be documented in this file.
|
|
3
|
+
|
|
4
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
5
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## 1.0.0
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Initial release
|
data/MIT_LICENSE.txt
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2025 Brian Durand
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
# Lumberjack Rails
|
|
2
|
+
|
|
3
|
+
[](https://github.com/bdurand/lumberjack_rails/actions/workflows/continuous_integration.yml)
|
|
4
|
+
[](https://github.com/testdouble/standard)
|
|
5
|
+
[](https://badge.fury.io/rb/lumberjack_rails)
|
|
6
|
+
|
|
7
|
+
The `lumberjack_rails` gem provides support for using the [lumberjack](https://github.com/bdurand/lumberjack) logging library in Rails applications.
|
|
8
|
+
|
|
9
|
+
Rails has some of its own extensions to the Ruby standard library logger, and this gem bridges the gap between the two logging systems to add Lumberjack features to the `Rails.logger` and Rails features to Lumberjack loggers.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
With this gem installed, your main application logger will be a Lumberjack logger. The logger that gets initialized is defined by your application's configuration.
|
|
14
|
+
|
|
15
|
+
### Configuration Options
|
|
16
|
+
|
|
17
|
+
#### `config.lumberjack.enabled`
|
|
18
|
+
|
|
19
|
+
Enables or disables the Lumberjack logger. If this is set to `false`, then Lumberjack will not be used.
|
|
20
|
+
|
|
21
|
+
#### `config.lumberjack.level`
|
|
22
|
+
|
|
23
|
+
Sets the log level for the Lumberjack logger. This can be set to any valid log level supported by Lumberjack. This will defer to the standard Rails `config.log_level` setting or default to `:debug` if neither is set.
|
|
24
|
+
|
|
25
|
+
#### `config.lumberjack.device`
|
|
26
|
+
|
|
27
|
+
The device to write logs to (file path, IO object, etc.). Defaults to the Rails log file.
|
|
28
|
+
|
|
29
|
+
#### `config.lumberjack.attributes`
|
|
30
|
+
|
|
31
|
+
Hash of attributes to apply to all log messages. These attributes will be included in every log entry.
|
|
32
|
+
|
|
33
|
+
#### `config.lumberjack.shift_age`
|
|
34
|
+
|
|
35
|
+
The age (in seconds) of log files before they are rotated, or a shift name (`daily`, `weekly`, `monthly`). The default is no log rotation. See the [logger](https://github.com/ruby/logger) gem documentation for details.
|
|
36
|
+
|
|
37
|
+
#### `config.lumberjack.shift_size`
|
|
38
|
+
|
|
39
|
+
The size (in bytes) of log files before they are rotated if `shift_age` is set to an integer. Defaults to `1048576` (1MB). See the [logger](https://github.com/ruby/logger) gem documentation for details.
|
|
40
|
+
|
|
41
|
+
#### `config.lumberjack.log_rake_tasks`
|
|
42
|
+
|
|
43
|
+
Whether to redirect `$stdout` and `$stderr` to `Rails.logger` for rake tasks that depend on the `:environment` task when using a Lumberjack::Logger. Defaults to `false`.
|
|
44
|
+
|
|
45
|
+
> [!TIP]
|
|
46
|
+
> This is useful for getting output from `db:migrate` and other rake tasks run in production into your logs. It can often be difficult to track down issues in these tasks without proper logging.
|
|
47
|
+
|
|
48
|
+
> [!NOTE]
|
|
49
|
+
> This setting is ignored when running in an interactive terminal session.
|
|
50
|
+
|
|
51
|
+
#### `config.lumberjack.middleware`
|
|
52
|
+
|
|
53
|
+
Whether to install Rack middleware that adds a Lumberjack context to each request. Defaults to `true`.
|
|
54
|
+
|
|
55
|
+
#### `config.lumberjack.silence_rack_request_started`
|
|
56
|
+
|
|
57
|
+
When set to `true`, the "Started ..." log lines generated by `Rails::Rack::Logger` will be suppressed. This can help reduce log noise in applications where these lines are not needed. Defaults to `false`.
|
|
58
|
+
|
|
59
|
+
#### `config.lumberjack.request_attributes_proc`
|
|
60
|
+
|
|
61
|
+
A proc to add to log entries for each Rack request. The proc will be called with the request object.
|
|
62
|
+
|
|
63
|
+
> [!TIP]
|
|
64
|
+
> You can use this feature to add both static attributes and dynamic attributes (using a proc) to all log entries within a request context.
|
|
65
|
+
|
|
66
|
+
```ruby
|
|
67
|
+
config.lumberjack.request_attributes_proc = ->(request) {
|
|
68
|
+
{
|
|
69
|
+
host: request.host,
|
|
70
|
+
method: request.request_method,
|
|
71
|
+
path: request.path,
|
|
72
|
+
request_id: request.request_id
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
#### Additional Options
|
|
78
|
+
|
|
79
|
+
> [!TIP]
|
|
80
|
+
> For more readable logs in development or test environments, you can set `config.lumberjack.template` to `:local` to use the built-in template intended for human readability.
|
|
81
|
+
>
|
|
82
|
+
> If you have attributes that are logged on every entry but don't want them cluttering up your development logs (i.e. `host`, `version`, etc.), you can set `config.lumberjack.exclude_attributes` to the attribute names to exclude.
|
|
83
|
+
|
|
84
|
+
You can include `Lumberjack::Rails.active_record_entry_formatter` in your logger formatter to format ActiveRecord models in log attributes with just the model name and id.
|
|
85
|
+
|
|
86
|
+
```ruby
|
|
87
|
+
config.lumberjack.formatter = Lumberjack.build_formatter do |formatter|
|
|
88
|
+
formatter.include(Lumberjack::Rails.active_record_entry_formatter)
|
|
89
|
+
end
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
#### Example Configuration
|
|
93
|
+
|
|
94
|
+
Here's an example of how you might configure Lumberjack in your `config/application.rb`:
|
|
95
|
+
|
|
96
|
+
```ruby
|
|
97
|
+
config.log_level = :info
|
|
98
|
+
|
|
99
|
+
# Set the program name on the logger
|
|
100
|
+
config.lumberjack.progname = Rails.application.railtie_name
|
|
101
|
+
|
|
102
|
+
# Add values we want on all log entries
|
|
103
|
+
config.lumberjack.attributes = {
|
|
104
|
+
host: Lumberjack::Utils.hostname, # Ensures hostname is UTF-8 encoded
|
|
105
|
+
pid: Lumberjack::Utils.global_pid # Returns a global PID value across all hosts
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
config.lumberjack.device = STDOUT
|
|
109
|
+
|
|
110
|
+
# Build the log entry formatter
|
|
111
|
+
config.lumberjack.formatter = Lumberjack.build_formatter do |formatter|
|
|
112
|
+
formatter.add(ActiveRecord::Base, :id)
|
|
113
|
+
|
|
114
|
+
# Format the :tags attribute as tags (e.g. [tag1] [tag2])
|
|
115
|
+
formatter.add_attribute("tags", :tags)
|
|
116
|
+
|
|
117
|
+
formatter.add_attribute("cost", :round, 2)
|
|
118
|
+
formatter.add_attribute_class("User") { |user| {id: user.id, username: user.username} }
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Use a custom template that adds the request id on all log entry lines.
|
|
122
|
+
config.lumberjack.template = "[{{time}} {{severity}} {{progname}} {{request_id}}] {{tags}} {{message}} -- {{attributes}}"
|
|
123
|
+
config.lumberjack.additional_lines = "> :request_id :message"
|
|
124
|
+
|
|
125
|
+
# Format log attributes as "[name=value]" (default is [name:value])
|
|
126
|
+
config.lumberjack.attribute_format = "[name=value]"
|
|
127
|
+
|
|
128
|
+
# Convert db:migrate and other rails task output to log entries
|
|
129
|
+
config.lumberjack.log_rake_tasks = true
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
> [!TIP]
|
|
133
|
+
> If you are using a logging pipeline in production that supports [JSONL](https://jsonlines.org/) logs, then check out the [lumberjack_json_device](https://github.com/bdurand/lumberjack_json_device). The gem provides a mechanism for defining the JSON schema for your logs and outputting them to JSONL.
|
|
134
|
+
|
|
135
|
+
> [!TIP]
|
|
136
|
+
> If you want more easily readable log output in development or test environments, you can set the `config.lumberjack.template` to `:local`.
|
|
137
|
+
>
|
|
138
|
+
> If you have attributes that are logged on every entry but don't want them cluttering up your development logs, you can set `config.lumberjack.exclude_attributes` to the attribute names to exclude.
|
|
139
|
+
>
|
|
140
|
+
> You can also colorize the logs by setting `config.lumberjack.colorize` to `true` and set the format of the severity with `config.lumberjack.severity_format`.
|
|
141
|
+
|
|
142
|
+
```ruby
|
|
143
|
+
config.lumberjack.template = :local
|
|
144
|
+
config.lumberjack.exclude_progname = true
|
|
145
|
+
config.lumberjack.exclude_attributes = [:host, :request_id]
|
|
146
|
+
config.lumberjack.colorize = true
|
|
147
|
+
config.lumberjack.severity_format = :emoji
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### TaggedLogger
|
|
151
|
+
|
|
152
|
+
Rails has its own solution for logging metadata in the `tagged` method added to logger which can add an array of tags to log entries.
|
|
153
|
+
|
|
154
|
+
Lumberjack supports the `tagged` method and will put the tags into the `tags` attribute. You can format these similar to how Rails formats them in the logger template with the `{{tags}}` formatter.
|
|
155
|
+
|
|
156
|
+
```ruby
|
|
157
|
+
# The :tags placeholder will be replaced with the tags attribute. This is the default template.
|
|
158
|
+
config.lumberjack.template = "[{{time}} {{severity}} {{progname}} ({{pid}})] {{tags}} {{message}} -- {{attributes}}"
|
|
159
|
+
|
|
160
|
+
# Add the :tags formatter. If you don't do this, then the tags will be formatted as an inspected array.
|
|
161
|
+
config.lumberjack.formatter = Lumberjack.build_formatter do |formatter|
|
|
162
|
+
formatter.add_attribute(:tags, :tags)
|
|
163
|
+
end
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Broadcast Logger
|
|
167
|
+
|
|
168
|
+
Rails provides a built-in mechanism for broadcasting log messages to multiple destinations. `Rails.logger` is actually an `ActiveSupport::BroadcastLogger` object wrapping one or more underlying loggers. When you call a method on `Rails.logger`, it will call that method on all underlying loggers. This can create some problems for methods that take a block since that block could get called once for each logger being broadcast to. Only one Lumberjack logger should be added `Rails.logger`. If more than one is added, method like `tag` or `context` that take a block will only be called on one of the loggers.
|
|
169
|
+
|
|
170
|
+
If you want to send your logs to multiple devices with Lumberjack, you can use the Multi device instead.
|
|
171
|
+
|
|
172
|
+
The one place that Rails uses multiple loggers out of the box is in development mode where logs are also sent to the console in addition to the log file. This functionality is supported.
|
|
173
|
+
|
|
174
|
+
### Lumberjack Contexts
|
|
175
|
+
|
|
176
|
+
Contexts are used in Lumberjack to provide isolation for changes to your logger. Within a context block, you can change the log level, progname, or attributes and they will only apply within that block execution.
|
|
177
|
+
|
|
178
|
+
Contexts will be added via `around` callbacks to the following frameworks if they are installed:
|
|
179
|
+
|
|
180
|
+
- ActionController
|
|
181
|
+
- ActiveJob
|
|
182
|
+
- ActionCable
|
|
183
|
+
- ActionMailer
|
|
184
|
+
- ActionMailbox
|
|
185
|
+
|
|
186
|
+
In addition, a Rack middleware will be added to ensure a context is set on Rails.logger for each request.
|
|
187
|
+
|
|
188
|
+
This allows you to change the log level or tag attributes on `Rails.logger` within your application code in these frameworks without affecting the global logger or the settings in any concurrent requests.
|
|
189
|
+
|
|
190
|
+
### Log Subscribers
|
|
191
|
+
|
|
192
|
+
Rails comes with several built-in log subscribers that are extended with Lumberjack. These include:
|
|
193
|
+
|
|
194
|
+
- `ActiveRecord::LogSubscriber`
|
|
195
|
+
- `ActionController::LogSubscriber`
|
|
196
|
+
- `ActionDispatch::LogSubscriber`
|
|
197
|
+
- `ActionView::LogSubscriber`
|
|
198
|
+
- `ActiveJob::LogSubscriber`
|
|
199
|
+
- `ActionMailer::LogSubscriber`
|
|
200
|
+
- `ActiveStorage::LogSubscriber`
|
|
201
|
+
|
|
202
|
+
These log subscribers will all use fork loggers. This these forked loggers are isolated from the main logger allowing you to change the log level and add attributes that is isolated to that log subscriber.
|
|
203
|
+
|
|
204
|
+
```ruby
|
|
205
|
+
# Set up log subscribers in an initializer
|
|
206
|
+
|
|
207
|
+
ActiveSupport.on_load(:action_controller) do
|
|
208
|
+
ActionController::LogSubscriber.logger.tag!(user_id: Current.user_id) # Tag all log entries with the user ID
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
ActiveSupport.on_load(:action_view) do
|
|
212
|
+
unless Rails.env.local?
|
|
213
|
+
ActionView::LogSubscriber.logger.level = :warn # Silence view rendering logs in non-local environments
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
You can also silence individual log subscriber events if you don't want to see them in your logs.
|
|
219
|
+
|
|
220
|
+
```ruby
|
|
221
|
+
ActiveSupport.on_load(:action_controller) do
|
|
222
|
+
ActionController::LogSubscriber.silence_event!!(:start_processing) # Silence the "Started ..." log lines
|
|
223
|
+
end
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
You can also silence the logs that Rack adds when a request starts processing. This subscriber is implemented a bit differently by Rails, so there is a different method to silence it.
|
|
227
|
+
|
|
228
|
+
```ruby
|
|
229
|
+
Lumberjack::Rails.silence_rack_request_started = true
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
You can also silence the Rack logger in your application's configuration.
|
|
233
|
+
|
|
234
|
+
```ruby
|
|
235
|
+
config.lumberjack.silence_rack_request_started = true
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
#### Enhanced ActionController Logging
|
|
239
|
+
|
|
240
|
+
The `ActionController::LogSubscriber` has been enhanced to allow you to specify additional attributes to be logged in the log entry when each request is finished processing. This log entry can be extremely useful as a canonical log entry for the request and Rails already supports adding some metadata onto the message. This extension allows you to add more metadata and add it as attributes for better structured logging.
|
|
241
|
+
|
|
242
|
+
```ruby
|
|
243
|
+
# Setup the additional attributes in an initializer.
|
|
244
|
+
|
|
245
|
+
ActiveSupport.on_load(:action_controller) do
|
|
246
|
+
# Add the IP address from the request to the canonical log entry for the request.
|
|
247
|
+
# The notification event is passed to the block.
|
|
248
|
+
ActionController::LogSubscriber.add_process_log_attribute(:ip_address) { |event| event.payload[:request].remote_ip }
|
|
249
|
+
|
|
250
|
+
# You can also add multiple attributes with with a block that returns a hash.
|
|
251
|
+
ActionController::LogSubscriber.process_log_attributes do |event|
|
|
252
|
+
request = event.payload[:request]
|
|
253
|
+
|
|
254
|
+
# Get the HTTP status code from the event payload.
|
|
255
|
+
status = event.payload[:status]
|
|
256
|
+
if status.nil? && (exception_class_name = event.payload[:exception]&.first)
|
|
257
|
+
status = ActionDispatch::ExceptionWrapper.status_code_for_exception(exception_class_name)
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
{
|
|
261
|
+
http: {
|
|
262
|
+
status: status,
|
|
263
|
+
method: request.method,
|
|
264
|
+
url: request.base_url + request.filtered_path,
|
|
265
|
+
useragent: request.user_agent,
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Log Formatter
|
|
273
|
+
|
|
274
|
+
ActiveRecord models logged in attributes will automatically be logged with a formatter that will only log the class name and id for the model. You can add additional formatters for `ApplicationRecord` or for your models to override this behavior.
|
|
275
|
+
|
|
276
|
+
### Testing
|
|
277
|
+
|
|
278
|
+
Lumberjack comes with built-in support for testing that critical log messages are generated. See the [lumberjack documentation](https://github.com/bdurand/lumberjack#testing-utilities) for more information.
|
|
279
|
+
|
|
280
|
+
If you are using RSpec, then you can use the [lumberjack_rails_rspec](https://github.com/bdurand/lumberjack_capture_device) gem for to add RSpec matchers for testing log messages to your test suite.
|
|
281
|
+
|
|
282
|
+
```ruby
|
|
283
|
+
# In spec/rails_helper.rb
|
|
284
|
+
|
|
285
|
+
require "lumberjack/capture_device/rspec"
|
|
286
|
+
|
|
287
|
+
RSpec.configure do |config|
|
|
288
|
+
config.around do |example|
|
|
289
|
+
capture_logger_around_example(Rails.logger, example)
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
RSpec.describe MyModel do
|
|
294
|
+
it "logs a message when doing something" do
|
|
295
|
+
MyModel.do_something_important
|
|
296
|
+
expect(Rails.logger).to include_log_entry(:info, /did something important/)
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
## Installation
|
|
302
|
+
|
|
303
|
+
Add this line to your application's Gemfile:
|
|
304
|
+
|
|
305
|
+
```ruby
|
|
306
|
+
gem 'lumberjack_rails'
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
And then execute:
|
|
310
|
+
|
|
311
|
+
```bash
|
|
312
|
+
$ bundle
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
Or install it yourself as:
|
|
316
|
+
|
|
317
|
+
```bash
|
|
318
|
+
$ gem install lumberjack_rails
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
## Contributing
|
|
322
|
+
|
|
323
|
+
Open a pull request on GitHub.
|
|
324
|
+
|
|
325
|
+
Please use the [standardrb](https://github.com/testdouble/standard) syntax and lint your code with `standardrb --fix` before submitting.
|
|
326
|
+
|
|
327
|
+
## License
|
|
328
|
+
|
|
329
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.0.0
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lumberjack
|
|
4
|
+
module Rails
|
|
5
|
+
# Extension for ActionCable::Connection::Base to wrap command processing with Lumberjack context.
|
|
6
|
+
#
|
|
7
|
+
# This module ensures that all logging within ActionCable command processing is wrapped
|
|
8
|
+
# with the appropriate Lumberjack logger context, maintaining log consistency
|
|
9
|
+
# and enabling tagged logging features.
|
|
10
|
+
module ActionCableExtension
|
|
11
|
+
# Override the command method to wrap it with Lumberjack logger context.
|
|
12
|
+
#
|
|
13
|
+
# @return [Object] the result of the original command method
|
|
14
|
+
def command(...)
|
|
15
|
+
Lumberjack::Rails.logger_context(logger) { super }
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lumberjack
|
|
4
|
+
module Rails
|
|
5
|
+
# Extension for ActionController::Base to wrap request processing with Lumberjack context.
|
|
6
|
+
#
|
|
7
|
+
# This module ensures that all logging within a controller action is wrapped
|
|
8
|
+
# with the appropriate Lumberjack logger context, maintaining log consistency
|
|
9
|
+
# and enabling tagged logging features.
|
|
10
|
+
module ActionControllerExtension
|
|
11
|
+
# Override the process method to wrap it with Lumberjack logger context.
|
|
12
|
+
#
|
|
13
|
+
# @return [Object] the result of the original process method
|
|
14
|
+
def process(...)
|
|
15
|
+
Lumberjack::Rails.logger_context(logger) { super }
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lumberjack::Rails
|
|
4
|
+
# This extension to the ActionController::LogSubscriber class allows specifying log attributes that
|
|
5
|
+
# will only be applied on the process_action event. This log entry already serves as the canonical
|
|
6
|
+
# log entry for requests and includes metadata such as duration, allocations, etc. With this extension
|
|
7
|
+
# you can add whatever additonal attributes you want to summarize what happened during the request
|
|
8
|
+
# as log attributes. This gives you more flexibility to add context to your request logs.
|
|
9
|
+
#
|
|
10
|
+
# You can add dynamically evaluated attributes by providing a block that takes the event as an argument.
|
|
11
|
+
#
|
|
12
|
+
# @example
|
|
13
|
+
# ActionController::LogSubscriber.add_process_log_attribute(:ip_address) do |event|
|
|
14
|
+
# event.payload.request.remote_ip
|
|
15
|
+
# end
|
|
16
|
+
#
|
|
17
|
+
# ActionController::LogSubscriber.add_process_log_attribute(:duration) do |event|
|
|
18
|
+
# event.duration
|
|
19
|
+
# end
|
|
20
|
+
module ActionControllerLogSubscriberExtension
|
|
21
|
+
extend ActiveSupport::Concern
|
|
22
|
+
|
|
23
|
+
prepended do
|
|
24
|
+
@lumberjack_process_log_attributes = {}
|
|
25
|
+
@lumberjack_process_log_blocks = []
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
class_methods do
|
|
29
|
+
# Add a log attribute to be included in the process_action log entry. You must provide
|
|
30
|
+
# either a static value or a block that takes the event as an argument to dynamically
|
|
31
|
+
# evaluate the value at log time.
|
|
32
|
+
#
|
|
33
|
+
# @param name [String, Symbol] the name of the log attribute
|
|
34
|
+
# @param value [Object] the static value of the log attribute (optional if block is provided)
|
|
35
|
+
# @yield [event] a block that takes the event as an argument to dynamically evaluate the value (optional if value is provided)
|
|
36
|
+
# @raise [ArgumentError] if neither a value nor a block is provided, or if both are provided
|
|
37
|
+
# @return [void]
|
|
38
|
+
def add_process_log_attribute(name, value = nil, &block)
|
|
39
|
+
raise ArgumentError.new("Must provide a value or a block") if value.nil? && block.nil?
|
|
40
|
+
raise ArgumentError.new("Cannot provide both a value and a block") if value && block
|
|
41
|
+
|
|
42
|
+
@lumberjack_process_log_attributes[name.to_s] = value || block
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Add log attributes to be included in the process_action log entry. The block must
|
|
46
|
+
# take an ActiveSupport::Notifications::Event as an argument and return a hash.
|
|
47
|
+
#
|
|
48
|
+
# @yieldparam event [ActiveSupport::Notifications::Event] the event being processed
|
|
49
|
+
# @yieldreturn [Hash] a hash of log attributes to be merged into the log entry attributes.
|
|
50
|
+
# @return [void]
|
|
51
|
+
def process_log_attributes(&block)
|
|
52
|
+
@lumberjack_process_log_blocks << block
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Get the log attributes to be included in the process_action log entry.
|
|
56
|
+
#
|
|
57
|
+
# @param event [ActiveSupport::Notifications::Event] the event being processed
|
|
58
|
+
# @return [Hash{String => Object}] a hash of log attributes
|
|
59
|
+
# @api private
|
|
60
|
+
def eval_process_log_attributes(event)
|
|
61
|
+
attributes = @lumberjack_process_log_attributes.each_with_object({}) do |(name, value_or_block), attrs|
|
|
62
|
+
attrs[name] = if value_or_block.respond_to?(:call)
|
|
63
|
+
value_or_block.call(event)
|
|
64
|
+
else
|
|
65
|
+
value_or_block
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
@lumberjack_process_log_blocks.each do |block|
|
|
70
|
+
attrs = block.call(event)
|
|
71
|
+
attributes.merge!(Lumberjack::Utils.flatten_attributes(attrs)) if attrs.is_a?(Hash)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
attributes
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
private
|
|
78
|
+
|
|
79
|
+
# Used for testing.
|
|
80
|
+
def clear_process_log_attributes
|
|
81
|
+
@lumberjack_process_log_attributes = {}
|
|
82
|
+
@lumberjack_process_log_blocks = []
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def process_action(event) # :nodoc:
|
|
87
|
+
with_process_logger_attributes(event) do
|
|
88
|
+
super
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
private
|
|
93
|
+
|
|
94
|
+
def with_process_logger_attributes(event, &block)
|
|
95
|
+
attributes = self.class.eval_process_log_attributes(event) if logger
|
|
96
|
+
if attributes && !attributes.empty?
|
|
97
|
+
logger.tag(attributes, &block)
|
|
98
|
+
else
|
|
99
|
+
block.call
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lumberjack
|
|
4
|
+
module Rails
|
|
5
|
+
# Extension for ActionMailbox::Base to wrap mailbox processing with Lumberjack context.
|
|
6
|
+
#
|
|
7
|
+
# This module ensures that all logging within mailbox processing is wrapped
|
|
8
|
+
# with the appropriate Lumberjack logger context, maintaining log consistency
|
|
9
|
+
# and enabling tagged logging features.
|
|
10
|
+
module ActionMailboxExtension
|
|
11
|
+
# Override the perform_processing method to wrap it with Lumberjack logger context.
|
|
12
|
+
#
|
|
13
|
+
# @return [Object] the result of the original perform_processing method
|
|
14
|
+
def perform_processing(...)
|
|
15
|
+
Lumberjack::Rails.logger_context(logger) { super }
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lumberjack
|
|
4
|
+
module Rails
|
|
5
|
+
# Extension for ActionMailer::Base to wrap mail processing with Lumberjack context.
|
|
6
|
+
#
|
|
7
|
+
# This module ensures that all logging within mailer processing is wrapped
|
|
8
|
+
# with the appropriate Lumberjack logger context, maintaining log consistency
|
|
9
|
+
# and enabling tagged logging features.
|
|
10
|
+
module ActionMailerExtension
|
|
11
|
+
# Override the process method to wrap it with Lumberjack logger context.
|
|
12
|
+
#
|
|
13
|
+
# @return [Object] the result of the original process method
|
|
14
|
+
def process(...)
|
|
15
|
+
Lumberjack::Rails.logger_context(logger) { super }
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lumberjack
|
|
4
|
+
module Rails
|
|
5
|
+
# Extension for ActiveJob::Base to wrap job execution with Lumberjack context.
|
|
6
|
+
#
|
|
7
|
+
# This module ensures that all logging within job execution is wrapped
|
|
8
|
+
# with the appropriate Lumberjack logger context, maintaining log consistency
|
|
9
|
+
# and enabling tagged logging features.
|
|
10
|
+
module ActiveJobExtension
|
|
11
|
+
# Override the perform_now method to wrap it with Lumberjack logger context.
|
|
12
|
+
#
|
|
13
|
+
# @return [Object] the result of the original perform_now method
|
|
14
|
+
def perform_now(...)
|
|
15
|
+
Lumberjack::Rails.logger_context(logger) { super }
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|