sinlog 0.0.5 → 0.0.7
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 +4 -4
- data/docs/Changelog.md +40 -0
- data/docs/Readme-zh.md +163 -83
- data/docs/Readme.md +192 -98
- data/lib/sinlog/01_consts.rb +27 -0
- data/lib/sinlog/02_logger.rb +109 -0
- data/lib/sinlog/03_module_fn.rb +146 -0
- data/lib/sinlog/04_log_ext.rb +41 -0
- data/lib/sinlog/05_short_ext.rb +52 -0
- data/lib/sinlog/06_loggable.rb +160 -0
- data/lib/sinlog/07_proc.rb +93 -0
- data/lib/sinlog/08_module_short_ext.rb +89 -0
- data/lib/sinlog/version.rb +2 -2
- data/lib/sinlog.rb +31 -17
- metadata +10 -10
- data/lib/sinlog/init.rb +0 -106
- data/lib/sinlog/log_ext.rb +0 -62
- data/lib/sinlog/log_short_ext.rb +0 -69
- data/lib/sinlog/loggable.rb +0 -57
- data/rbi/sinlog/init.rbi +0 -34
- data/rbi/sinlog/log_ext.rbi +0 -27
- data/rbi/sinlog/log_short_ext.rbi +0 -27
- data/rbi/sinlog/loggable.rbi +0 -25
- data/rbi/sinlog/version.rbi +0 -3
data/docs/Readme.md
CHANGED
|
@@ -22,18 +22,22 @@ A very, very simple Ruby singleton logger with colored log levels.
|
|
|
22
22
|
Table of Contents (click to expand)
|
|
23
23
|
</summary>
|
|
24
24
|
|
|
25
|
+
- [API DOC](#api-doc)
|
|
25
26
|
- [Quick Start](#quick-start)
|
|
26
27
|
- [Installation](#installation)
|
|
27
|
-
- [
|
|
28
|
+
- [API Style](#api-style)
|
|
29
|
+
- [Procedural Style](#procedural-style)
|
|
30
|
+
- [OOP style](#oop-style)
|
|
31
|
+
- [FP Style](#fp-style)
|
|
32
|
+
- [Monkey Patching](#monkey-patching)
|
|
33
|
+
- [Comparison Table](#comparison-table)
|
|
28
34
|
- [Method List](#method-list)
|
|
29
|
-
- [
|
|
30
|
-
- [
|
|
35
|
+
- [Mixin \& Refin](#mixin--refin)
|
|
36
|
+
- [ShortMixin \& ShortRefin](#shortmixin--shortrefin)
|
|
31
37
|
- [Examples](#examples)
|
|
32
|
-
- [Classic Method Call (Neither Mixin nor Refinement)](#classic-method-call-neither-mixin-nor-refinement)
|
|
33
|
-
- [Mixin](#mixin)
|
|
34
38
|
- [Refinement](#refinement)
|
|
39
|
+
- [Mixin](#mixin)
|
|
35
40
|
- [Learn Sinlog API by Example](#learn-sinlog-api-by-example)
|
|
36
|
-
- [Classic Method Call](#classic-method-call)
|
|
37
41
|
- [Advanced](#advanced)
|
|
38
42
|
- [Real World Example](#real-world-example)
|
|
39
43
|
- [Log Levels](#log-levels)
|
|
@@ -43,11 +47,17 @@ Table of Contents (click to expand)
|
|
|
43
47
|
- [Notes](#notes)
|
|
44
48
|
- [Side Note](#side-note)
|
|
45
49
|
- [Changelog](#changelog)
|
|
46
|
-
- [
|
|
50
|
+
- [v0.0.7 (2025-12-03)](#v007-2025-12-03)
|
|
47
51
|
- [License](#license)
|
|
48
52
|
|
|
49
53
|
</details>
|
|
50
54
|
|
|
55
|
+
## API DOC
|
|
56
|
+
|
|
57
|
+

|
|
58
|
+
|
|
59
|
+
- Github Pages: <https://2moe.github.io/sinlog-gem>
|
|
60
|
+
|
|
51
61
|
## Quick Start
|
|
52
62
|
|
|
53
63
|
## Installation
|
|
@@ -58,31 +68,123 @@ Table of Contents (click to expand)
|
|
|
58
68
|
gem install sinlog
|
|
59
69
|
```
|
|
60
70
|
|
|
61
|
-
###
|
|
71
|
+
### API Style
|
|
72
|
+
|
|
73
|
+
In this library, a set of similar functionalities can be accessed through multiple different calling approaches.
|
|
74
|
+
|
|
75
|
+
Which style you choose mainly depends on your personal preference.
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
#### Procedural Style
|
|
79
|
+
|
|
80
|
+
```ruby
|
|
81
|
+
require 'sinlog'
|
|
82
|
+
|
|
83
|
+
# update the Sinlog logger level
|
|
84
|
+
Sinlog.logger(level: "debug")
|
|
85
|
+
# OR: Sinlog::Logger.logger("debug")
|
|
86
|
+
|
|
87
|
+
Sinlog.dbg 'debug'
|
|
88
|
+
Sinlog.info 'information'
|
|
89
|
+
Sinlog.warn 'warning'
|
|
90
|
+
Sinlog.err 'error'
|
|
91
|
+
Sinlog.fatal 'fatal'
|
|
92
|
+
Sinlog.unk 'unknown'
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
OR:
|
|
96
|
+
|
|
97
|
+
```sh
|
|
98
|
+
# POSIX-sh
|
|
99
|
+
|
|
100
|
+
# Set an environment variable for a custom log level
|
|
101
|
+
export YOUR_CUSTOM_LOG=debug
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
```ruby
|
|
105
|
+
# RUBY
|
|
106
|
+
|
|
107
|
+
require 'sinlog'
|
|
108
|
+
|
|
109
|
+
log = Sinlog.logger(env_name: "YOUR_CUSTOM_LOG")
|
|
110
|
+
log.debug "This is a debug message"
|
|
111
|
+
log.info 'information'
|
|
112
|
+
log.warn 'warning'
|
|
113
|
+
log.error 'error'
|
|
114
|
+
log.fatal 'fatal'
|
|
115
|
+
log.unknown 'unknown'
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
#### OOP style
|
|
119
|
+
|
|
120
|
+
```ruby
|
|
121
|
+
require 'sinlog'
|
|
122
|
+
|
|
123
|
+
using Sinlog::Refin
|
|
124
|
+
# OR: include Sinlog::Mixin
|
|
125
|
+
|
|
126
|
+
'debug'.log_dbg
|
|
127
|
+
'information'.log_info
|
|
128
|
+
'warning'.log_warn
|
|
129
|
+
'error'.log_err
|
|
130
|
+
'fatal'.log_fatal
|
|
131
|
+
'unknown'.log_unk
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
#### FP Style
|
|
135
|
+
|
|
136
|
+
```ruby
|
|
137
|
+
require 'sinlog'
|
|
138
|
+
|
|
139
|
+
# update the Sinlog logger level
|
|
140
|
+
{level: "dbg"}.then { Sinlog.logger **_1 }
|
|
141
|
+
|
|
142
|
+
Log = Sinlog::Proc
|
|
62
143
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
144
|
+
'debug'.tap &Log.dbg
|
|
145
|
+
# OR: Log.dbg['debug']
|
|
146
|
+
# OR: Log.dbg.call 'debug'
|
|
147
|
+
# OR: Log.dbg.('debug')
|
|
148
|
+
|
|
149
|
+
class Object; def ▷(f) = f.call(self) end
|
|
150
|
+
|
|
151
|
+
true.▷(Log.dbg >> Log.info >> Log.warn >> Log.err >> Log.fatal >> Log.unk)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Monkey Patching
|
|
155
|
+
|
|
156
|
+
### Comparison Table
|
|
157
|
+
|
|
158
|
+
| Module | Type | Activation | Method Naming |
|
|
159
|
+
| ---------- | ---------- | ---------- | -------------------------------------------------------- |
|
|
160
|
+
| Mixin | Mixin | include | log_dbg, log_info, log_warn, log_err, log_fatal, log_unk |
|
|
161
|
+
| Refin | Refinement | using | log_dbg, log_info, log_warn, log_err, log_fatal, log_unk |
|
|
162
|
+
| ShortMixin | Mixin | include | dbg, info, warn, err, fatal, unk |
|
|
163
|
+
| ShortRefin | Refinement | using | dbg, info, warn, err, fatal, unk |
|
|
68
164
|
|
|
69
165
|
### Method List
|
|
70
166
|
|
|
71
|
-
####
|
|
167
|
+
#### Mixin & Refin
|
|
72
168
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
169
|
+
- `log_dbg` – DEBUG
|
|
170
|
+
- `log_info` – INFO
|
|
171
|
+
- `log_warn` – WARN
|
|
172
|
+
- `log_err` – ERROR
|
|
173
|
+
- `log_fatal` – FATAL
|
|
174
|
+
- `log_unk` – UNKNOWN
|
|
79
175
|
|
|
80
|
-
####
|
|
176
|
+
#### ShortMixin & ShortRefin
|
|
81
177
|
|
|
82
|
-
`LogShortExt` works the same way as `LogExt`, except for method naming:
|
|
83
178
|
|
|
84
|
-
|
|
85
|
-
-
|
|
179
|
+
- **ShortRefin** is similar to **Refin**
|
|
180
|
+
- Apart from the difference in method naming, their internal implementations are identical.
|
|
181
|
+
- Methods in **Refin** have the `log_` prefix
|
|
182
|
+
- **ShortRefin** does not
|
|
183
|
+
|
|
184
|
+
- **ShortMixin** is similar to **Mixin**
|
|
185
|
+
- The only difference is in naming
|
|
186
|
+
- Methods in **Mixin** have the `log_` prefix
|
|
187
|
+
- **ShortMixin** does not
|
|
86
188
|
|
|
87
189
|
---
|
|
88
190
|
|
|
@@ -93,51 +195,55 @@ gem install sinlog
|
|
|
93
195
|
- `fatal` – FATAL
|
|
94
196
|
- `unk` – UNKNOWN
|
|
95
197
|
|
|
96
|
-
> ⚠️
|
|
97
|
-
>
|
|
198
|
+
> ⚠️ Since **ShortMixin** and **ShortRefin** define a `warn` method, they will override the default `warn`.
|
|
199
|
+
> For Ruby code that uses `warn "msg"` (which outputs to **stderr** rather than using a log format), you may need to manually change it to `Kernel.warn "msg"`.
|
|
98
200
|
>
|
|
99
|
-
> If this
|
|
201
|
+
> If this bothers you, then use `using Sinlog::Refin` instead of `using Sinlog::ShortRefin`.
|
|
100
202
|
|
|
101
203
|
### Examples
|
|
102
204
|
|
|
103
|
-
####
|
|
205
|
+
#### Refinement
|
|
104
206
|
|
|
105
207
|
```ruby
|
|
106
208
|
require 'sinlog'
|
|
209
|
+
using Sinlog::Refin
|
|
210
|
+
{ dir: "/path/to/xx" }.log_info
|
|
211
|
+
```
|
|
107
212
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
213
|
+
```ruby
|
|
214
|
+
require 'sinlog'
|
|
215
|
+
using Sinlog::ShortRefin
|
|
216
|
+
{ dir: "/path/to/xx" }.info
|
|
111
217
|
```
|
|
112
218
|
|
|
113
219
|
#### Mixin
|
|
114
220
|
|
|
115
221
|
```ruby
|
|
116
222
|
require 'sinlog'
|
|
117
|
-
include Sinlog::
|
|
223
|
+
include Sinlog::Mixin
|
|
118
224
|
"Hello".log_info
|
|
119
225
|
```
|
|
120
226
|
|
|
121
|
-
#### Refinement
|
|
122
|
-
|
|
123
227
|
```ruby
|
|
124
228
|
require 'sinlog'
|
|
125
|
-
|
|
126
|
-
|
|
229
|
+
include Sinlog::ShortMixin
|
|
230
|
+
"Hello".info
|
|
127
231
|
```
|
|
128
232
|
|
|
129
233
|
## Learn Sinlog API by Example
|
|
130
234
|
|
|
131
|
-
<img src="../assets/img/preview.
|
|
235
|
+
<img src="../misc/assets/img/preview.webp" alt="preview">
|
|
132
236
|
|
|
133
237
|
```ruby
|
|
134
238
|
require 'sinlog'
|
|
135
239
|
|
|
136
|
-
|
|
137
|
-
|
|
240
|
+
module A
|
|
241
|
+
module_function
|
|
242
|
+
using Sinlog::ShortRefin
|
|
138
243
|
|
|
139
|
-
def
|
|
140
|
-
'
|
|
244
|
+
def log
|
|
245
|
+
['Hey hey hey, could you see this debug message?',
|
|
246
|
+
'You might find it a bit verbose, hahaha!'].dbg
|
|
141
247
|
'Just some info.'.info
|
|
142
248
|
|
|
143
249
|
'FBI, open the door!'.warn
|
|
@@ -147,42 +253,14 @@ class A
|
|
|
147
253
|
end
|
|
148
254
|
end
|
|
149
255
|
|
|
150
|
-
Sinlog::LV[:info].then do
|
|
151
|
-
Sinlog.logger_with_level it
|
|
152
|
-
end
|
|
153
|
-
|
|
154
256
|
A.log
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
### Classic Method Call
|
|
158
257
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
log = Sinlog.logger
|
|
165
|
-
|
|
166
|
-
log.debug 'debug'
|
|
167
|
-
log.info 'information'
|
|
168
|
-
log.warn 'warning'
|
|
169
|
-
log.error 'error'
|
|
170
|
-
log.fatal 'fatal'
|
|
171
|
-
log.unknown 'unknown'
|
|
258
|
+
# update the log level to error
|
|
259
|
+
Sinlog.logger(level: 'err')
|
|
260
|
+
Kernel.warn 'Logger.level => error'
|
|
261
|
+
A.log
|
|
172
262
|
```
|
|
173
263
|
|
|
174
|
-
> The data type of `Sinlog.logger` is Ruby’s standard library `Logger`.
|
|
175
|
-
|
|
176
|
-
In addition to the common methods listed above, you can also use other methods such as `.reopen`.
|
|
177
|
-
For details, see <https://docs.ruby-lang.org/en/3.4/Logger.html>
|
|
178
|
-
|
|
179
|
-
- `debug`
|
|
180
|
-
- `info`
|
|
181
|
-
- `warn`
|
|
182
|
-
- `error`
|
|
183
|
-
- `fatal`
|
|
184
|
-
- `unknown`
|
|
185
|
-
|
|
186
264
|
## Advanced
|
|
187
265
|
|
|
188
266
|
After trying it out ourselves, we have a basic understanding of `sinlog`.
|
|
@@ -200,7 +278,8 @@ require 'sinlog'
|
|
|
200
278
|
class EpubProcessor
|
|
201
279
|
def initialize(epub_file, logger = nil)
|
|
202
280
|
@epub = epub_file
|
|
203
|
-
|
|
281
|
+
logger ||= Sinlog::logger(env_name: "XX_LOG")
|
|
282
|
+
@logger = logger
|
|
204
283
|
@logger.debug "EpubProcessor class initialization completed."
|
|
205
284
|
end
|
|
206
285
|
end
|
|
@@ -223,16 +302,18 @@ Log levels from low to high are:
|
|
|
223
302
|
- fatal = 4
|
|
224
303
|
- unknown = 5
|
|
225
304
|
|
|
305
|
+
> Interestingly, the log levels in Ruby’s standard library `Logger` are the opposite of Rust’s [log::Level](https://docs.rs/log/latest/log/enum.Level.html).
|
|
306
|
+
|
|
226
307
|
```ruby
|
|
227
308
|
p Sinlog::LV
|
|
228
309
|
# => {debug: 0, info: 1, warn: 2, error: 3, fatal: 4, unknown: 5}
|
|
229
310
|
|
|
230
311
|
# Change the log level to warn
|
|
231
|
-
log = Sinlog.
|
|
312
|
+
log = Sinlog.logger(level: 'warn')
|
|
232
313
|
# OR:
|
|
233
|
-
# log = Sinlog.logger
|
|
314
|
+
# log = Sinlog.logger(level: Sinlog::LV[:warn])
|
|
234
315
|
# OR:
|
|
235
|
-
# log = Sinlog.
|
|
316
|
+
# log = Sinlog.logger.tap { it.level = 2 }
|
|
236
317
|
|
|
237
318
|
log.error "This message will be displayed! Lower level WARN (2) will display higher level ERROR (3) logs."
|
|
238
319
|
log.info "This message will not be displayed! Higher level WARN (2) will not display lower level INFO (1) logs."
|
|
@@ -249,13 +330,11 @@ To allow them to configure `log.level` directly, we can use environment variable
|
|
|
249
330
|
|
|
250
331
|
> Using environment variables is simple and efficient.
|
|
251
332
|
|
|
252
|
-
By default, Sinlog will attempt to read the value of the environment variable `RUBY_LOG`.
|
|
253
|
-
|
|
254
|
-
It essentially calls the function `set_level_from_env!(env_name = 'RUBY_LOG')`.
|
|
333
|
+
By default, `Sinlog::Logger` will attempt to read the value of the environment variable `RUBY_LOG`.
|
|
255
334
|
|
|
256
335
|
- If the environment variable does not exist, it uses `debug(0)`.
|
|
257
|
-
- If the environment variable exists but is empty, it uses `
|
|
258
|
-
- If the environment variable's value is invalid, it uses `
|
|
336
|
+
- If the environment variable exists but is empty, it uses `error(3)`.
|
|
337
|
+
- If the environment variable's value is invalid, it uses `error(3)`.
|
|
259
338
|
|
|
260
339
|
We can set the environment variable using POSIX-sh, and then the logger will automatically set the log level to `warn` (the value of `RUBY_LOG`) during initialization.
|
|
261
340
|
|
|
@@ -275,7 +354,7 @@ export XX_CLI_LOG=info
|
|
|
275
354
|
Ruby:
|
|
276
355
|
|
|
277
356
|
```ruby
|
|
278
|
-
logger = Sinlog.
|
|
357
|
+
logger = Sinlog.logger(env_name:"XX_CLI_LOG")
|
|
279
358
|
|
|
280
359
|
logger.debug "This message will not be displayed because the current log level is INFO(1)."
|
|
281
360
|
logger.info "Hello!"
|
|
@@ -285,7 +364,9 @@ logger.info "Hello!"
|
|
|
285
364
|
|
|
286
365
|
By default, Sinlog outputs to `STDERR`.
|
|
287
366
|
|
|
288
|
-
|
|
367
|
+
> The data type of `Sinlog.logger` is `::Logger` (from Ruby's standard library).
|
|
368
|
+
|
|
369
|
+
If you need to customize the log output path, you can call the `::Logger`'s `reopen` method.
|
|
289
370
|
|
|
290
371
|
```ruby
|
|
291
372
|
# Logs will be output to the file a.log
|
|
@@ -305,13 +386,15 @@ log.error "What happened! QuQ"
|
|
|
305
386
|
|
|
306
387
|
### Other Logger Methods
|
|
307
388
|
|
|
308
|
-
In addition to `.reopen` and `.level`, we can also call other methods from Ruby's standard library logger on `Sinlog.
|
|
389
|
+
In addition to `.reopen` and `.level`, we can also call other methods from Ruby's standard library logger on `Sinlog.logger`.
|
|
390
|
+
|
|
391
|
+
For details, see <https://docs.ruby-lang.org/en/3.4/Logger.html>
|
|
309
392
|
|
|
310
393
|
### Notes
|
|
311
394
|
|
|
312
|
-
Sinlog uses the Singleton pattern, meaning the entire program will share the same instance (logger).
|
|
395
|
+
`Sinlog::Logger` uses the Singleton pattern, meaning the entire program will share the same instance (logger).
|
|
313
396
|
|
|
314
|
-
Modifying Sinlog in class A of the same program will affect Sinlog in class B.
|
|
397
|
+
Modifying `Sinlog.logger` (a.k.a. `Sinlog::Logger.instance.logger`) in class A of the same program will affect `Sinlog::Logger` in class B.
|
|
315
398
|
|
|
316
399
|
## Side Note
|
|
317
400
|
|
|
@@ -320,21 +403,32 @@ The API might not fully adhere to idiomatic Ruby usage, so I appreciate your und
|
|
|
320
403
|
|
|
321
404
|
## Changelog
|
|
322
405
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
- `Sinlog.instance.logger` can be simplified => `Sinlog.logger`
|
|
406
|
+
[Earlier versions](./Changelog.md)
|
|
326
407
|
|
|
327
|
-
|
|
328
|
-
- e.g., `logger = Sinlog.logger_with_level(Sinlog::LV[:warn])`
|
|
329
|
-
- old: `Sinlog.instance.logger.tap { it.level = Sinlog::LV[:warn] }`
|
|
408
|
+
### v0.0.7 (2025-12-03)
|
|
330
409
|
|
|
331
|
-
- add `
|
|
332
|
-
|
|
333
|
-
-
|
|
410
|
+
- add `Sinlog::Proc` module
|
|
411
|
+
- add `lib/sinlog/08_module_short_ext.rb`:
|
|
412
|
+
- `Sinlog.dbg`
|
|
413
|
+
- `Sinlog.info`
|
|
414
|
+
- `Sinlog.warn`
|
|
415
|
+
- `Sinlog.err`
|
|
416
|
+
- `Sinlog.fatal`
|
|
417
|
+
- `Sinlog.unk`
|
|
418
|
+
- update `Sinlog::Logger.logger`
|
|
419
|
+
- Previous: `def self.logger`
|
|
420
|
+
- Current: `def self.logger(level = nil, env_name = nil)`
|
|
334
421
|
|
|
335
422
|
Breaking changes:
|
|
336
|
-
|
|
337
|
-
-
|
|
423
|
+
|
|
424
|
+
- `Sinlog.to_log_level` => `Sinlog.as_log_level`
|
|
425
|
+
- rename `lib/sinlog/*.rb`
|
|
426
|
+
- consts => 01_consts
|
|
427
|
+
- logger => 02_logger
|
|
428
|
+
- module_fn => 03_module_fn
|
|
429
|
+
- log_ext => 04_log_ext
|
|
430
|
+
- short_ext => 05_short_ext
|
|
431
|
+
- loggable => 06_loggable
|
|
338
432
|
|
|
339
433
|
## License
|
|
340
434
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'logger'
|
|
4
|
+
|
|
5
|
+
module Sinlog
|
|
6
|
+
StdLogger = ::Logger
|
|
7
|
+
|
|
8
|
+
# Define colors for different log levels
|
|
9
|
+
COLORS = {
|
|
10
|
+
debug: "\e[34m", # Blue
|
|
11
|
+
info: "\e[36m", # Cyan
|
|
12
|
+
warn: "\e[33m", # Yellow
|
|
13
|
+
error: "\e[31m", # Red
|
|
14
|
+
fatal: "\e[35m", # Magenta
|
|
15
|
+
unknown: "\e[0m", # Reset
|
|
16
|
+
}.freeze
|
|
17
|
+
|
|
18
|
+
# log levels
|
|
19
|
+
LV = {
|
|
20
|
+
debug: StdLogger::DEBUG,
|
|
21
|
+
info: StdLogger::INFO,
|
|
22
|
+
warn: StdLogger::WARN,
|
|
23
|
+
error: StdLogger::ERROR,
|
|
24
|
+
fatal: StdLogger::FATAL,
|
|
25
|
+
unknown: StdLogger::UNKNOWN,
|
|
26
|
+
}.freeze
|
|
27
|
+
end
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Sinlog # rubocop:disable Style/ClassAndModuleChildren
|
|
4
|
+
# Logger Singleton Class
|
|
5
|
+
class Logger
|
|
6
|
+
require 'singleton'
|
|
7
|
+
|
|
8
|
+
include Singleton
|
|
9
|
+
attr_reader :logger
|
|
10
|
+
|
|
11
|
+
# Since this is a Singleton class, you should use {.instance} instead of `.new`.
|
|
12
|
+
#
|
|
13
|
+
# @return [self] Sinlog::Logger
|
|
14
|
+
#
|
|
15
|
+
# @example
|
|
16
|
+
#
|
|
17
|
+
# instance = Sinlog::Logger.instance
|
|
18
|
+
# instance.logger.info "Hello"
|
|
19
|
+
def initialize
|
|
20
|
+
@logger = StdLogger.new($stderr)
|
|
21
|
+
set_level_from_env!
|
|
22
|
+
@logger.formatter = Kernel.proc do |severity, datetime, progname, msg|
|
|
23
|
+
color = COLORS[severity.downcase.to_sym]
|
|
24
|
+
reset = COLORS[:unknown]
|
|
25
|
+
formatted_datetime = datetime.strftime('%H:%M:%S.%L')
|
|
26
|
+
prog = format_prog_name(progname)
|
|
27
|
+
"[#{color}#{severity}#{reset}] #{formatted_datetime} #{prog}#{msg}\n"
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Configures and returns the {StdLogger}.
|
|
32
|
+
#
|
|
33
|
+
# @note Similar to {Sinlog.logger}, but uses different parameter types.
|
|
34
|
+
#
|
|
35
|
+
# - {Sinlog.logger}: uses keyword arguments, e.g., (level: "info", env_name: "RUBY_LOG")
|
|
36
|
+
# - This function: uses positional arguments, e.g., ("warn", "CUSTOM_LOG")
|
|
37
|
+
#
|
|
38
|
+
# @param level [Integer, String, Symbol, nil] Log Level.
|
|
39
|
+
# @param env_name [#to_s] Name of the environment variable.
|
|
40
|
+
#
|
|
41
|
+
# @return [StdLogger]
|
|
42
|
+
#
|
|
43
|
+
# @see Sinlog.logger
|
|
44
|
+
#
|
|
45
|
+
# ## Example
|
|
46
|
+
#
|
|
47
|
+
# log = Sinlog::Logger.logger("debug")
|
|
48
|
+
# log.info "Information"
|
|
49
|
+
# log.debug "This is a debug message"
|
|
50
|
+
#
|
|
51
|
+
# The log output format will be similar to:
|
|
52
|
+
#
|
|
53
|
+
# <ul>
|
|
54
|
+
# <li><p><span style="color:darkcyan;">[INFO]</span> 21:29:22.004 Information</p></li>
|
|
55
|
+
# <li><p><span style="color:blue;">[DEBUG]</span> 21:29:22.005 This is a debug message</p></li>
|
|
56
|
+
# </ul>
|
|
57
|
+
#
|
|
58
|
+
# > Where "INFO" is highlighted in cyan and "DEBUG" is highlighted in blue.
|
|
59
|
+
#
|
|
60
|
+
# The default log level is set based on the `RUBY_LOG` environment variable.
|
|
61
|
+
#
|
|
62
|
+
# If this variable is not set, the default level is `DEBUG`.
|
|
63
|
+
def self.logger(level = nil, env_name = nil)
|
|
64
|
+
Sinlog.logger(level:, env_name:)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Sets the `@logger.level` (**log level**) based on the value of an environment variable.
|
|
68
|
+
#
|
|
69
|
+
# If `env_name` is not specified, it reads the value of the `RUBY_LOG` environment variable.
|
|
70
|
+
#
|
|
71
|
+
# - If the value exists, it is converted to lowercase, then to a symbol, and looked up in the LV hash;
|
|
72
|
+
# - If it does not exist, the default level is `DEBUG(0)`;
|
|
73
|
+
# - If the lookup result is invalid, the level is set to `ERROR(3)`;
|
|
74
|
+
# - If the environment variable value is empty, the lookup result will be invalid,
|
|
75
|
+
# and the level will be set to `ERROR(3)`.
|
|
76
|
+
#
|
|
77
|
+
# @example
|
|
78
|
+
#
|
|
79
|
+
# ENV["XX_LOG"] = "info" # or setenv in posix-sh: export XX_LOG=info
|
|
80
|
+
#
|
|
81
|
+
# level = Sinlog.instance.set_level_from_env!("XX_LOG")
|
|
82
|
+
# level == Sinlog::LV[:info] # => true
|
|
83
|
+
#
|
|
84
|
+
# log = Sinlog.logger
|
|
85
|
+
# log.debug "This message will not be displayed because the current log level is info"
|
|
86
|
+
# log.info "Hello!"
|
|
87
|
+
#
|
|
88
|
+
# @return [Integer] `@logger.level`
|
|
89
|
+
# @param env_name [#to_s] Name of the environment variable.
|
|
90
|
+
def set_level_from_env!(env_name = 'RUBY_LOG')
|
|
91
|
+
env_str = ENV[env_name.to_s]&.downcase || 'debug'
|
|
92
|
+
|
|
93
|
+
Sinlog
|
|
94
|
+
.as_log_level(env_str)
|
|
95
|
+
.tap { @logger.level = _1 }
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
private
|
|
99
|
+
|
|
100
|
+
def format_prog_name(progname)
|
|
101
|
+
return '' if progname.to_s.empty?
|
|
102
|
+
|
|
103
|
+
green = "\e[32m"
|
|
104
|
+
reset = "\e[0m"
|
|
105
|
+
space = ' '
|
|
106
|
+
"<#{green}#{progname}#{reset}>#{space}"
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|