cogger 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/README.adoc +338 -99
- data/cogger.gemspec +3 -4
- data/lib/cogger/client.rb +3 -2
- data/lib/cogger/configuration.rb +48 -0
- data/lib/cogger/formatters/color.rb +24 -0
- data/lib/cogger/formatters/crash.rb +30 -0
- data/lib/cogger/formatters/json.rb +30 -0
- data/lib/cogger/formatters/kit/colorizer.rb +12 -0
- data/lib/cogger/formatters/kit/sanitizer.rb +37 -0
- data/lib/cogger/formatters/parsers/dynamic.rb +30 -0
- data/lib/cogger/formatters/parsers/individual.rb +61 -0
- data/lib/cogger/formatters/parsers/universal.rb +44 -0
- data/lib/cogger/formatters/processors/color.rb +59 -0
- data/lib/cogger/formatters/simple.rb +21 -0
- data/lib/cogger/hub.rb +69 -0
- data/lib/cogger/program.rb +10 -0
- data/lib/cogger/registry.rb +79 -0
- data/lib/cogger.rb +12 -2
- data.tar.gz.sig +0 -0
- metadata +43 -39
- metadata.gz.sig +0 -0
- data/lib/cogger/color.rb +0 -43
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 04acb9b4497c231d507b13ca31312db5cec0cf8e5ad8786d23afb20344acf9f6
|
4
|
+
data.tar.gz: 537e54ca280321a1522ff7f9b1789f2d396780317fade574d4260a3aee1cb495
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 46fd6ca89fd5c7da0c3fbf25ebe6e796cd24617688fbe8dd3681bc423d48842decb122e26d18b37391e0f34f5c3a239ab8bf5b81e72ac1f1379041142831cebf
|
7
|
+
data.tar.gz: 1fef8f07f3340fc6e3afe7b89ed3abd087e9ae5b55c46a0c0a23685a670eb7d8e85603220411592ee1f22a64993fdd0181b54990d3cf728bd55146376c14ca08
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/README.adoc
CHANGED
@@ -1,24 +1,31 @@
|
|
1
|
-
:pastel_link: link:https://github.com/piotrmurach/pastel[Pastel]
|
2
|
-
|
3
1
|
:toc: macro
|
4
2
|
:toclevels: 5
|
5
3
|
:figure-caption!:
|
6
4
|
|
5
|
+
:tone_link: link:https://alchemists.io/projects/tone[Tone]
|
6
|
+
:logger_link: link:https://rubyapi.org/o/s?q=Logger[Logger]
|
7
|
+
:format_link: link:https://ruby-doc.org/3.2.1/format_specifications_rdoc.html[Format Specification]
|
8
|
+
:pattern_matching_link: link:https://alchemists.io/articles/ruby_pattern_matching[pattern matching]
|
9
|
+
:refinements_link: link:https://alchemists.io/projects/refinements[Refinements]
|
10
|
+
|
7
11
|
= Cogger
|
8
12
|
|
9
|
-
Cogger is a portmanteau for
|
10
|
-
decorates Ruby's native logger with colorized output.
|
13
|
+
Cogger is a portmanteau for custom logging (i.e. `[c]ustom + l[ogger] = cogger`) which enhances Ruby's native logging functionality with additional features such as dynamic emojis, colorized text, structured JSON, and much more.
|
11
14
|
|
12
15
|
toc::[]
|
13
16
|
|
14
17
|
== Features
|
15
18
|
|
16
19
|
- Decorates Ruby's default `Logger`.
|
17
|
-
-
|
20
|
+
- Provides dynamic emoji output based on severity.
|
21
|
+
- Provides dynamic or specific color decoration via the {tone_link} gem.
|
22
|
+
- Provides customizable formatters for simple, color, JSON, and/or custom output.
|
23
|
+
- Provides customizable templates which leverage the native {format_link}.
|
24
|
+
- Provides filtering of sensitive information.
|
18
25
|
|
19
26
|
== Screenshot
|
20
27
|
|
21
|
-
image::https://alchemists.io/images/projects/cogger/screenshots/console.png[Console,width=
|
28
|
+
image::https://alchemists.io/images/projects/cogger/screenshots/console.png[Console,width=1139,height=211,role=focal_point]
|
22
29
|
|
23
30
|
== Requirements
|
24
31
|
|
@@ -35,150 +42,380 @@ bin/setup
|
|
35
42
|
|
36
43
|
== Usage
|
37
44
|
|
38
|
-
All
|
45
|
+
All interaction is provided by `Cogger` which can be used as follows:
|
46
|
+
|
47
|
+
[source,ruby]
|
48
|
+
----
|
49
|
+
logger = Cogger.new
|
50
|
+
logger.info "demo" # "demo"
|
51
|
+
----
|
52
|
+
|
53
|
+
If you set your logging level to `debug`, you can walk through each level:
|
54
|
+
|
55
|
+
[source,ruby]
|
56
|
+
----
|
57
|
+
logger = Cogger.new level: :debug
|
58
|
+
|
59
|
+
# Without blocks.
|
60
|
+
logger.debug "demo" # "demo"
|
61
|
+
logger.info "demo" # "demo"
|
62
|
+
logger.warn "demo" # "demo"
|
63
|
+
logger.error "demo" # "demo"
|
64
|
+
logger.fatal "demo" # "demo"
|
65
|
+
logger.unknown "demo" # "demo"
|
66
|
+
logger.any "demo" # "demo"
|
67
|
+
|
68
|
+
# With blocks.
|
69
|
+
logger.debug { "demo" } # "demo"
|
70
|
+
logger.info { "demo" } # "demo"
|
71
|
+
logger.warn { "demo" } # "demo"
|
72
|
+
logger.error { "demo" } # "demo"
|
73
|
+
logger.fatal { "demo" } # "demo"
|
74
|
+
logger.unknown { "demo" } # "demo"
|
75
|
+
logger.any { "demo" } # "demo"
|
76
|
+
----
|
77
|
+
|
78
|
+
...or, if you'd like to display all severities at once, use:
|
39
79
|
|
40
80
|
[source,ruby]
|
41
81
|
----
|
42
|
-
logger
|
82
|
+
%i[debug info warn error fatal unknown any].each { |severity| logger.public_send severity, "demo" }
|
83
|
+
----
|
84
|
+
|
85
|
+
=== Initialization
|
86
|
+
|
87
|
+
When creating a new logger, you can configure behavior via the following attributes:
|
88
|
+
|
89
|
+
* `id`: The program/process ID which shows up in the logs as your `id`. Default: `$PROGRAM_NAME`. For example, if initialized within `demo.rb`, the `id` would be `"demo"`,
|
90
|
+
* `io`: The input/output stream. This can be `STDOUT/$stdout`, a file/path, or `nil`. Default: `$stdout`.
|
91
|
+
* `level`: The severity level you want to log at. Can be `:debug`, `:info`, `:warn`, `:error`, `:fatal`, or `:unknown`. Default: `:info`.
|
92
|
+
* `formatter`: The formatter to use for formatting your log output. Default: `Cogger::Formatter::Color`. See the _Formatters_ section for more info.
|
93
|
+
* `mode`: The binary mode which determines if your logs should be written in binary mode or not. Can be `true` or `false` and is identical to the `binmode` functionality found in the {logger_link} class. Default: `false`.
|
94
|
+
* `age`: The rotation age of your log. This only applies when logging to a file. This is equivalent to the `shift_age` as found with the {logger_link} class. Default: `0`.
|
95
|
+
* `size`: The rotation size of your log. This only applies when logging to a file. This is equivalent to the `shift_size` as found with the {logger_link} class. Default: `1,048,576` (i.e. 1 MB).
|
96
|
+
* `suffix`: The rotation suffix. This only applies when logging to a file. This is equivalent to the `shift_period_suffix` as found with the {logger_link} class and is used when creating new rotation files. Default: `%Y-%m-%d`.
|
43
97
|
|
44
|
-
logger
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
logger
|
50
|
-
|
51
|
-
|
52
|
-
logger.
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
98
|
+
Given the above description, here's how'd you create a new logger instance with all attributes:
|
99
|
+
|
100
|
+
[source,ruby]
|
101
|
+
----
|
102
|
+
# Default
|
103
|
+
logger = Cogger.new
|
104
|
+
|
105
|
+
# Custom
|
106
|
+
logger = Cogger.new id: :demo,
|
107
|
+
io: "demo.log",
|
108
|
+
level: :debug,
|
109
|
+
mode: false,
|
110
|
+
age: 5,
|
111
|
+
size: 1_000,
|
112
|
+
suffix: "%Y"
|
113
|
+
----
|
114
|
+
|
115
|
+
=== Environment
|
116
|
+
|
117
|
+
The default log level is `INFO` but can be customized via your environment. For instance, you could
|
118
|
+
set the logging level to any of the following:
|
119
|
+
|
120
|
+
[source,bash]
|
121
|
+
----
|
122
|
+
export LOG_LEVEL=DEBUG
|
123
|
+
export LOG_LEVEL=INFO
|
124
|
+
export LOG_LEVEL=WARN
|
125
|
+
export LOG_LEVEL=ERROR
|
126
|
+
export LOG_LEVEL=FATAL
|
127
|
+
export LOG_LEVEL=UNKNOWN
|
128
|
+
export LOG_LEVEL=ANY
|
58
129
|
----
|
59
130
|
|
60
|
-
By default,
|
61
|
-
|
62
|
-
|
131
|
+
By default, `Cogger` will automatically use whatever is set via the `LOG_LEVEL` environment variable unless overwritten during initialization.
|
132
|
+
|
133
|
+
=== Templates
|
63
134
|
|
64
|
-
|
135
|
+
Templates are used by all formatters and adhere to {format_link} as used by `Kernel#format`. All specifiers, flags, width, and precision are supported except for the following restrictions:
|
136
|
+
|
137
|
+
- Use of _reference by name_ is required which means `%<demo>s` is allowed but `%{demo}` is not. This is because _reference by name_ is required for regular expressions and/or {pattern_matching_link}.
|
138
|
+
- Use of the `n$` flag is prohibited because this isn't compatible with the above.
|
139
|
+
|
140
|
+
In addition to the above, the {format_link} is further enhanced with the use of _universal_ and _individual_ directives which are primarily used by the _color_ formatter but might prove useful for other formatters. Example:
|
65
141
|
|
66
142
|
[source,ruby]
|
67
143
|
----
|
68
|
-
|
144
|
+
# Universal: Dynamic
|
145
|
+
"<dynamic>%<severity>s %<at>s %<id>s %<message>s</dynamic>"
|
146
|
+
|
147
|
+
# Universal: Specific
|
148
|
+
"<green>%<severity>s %<at>s %<id>s %<message>s</green>"
|
149
|
+
|
150
|
+
# Individual: Dynamic
|
151
|
+
"%<severity:dynamic>s %<at:green>s %<id:green>s %<message:green>s"
|
69
152
|
|
70
|
-
|
71
|
-
|
72
|
-
logger.progname # nil
|
153
|
+
# Individual: Specific
|
154
|
+
"%<severity:purple>s %<at:yellow>s %<id:cyan>s %<message:green>s"
|
73
155
|
----
|
74
156
|
|
75
|
-
|
157
|
+
Here's a detailed breakdown of the above:
|
76
158
|
|
77
|
-
|
78
|
-
|
159
|
+
* *Universal*: Applies color universally to the _entire_ template and requires you to:
|
160
|
+
** Wrap your entire template in a and start (`<example>`) and end tag (`</example>`).
|
161
|
+
** Your tag names must either be `<dynamic></dynamic>`, any default color (i.e. `<green></green>`), or alias (i.e. `<your_alias></your_alias>`) as supported by the {tone_link} gem.
|
162
|
+
* *Individual*: Individual templates allow you to apply color to _specific_ attributes and require you to:
|
163
|
+
** Format your attributes as `attribute:directive`. The colon delimiter is required to separate your attribute for your color choice.
|
164
|
+
** The color value (what follows after the colon) can be `dynamic`, any default color (i.e. `green`), or alias (i.e. `your_alias`) as supported by the {tone_link} gem.
|
79
165
|
|
80
|
-
|
166
|
+
In addition to the general categorization of universal and individual tags, each support the following directives:
|
81
167
|
|
82
|
-
|
83
|
-
you
|
168
|
+
* *Dynamic*: A dynamic directive means that color will be determined by severity level only. This means if info level is used, the associated color (alias) for info will be applied. Same goes for warn, error, etc.
|
169
|
+
* *Specific*: A specific directive means the color you use will be applied without any further processing regardless of the severity level. This gives you the ability to customize your colors further in situations where dynamic coloring isn't enough.
|
170
|
+
|
171
|
+
=== Emojis
|
172
|
+
|
173
|
+
In addition to coloring to your log output, you can add emojis as well. Here are the defaults:
|
84
174
|
|
85
175
|
[source,ruby]
|
86
176
|
----
|
87
|
-
|
177
|
+
Cogger.emojis
|
178
|
+
|
179
|
+
# {
|
180
|
+
# :debug => "🔎",
|
181
|
+
# :info => "🟢",
|
182
|
+
# :warn => "⚠️ ",
|
183
|
+
# :error => "🛑",
|
184
|
+
# :fatal => "🔥"
|
185
|
+
# }
|
88
186
|
----
|
89
187
|
|
90
|
-
|
188
|
+
To add an emoji, use:
|
91
189
|
|
92
190
|
[source,ruby]
|
93
191
|
----
|
94
|
-
|
192
|
+
Cogger.add_emoji(:tada, "🎉")
|
193
|
+
.add_emoji :favorite, "❇️"
|
95
194
|
----
|
96
195
|
|
97
|
-
|
98
|
-
normal logger. Example:
|
196
|
+
By default, the `:emoji` formatter provides dynamic rendering of emojis based on severity level. Example:
|
99
197
|
|
100
198
|
[source,ruby]
|
101
199
|
----
|
102
|
-
logger = Cogger.
|
103
|
-
|
104
|
-
|
105
|
-
|
200
|
+
logger = Cogger.new formatter: :emoji
|
201
|
+
logger.info "demo"
|
202
|
+
|
203
|
+
# 🟢 demo
|
106
204
|
----
|
107
205
|
|
108
|
-
|
206
|
+
If you wanted to use a specific emoji, you could use the color formatter with a specific template:
|
109
207
|
|
110
208
|
[source,ruby]
|
111
209
|
----
|
112
|
-
logger = Cogger.
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
instance.datetime_format = "%Y-%m-%d"
|
117
|
-
end
|
210
|
+
logger = Cogger.new formatter: Cogger::Formatters::Color.new("%<emoji:tada>s %<message:dynamic>s")
|
211
|
+
logger.info "demo"
|
212
|
+
|
213
|
+
# 🎉 demo
|
118
214
|
----
|
119
215
|
|
120
|
-
|
216
|
+
Keep in mind that using a specific, non-dynamic, emoji will _always_ display no matter the current severity level.
|
121
217
|
|
122
|
-
|
123
|
-
set the logging level to any of the following:
|
218
|
+
=== Formatters
|
124
219
|
|
125
|
-
|
220
|
+
Multiple formatters are provided for you which can be further customized as needed. Here's what is provided by default:
|
221
|
+
|
222
|
+
[source,ruby]
|
126
223
|
----
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
224
|
+
Cogger.formatters
|
225
|
+
|
226
|
+
# {
|
227
|
+
# :color => [
|
228
|
+
# Cogger::Formatters::Color < Object,
|
229
|
+
# nil
|
230
|
+
# ],
|
231
|
+
# :detail => [
|
232
|
+
# Cogger::Formatters::Simple < Object,
|
233
|
+
# "[%<id>s] [%<severity>s] [%<at>s] %<message>s"
|
234
|
+
# ],
|
235
|
+
# :emoji => [
|
236
|
+
# Cogger::Formatters::Color < Object,
|
237
|
+
# "%<emoji:dynamic>s% <message:dynamic>s"
|
238
|
+
# ],
|
239
|
+
# :json => [
|
240
|
+
# Cogger::Formatters::JSON < Object,
|
241
|
+
# nil
|
242
|
+
# ],
|
243
|
+
# :simple => [
|
244
|
+
# Cogger::Formatters::Simple < Object,
|
245
|
+
# nil
|
246
|
+
# ],
|
247
|
+
# :rack => [
|
248
|
+
# Cogger::Formatters::Simple < Object,
|
249
|
+
# "[%<id>s] [%<severity>s] [%<at>s] %<verb>s %<status>s %<duration>s %<ip>s %<path>s %<length>s # %<params>s"
|
250
|
+
# ]
|
251
|
+
# }
|
252
|
+
----
|
253
|
+
|
254
|
+
You can add a formatter by providing a unique name, class, and associated template (`nil` can be used if you want to use the formatter's default template):
|
255
|
+
|
256
|
+
[source,ruby]
|
257
|
+
----
|
258
|
+
# Add
|
259
|
+
Cogger.add_formatter :basic, Cogger::Formatters::Simple, "%<severity>s %<message>s"
|
260
|
+
|
261
|
+
# Get
|
262
|
+
Cogger.get_formatter :basic
|
263
|
+
# [Cogger::Formatters::Simple, "%<severity>s %<message>s"]
|
134
264
|
----
|
135
265
|
|
136
|
-
|
137
|
-
variable unless overwritten during initialization.
|
266
|
+
Symbols or strings can be used interchangeably when adding/getting formatters. As mentioned above, a template doesn't have to be supplied if you want to use the formatter's default template which can be inspected by asking for it:
|
138
267
|
|
139
|
-
|
268
|
+
[source,ruby]
|
269
|
+
----
|
270
|
+
Cogger::Formatters::Simple::TEMPLATE
|
271
|
+
# "%<message>s"
|
272
|
+
----
|
273
|
+
|
274
|
+
💡 When you find yourself customizing any of the default formatters, you can reduce typing by adding your custom configuration to the registry and then referring to it via a symbol when initializing a new logger.
|
275
|
+
|
276
|
+
==== Simple
|
277
|
+
|
278
|
+
The simple formatter is a bare bones formatter that uses no color information, doesn't support the universal/dynamic template syntax, and only supports the {format_link} as mentioned in the _Templates_ section earlier. This formatter can be used via the following template variations:
|
279
|
+
|
280
|
+
[source,ruby]
|
281
|
+
----
|
282
|
+
logger = Cogger.new formatter: :detail
|
283
|
+
logger = Cogger.new formatter: :simple
|
284
|
+
logger = Cogger.new formatter: :rack
|
285
|
+
----
|
286
|
+
|
287
|
+
==== Color
|
288
|
+
|
289
|
+
The color formatter is enabled by default and is the equivalent of initializing with either of the following:
|
290
|
+
|
291
|
+
[source,ruby]
|
292
|
+
----
|
293
|
+
logger = Cogger.new
|
294
|
+
logger = Cogger.new formatter: Cogger::Formatters::Color.new
|
295
|
+
logger = Cogger.new formatter: Cogger::Formatters::Color.new("%<message:dynamic>s")
|
296
|
+
----
|
297
|
+
|
298
|
+
All three of the above examples are identical so you can start to see how different formatters can be used and customized further. Please refer back to the _Templates_ section on how to customize this formatter with more sophisticated templates.
|
299
|
+
|
300
|
+
In addition to template customization, you can customize your color aliases as well. Default colors are provided by {tone_link} which are _aliased_ by log level:
|
301
|
+
|
302
|
+
[source,ruby]
|
303
|
+
----
|
304
|
+
Cogger.aliases
|
305
|
+
|
306
|
+
# {
|
307
|
+
# debug: :white,
|
308
|
+
# info: :green,
|
309
|
+
# warn: :yellow,
|
310
|
+
# error: :red,
|
311
|
+
# fatal: %i[white bold on_red],
|
312
|
+
# unknown: %i[white bold],
|
313
|
+
# any: %i[white bold]
|
314
|
+
# }
|
315
|
+
----
|
316
|
+
|
317
|
+
This allows a color or combination of color styles (i.e. foreground + background) to be dynamically applied based on log level. You can add additional aliases via:
|
318
|
+
|
319
|
+
[source,ruby]
|
320
|
+
----
|
321
|
+
Cogger.add_alias :mystery, :white, :on_purple
|
322
|
+
----
|
323
|
+
|
324
|
+
Once an alias is added, it can be immediately applied via the template of your formatter. Example:
|
325
|
+
|
326
|
+
[source,ruby]
|
327
|
+
----
|
328
|
+
# Applies the `mystery` alias universally to your template.
|
329
|
+
logger = Cogger.new formatter: Cogger::Formatters::Color.new("<mystery>%<message>s</mystery>")
|
330
|
+
----
|
331
|
+
|
332
|
+
==== JSON
|
140
333
|
|
141
|
-
|
334
|
+
This formatter is similar in behavior to the _simple_ formatter except the template allows you to order the layout of your keys only. All other information is ignored. To use:
|
142
335
|
|
143
336
|
[source,ruby]
|
144
337
|
----
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
338
|
+
# Default order
|
339
|
+
logger = Cogger.new formatter: :json
|
340
|
+
logger.info verb: "GET", path: "/"
|
341
|
+
|
342
|
+
# {"id":"console","severity":"INFO","at":"2023-04-10 09:03:55 -0600","verb":"GET","path":"/"}
|
343
|
+
|
344
|
+
# Custom order
|
345
|
+
logger = Cogger.new formatter: Cogger::Formatters::JSON.new("%<severity>s %<verb>s")
|
346
|
+
logger.info verb: "GET", path: "/"
|
347
|
+
|
348
|
+
# {"severity":"INFO","verb":"GET","id":"console","at":"2023-04-10 09:05:03 -0600","path":"/"}
|
154
349
|
----
|
155
350
|
|
156
|
-
|
157
|
-
|
158
|
-
|
351
|
+
Your template can be a full or partial match of keys. If no keys match what is defined in the template, then the original order of the keys will be used instead.
|
352
|
+
|
353
|
+
==== Custom
|
159
354
|
|
355
|
+
Should none of the built-in formatters be to your liking, you can implement, use, and/or register a custom formatter as well. The most minimum, bare bones, skeleton would be:
|
160
356
|
|
161
357
|
[source,ruby]
|
162
358
|
----
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
unknown: %i[white on_black],
|
171
|
-
any: %i[white on_black]
|
172
|
-
}
|
173
|
-
)
|
359
|
+
class MyFormatter
|
360
|
+
TEMPLATE = "%<message>s"
|
361
|
+
|
362
|
+
def initialize template = TEMPLATE, sanitizer: Kit::Sanitizer.new
|
363
|
+
@template = template
|
364
|
+
@sanitizer = sanitizer
|
365
|
+
end
|
174
366
|
|
175
|
-
|
367
|
+
def call(*entry) = "#{format template, sanitizer.call(*entry)}\n"
|
368
|
+
|
369
|
+
private
|
370
|
+
|
371
|
+
attr_reader :template, :sanitizer
|
372
|
+
end
|
176
373
|
----
|
177
374
|
|
178
|
-
The
|
179
|
-
style accepted by `Pastel#decorate` method is supported.
|
375
|
+
There is no restriction on what dependency you might want to initialize your custom formatter with but -- as a bare minimum -- you'll want to provide a default template and inject the sanitizer which sanitizes the raw log entry into a hash you can interact with in your implementation. The only other requirement is that you must implement `#call` which takes a log entry which is an array of positional arguments (i.e. `severity`, `at`, `id`, `message`) and answers back a formatted string. If you need more examples you can either read the link:https://rubyapi.org/o/logger/formatter#method-i-call[Logger::Formatter] or look at any of the formatters provided within this gem.
|
180
376
|
|
181
|
-
|
377
|
+
=== Filters
|
378
|
+
|
379
|
+
Filters allow you to mask sensitive information you don't want showing up in your logs. Here are the defaults:
|
380
|
+
|
381
|
+
[source,ruby]
|
382
|
+
----
|
383
|
+
Cogger.filters
|
384
|
+
|
385
|
+
# [
|
386
|
+
# :_csrf,
|
387
|
+
# :password,
|
388
|
+
# :password_confirmation
|
389
|
+
# ]
|
390
|
+
----
|
391
|
+
|
392
|
+
To add additional filters, use:
|
393
|
+
|
394
|
+
[source,ruby]
|
395
|
+
----
|
396
|
+
Cogger.add_filter(:login)
|
397
|
+
.add_filter "email"
|
398
|
+
|
399
|
+
# [
|
400
|
+
# :_csrf,
|
401
|
+
# :password,
|
402
|
+
# :password_confirmation,
|
403
|
+
# :login,
|
404
|
+
# :email
|
405
|
+
# ]
|
406
|
+
----
|
407
|
+
|
408
|
+
Symbols and strings can be used interchangeably but are stored as symbols since symbols are used when filtering log entries. Once your filters are in place, you can immediately see their effects:
|
409
|
+
|
410
|
+
[source,ruby]
|
411
|
+
----
|
412
|
+
logger = Cogger.new formatter: :json
|
413
|
+
logger.info login: "jayne", password: "secret"
|
414
|
+
|
415
|
+
# {"id":"console","severity":"INFO","at":"2023-04-09 17:33:00 -0600","login":"[FILTERED]","password":"[FILTERED]"}
|
416
|
+
----
|
417
|
+
|
418
|
+
=== Testing
|
182
419
|
|
183
420
|
When testing the Cogger client, you might find it convenient to use `StringIO`, or a file, for
|
184
421
|
logging purposes in order to not pollute your test output but also have a convenient way to see what
|
@@ -187,7 +424,7 @@ was logged. Example:
|
|
187
424
|
[source,ruby]
|
188
425
|
----
|
189
426
|
class Demo
|
190
|
-
def initialize logger: Cogger.
|
427
|
+
def initialize logger: Cogger.new
|
191
428
|
@logger = logger
|
192
429
|
end
|
193
430
|
|
@@ -199,22 +436,24 @@ class Demo
|
|
199
436
|
end
|
200
437
|
|
201
438
|
RSpec.describe Demo do
|
439
|
+
using Refinements::StringIOs
|
440
|
+
|
202
441
|
subject(:demo) { described_class.new logger: }
|
203
442
|
|
204
|
-
let(:logger) { Cogger.
|
443
|
+
let(:logger) { Cogger.new io: }
|
444
|
+
let(:io) { StringIO.new }
|
205
445
|
|
206
446
|
describe "#say" do
|
207
447
|
it "logs text" do
|
208
448
|
demo.say "test"
|
209
|
-
expect(
|
449
|
+
expect(io.reread).to include("test")
|
210
450
|
end
|
211
451
|
end
|
212
452
|
end
|
213
453
|
----
|
214
454
|
|
215
455
|
Notice that when testing the instance of `Demo` and injecting a logger which logs to a string I/O
|
216
|
-
object, you can conveniently
|
217
|
-
to write while also not adding additional noise to your test suite's output.
|
456
|
+
object, you can conveniently _reread_ the string -- provided by the {refinements_link} gem -- to see what was logged. This makes your specs easier to write while also not adding additional noise to your test suite's output.
|
218
457
|
|
219
458
|
== Development
|
220
459
|
|
data/cogger.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |spec|
|
4
4
|
spec.name = "cogger"
|
5
|
-
spec.version = "0.
|
5
|
+
spec.version = "0.7.0"
|
6
6
|
spec.authors = ["Brooke Kuhlmann"]
|
7
7
|
spec.email = ["brooke@alchemists.io"]
|
8
8
|
spec.homepage = "https://alchemists.io/projects/cogger"
|
9
|
-
spec.summary = "
|
9
|
+
spec.summary = "A customizable logger."
|
10
10
|
spec.license = "Hippocratic-2.1"
|
11
11
|
|
12
12
|
spec.metadata = {
|
@@ -23,8 +23,7 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.cert_chain = [Gem.default_cert_path]
|
24
24
|
|
25
25
|
spec.required_ruby_version = "~> 3.2"
|
26
|
-
spec.add_dependency "
|
27
|
-
spec.add_dependency "refinements", "~> 10.0"
|
26
|
+
spec.add_dependency "tone", "~> 0.1"
|
28
27
|
spec.add_dependency "zeitwerk", "~> 2.6"
|
29
28
|
|
30
29
|
spec.extra_rdoc_files = Dir["README*", "LICENSE*"]
|
data/lib/cogger/client.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require "forwardable"
|
4
4
|
require "logger"
|
5
5
|
require "refinements/loggers"
|
6
|
+
require "tone"
|
6
7
|
|
7
8
|
module Cogger
|
8
9
|
# Provides the primary client for colorized logging.
|
@@ -13,7 +14,7 @@ module Cogger
|
|
13
14
|
|
14
15
|
delegate %i[formatter level progname debug info warn error fatal unknown] => :logger
|
15
16
|
|
16
|
-
def initialize logger = Logger.new($stdout), color:
|
17
|
+
def initialize logger = Logger.new($stdout), color: Cogger.color, **attributes
|
17
18
|
@logger = logger
|
18
19
|
@color = color
|
19
20
|
@attributes = attributes
|
@@ -42,7 +43,7 @@ module Cogger
|
|
42
43
|
def default_level = logger.class.const_get ENV.fetch("LOG_LEVEL", "INFO")
|
43
44
|
|
44
45
|
def default_formatter
|
45
|
-
-> severity, _at, _name, message { "#{color
|
46
|
+
-> severity, _at, _name, message { "#{color[message, severity.downcase]}\n" }
|
46
47
|
end
|
47
48
|
end
|
48
49
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "logger"
|
4
|
+
|
5
|
+
module Cogger
|
6
|
+
# Defines the default configuration for all pipes.
|
7
|
+
Configuration = Data.define(
|
8
|
+
:id,
|
9
|
+
:io,
|
10
|
+
:level,
|
11
|
+
:formatter,
|
12
|
+
:mode,
|
13
|
+
:age,
|
14
|
+
:size,
|
15
|
+
:suffix,
|
16
|
+
:logger
|
17
|
+
) do
|
18
|
+
def initialize id: Program.call,
|
19
|
+
io: $stdout,
|
20
|
+
level: Logger.const_get(ENV.fetch("LOG_LEVEL", "INFO")),
|
21
|
+
formatter: Formatters::Color.new,
|
22
|
+
mode: false,
|
23
|
+
age: 0,
|
24
|
+
size: 1_048_576,
|
25
|
+
suffix: "%Y-%m-%d",
|
26
|
+
logger: Logger
|
27
|
+
super
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_logger
|
31
|
+
logger.new io,
|
32
|
+
age,
|
33
|
+
size,
|
34
|
+
progname: id,
|
35
|
+
level:,
|
36
|
+
formatter:,
|
37
|
+
binmode: mode,
|
38
|
+
shift_period_suffix: suffix
|
39
|
+
end
|
40
|
+
|
41
|
+
def inspect
|
42
|
+
"#<#{self.class} @id=#{id}, @io=#{io.class}, @level=#{level}, " \
|
43
|
+
"@formatter=#{formatter.class}, " \
|
44
|
+
"@mode=#{mode}, @age=#{age}, @size=#{size}, @suffix=#{suffix.inspect}, " \
|
45
|
+
"@logger=#{logger}>"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|