tty-logger 0.0.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fc0a525df2a56832f927f224ed3d9d25b0e200e89745b743af4f35b1013f10ed
4
- data.tar.gz: 27598db1b9976f9e12a76a67225cc52c489a5e963008a50309bd70649983ff1e
3
+ metadata.gz: '0594c7ef471a07571e5621e8535469fcb50edeeb10d7ffa58b194ef8fe4f8350'
4
+ data.tar.gz: 42a3b6c20b756754723c42c5b0ce85490b403978ffe566cb267dc6f18811f1c9
5
5
  SHA512:
6
- metadata.gz: fa29e2ff2aaccc1ea89e8ef907cbbf740e9001066f0c4926c8383df31610813e5b84adfd1d9e102cfd68a9ea53373c42a4f5d2ac50394f7f839c2787b68b51a8
7
- data.tar.gz: 7713b63753afad9b07eabdae55526a0130c5d36334bfd10c15f2284b412cce26f60fe1ee74531a3a74b2c18a4fca3396372112f8f3cbaaa459ebf3a1b0a0d26a
6
+ metadata.gz: 5fb46bcc0515d4f4762dc9c601b65131a493153ed85e48e83ac64ae70b0b2060d0780d867560bfc8e50ed4c461ea62e1aeba5b4e1b6b55572656196e9958840b
7
+ data.tar.gz: 235421d689aa362a858a813fd369cef67673b0c6b13ccf50f6733a603746c3dfc00bde16fdd73fb1dd4358e9457c70d61c033c60d409e3f721eb0b34cc5c40bd
@@ -1,7 +1,57 @@
1
1
  # Change log
2
2
 
3
- ## [v0.1.0] - 2019-07-x
3
+ ## [v0.5.0] - 2020-09-27
4
+
5
+ ### Added
6
+ * Add :message_format option to customize how messages are displayed in the console
7
+ by Josh Greenwood (@JoshTGreenwood)
8
+
9
+ ### Fixed
10
+ * Fix to select event name from valid log types or current level
11
+ by Ryan Schlesinger (@ryansch)
12
+ * Fix duplicate filters attribute definition in TTY::Logger::Config
13
+
14
+ ## [v0.4.0] - 2020-07-29
15
+
16
+ ### Added
17
+ * Allow editing logger configuration at runtime ([#10](https://github.com/piotrmurach/tty-logger/pull/10))
18
+ * Support for the `<<` streaming operator ([#9](https://github.com/piotrmurach/tty-logger/pull/9)))
19
+
20
+ ### Changed
21
+ * Change gemspec to update pastel version and restrict only to minor version
22
+
23
+ ### Fixed
24
+ * Fix to filter sensitive information from exceptions
25
+
26
+ ## [v0.3.0] - 2020-01-01
27
+
28
+ ### Added
29
+ * Add ability to filter sensitive information out of structured data
30
+
31
+ ### Changed
32
+ * Remove the test and task files from the gemspec
33
+
34
+ ### Fixed
35
+ * Fix console handler highlighting of nested hash keys
36
+
37
+ ## [v0.2.0] - 2019-09-30
38
+
39
+ ### Added
40
+ * Add ability to add structured data inside logging block
41
+ * Add ability to filter sensitive data
42
+ * Add ability to define custom log types
43
+ * Add ability to temporarily log at different level
44
+ * Add performance tests
45
+
46
+ ### Changed
47
+ * Change to dynamically define log types
48
+
49
+ ## [v0.1.0] - 2019-07-21
4
50
 
5
51
  * Initial implementation and release
6
52
 
53
+ [v0.5.0]: https://github.com/piotrmurach/tty-logger/compare/v0.4.0..v0.5.0
54
+ [v0.4.0]: https://github.com/piotrmurach/tty-logger/compare/v0.3.0..v0.4.0
55
+ [v0.3.0]: https://github.com/piotrmurach/tty-logger/compare/v0.2.0..v0.3.0
56
+ [v0.2.0]: https://github.com/piotrmurach/tty-logger/compare/v0.1.0..v0.2.0
7
57
  [v0.1.0]: https://github.com/piotrmurach/tty-logger/compare/v0.1.0
data/README.md CHANGED
@@ -1,17 +1,48 @@
1
1
  <div align="center">
2
- <a href="https://piotrmurach.github.io/tty" target="_blank"><img width="130" src="https://cdn.rawgit.com/piotrmurach/tty/master/images/tty.png" alt="tty logo" /></a>
2
+ <a href="https://ttytoolkit.org" target="_blank"><img width="130" src="https://github.com/piotrmurach/tty/raw/master/images/tty.png" alt="tty logo" /></a>
3
3
  </div>
4
4
 
5
- # TTY::Logger
5
+ # TTY::Logger [![Gitter](https://badges.gitter.im/Join%20Chat.svg)][gitter]
6
+
7
+ [![Gem Version](https://badge.fury.io/rb/tty-logger.svg)][gem]
8
+ [![Build Status](https://secure.travis-ci.org/piotrmurach/tty-logger.svg?branch=master)][travis]
9
+ [![Build status](https://ci.appveyor.com/api/projects/status/vtrkdk0naknnxoog?svg=true)][appveyor]
10
+ [![Code Climate](https://codeclimate.com/github/piotrmurach/tty-logger/badges/gpa.svg)][codeclimate]
11
+ [![Coverage Status](https://coveralls.io/repos/github/piotrmurach/tty-logger/badge.svg)][coverage]
12
+ [![Inline docs](http://inch-ci.org/github/piotrmurach/tty-logger.svg?branch=master)][inchpages]
13
+
14
+ [gitter]: https://gitter.im/piotrmurach/tty
15
+ [gem]: http://badge.fury.io/rb/tty-logger
16
+ [travis]: http://travis-ci.org/piotrmurach/tty-logger
17
+ [appveyor]: https://ci.appveyor.com/project/piotrmurach/tty-logger
18
+ [codeclimate]: https://codeclimate.com/github/piotrmurach/tty-logger
19
+ [coverage]: https://coveralls.io/github/piotrmurach/tty-logger
20
+ [inchpages]: http://inch-ci.org/github/piotrmurach/tty-logger
6
21
 
7
22
  > A readable, structured and beautiful logging for the terminal
8
23
 
24
+ **TTY::Logger** provides independent logging component for [TTY toolkit](https://github.com/piotrmurach/tty).
25
+
26
+ ![](assets/tty-logger-levels.png)
27
+
28
+ ## Features
29
+
30
+ * Intuitive console output for an increased readability
31
+ * Ability to stream data to any IO object
32
+ * Supports structured data logging
33
+ * Filters sensitive data
34
+ * Allows to define custom log types
35
+ * Formats and truncates messages to avoid clogging logging output
36
+ * Customizable styling of labels and symbols for console output
37
+ * Includes metadata information: time, location, scope
38
+ * Handles multiple logging outputs
39
+
9
40
  ## Installation
10
41
 
11
42
  Add this line to your application's Gemfile:
12
43
 
13
44
  ```ruby
14
- gem 'tty-logger'
45
+ gem "tty-logger"
15
46
  ```
16
47
 
17
48
  And then execute:
@@ -22,12 +53,746 @@ Or install it yourself as:
22
53
 
23
54
  $ gem install tty-logger
24
55
 
25
- ## Usage
56
+
57
+ ## Contents
58
+
59
+ * [1. Usage](#1-usage)
60
+ * [2. Synopsis](#2-synopsis)
61
+ * [2.1 Logging](#21-logging)
62
+ * [2.1.1 Exceptions](#211-exceptions)
63
+ * [2.1.2 Types](#212-types)
64
+ * [2.2 Levels](#22-levels)
65
+ * [2.2.1 Scoped Level](#22-scoped-level)
66
+ * [2.3 Structured Data](#23-structured-data)
67
+ * [2.4 Configuration](#24-configuration)
68
+ * [2.4.1 Metadata](#241-metadata)
69
+ * [2.4.2 Filters](#242-filters)
70
+ * [2.5 Cloning](#25-cloning)
71
+ * [2.6 Handlers](#26-handlers)
72
+ * [2.6.1 Console Handler](#261-console-handler)
73
+ * [2.6.2 Stream Handler](#262-stream-handler)
74
+ * [2.6.3 Custom Handler](#263-custom-handler)
75
+ * [2.6.4 Multiple Handlers](#264-multiple-handlers)
76
+ * [2.7 Formatters](#27-formatters)
77
+ * [2.8 Output streams](#28-output-streams)
78
+ * [3. Community Extensions](#3-community-extensions)
79
+ * [3.1 Sentry Handler](#31-sentry-handler)
80
+
81
+ ## 1. Usage
82
+
83
+ Create logger:
84
+
85
+ ```ruby
86
+ logger = TTY::Logger.new
87
+ ```
88
+
89
+ And log information using any of the logger [built-in types](#212-types):
90
+
91
+ ```ruby
92
+ logger.info "Deployed successfully"
93
+ logger.info "Deployed", "successfully"
94
+ logger.info { "Dynamically generated info" }
95
+ ```
96
+
97
+ Include structured data:
98
+
99
+ ```ruby
100
+ logger.success "Deployed successfully", myapp: "myapp", env: "prod"
101
+ # =>
102
+ # ✔ success Deployed successfully app=myapp env=prod
103
+ ```
104
+
105
+ Add [metadata](#241-metadata) information:
106
+
107
+ ```ruby
108
+ logger = TTY::Logger.new do |config|
109
+ config.metadata = [:date, :time]
110
+ end
111
+ logger.info "Deployed successfully", myapp: "myapp", env: "prod"
112
+ # =>
113
+ # [2019-07-17] [23:21:55.287] › ℹ info Info about the deploy app=myapp env=prod
114
+ ```
115
+
116
+ Or change structured data [formatting](#27-formatters) display to `JSON`:
117
+
118
+ ```ruby
119
+ logger = TTY::Logger.new do |config|
120
+ config.formatter = :json
121
+ end
122
+ logger.info "Deployed successfully"
123
+ # =>
124
+ # [2019-07-17] [23:21:55.287] › ℹ info Info about the deploy {"app":"myapp","env":"prod"}
125
+ ```
126
+
127
+ ## 2. Synopsis
128
+
129
+ ## 2.1 Logging
130
+
131
+ There are many logger types to choose from:
132
+
133
+ * `debug` - logs message at `:debug` level
134
+ * `info` - logs message at `:info` level
135
+ * `success` - logs message at `:info` level
136
+ * `wait` - logs message at `:info` level
137
+ * `warn` - logs message at `:warn` level
138
+ * `error` - logs message at `:error` level
139
+ * `fatal` - logs message at `:fatal` level
140
+
141
+ To log a message, simply choose one of the above types and pass in the actual message. For example, to log successfully deployment at info level do:
142
+
143
+ ```ruby
144
+ logger.success "Deployed successfully"
145
+ # =>
146
+ # ✔ success Deployed successfully
147
+ ```
148
+
149
+ Or pass in multiple messages:
150
+
151
+ ```ruby
152
+ logger.success "Deployed", "successfully"
153
+ # =>
154
+ # ✔ success Deployed successfully
155
+ ```
156
+
157
+ You can delay message evaluation by passing it inside a block:
158
+
159
+ ```ruby
160
+ logger.success { "Dynamically generated info" }
161
+ # =>
162
+ # ✔ success Dynamically generated info
163
+ ```
164
+
165
+ Similar to regular logging, you cal split your message into chunks inside a block:
166
+
167
+ ```ruby
168
+ logger.success { ["Dynamically", "generated", "info"] }
169
+ # =>
170
+ # ✔ success Dynamically generated info
171
+ ```
172
+
173
+ The above comes handy when paired with [structured data](#23-structured-data).
174
+
175
+ #### 2.1.1 Exceptions
176
+
177
+ You can also report on exceptions.
178
+
179
+ For example, let's say you caught an exception about incorrect data format and use `fatal` level to log it:
180
+
181
+ ```ruby
182
+ begin
183
+ raise ArgumentError, "Wrong data"
184
+ rescue => ex
185
+ logger.fatal("Error:", ex)
186
+ end
187
+ ```
188
+
189
+ This will result in a message followed by a full backtrace:
190
+
191
+ ```ruby
192
+ # =>
193
+ # ! fatal Error: Wrong data
194
+ # tty-logger/spec/unit/exception_spec.rb:12:in `block (2 levels) in <top (required)>'
195
+ # rspec-core-3.8.2/lib/rspec/core/example.rb:257:in `instance_exec'
196
+ # rspec-core-3.8.2/lib/rspec/core/example.rb:257:in `block in run'
197
+ ```
198
+
199
+ #### 2.1.2 Types
200
+
201
+ You can define custom log types via the `types` configuration option:
202
+
203
+ For example, if you want to add `thanks` and `done` log types, you need to provide their names along with logging levels. You can further customise the `:console` output with your desired styling:
204
+
205
+ ```ruby
206
+ logger = TTY::Logger.new do |config|
207
+ config.types = {
208
+ thanks: {level: :info},
209
+ done: {level: :info}
210
+ }
211
+ config.handlers = [
212
+ [:console, {
213
+ styles: {
214
+ thanks: {
215
+ symbol: "❤️ ",
216
+ label: "thanks",
217
+ color: :magenta,
218
+ levelpad: 0
219
+ },
220
+ done: {
221
+ symbol: "!!",
222
+ label: "done",
223
+ color: :green,
224
+ levelpad: 2
225
+ }
226
+ }
227
+ }]
228
+ ]
229
+ end
230
+ ```
231
+
232
+ Once defined, you can call new log types:
233
+
234
+ ```ruby
235
+ logger.thanks("Great work!")
236
+ logger.done("Work done!")
237
+ # =>
238
+ # ❤️ thanks Great work!
239
+ # !! done Work done!
240
+ ```
241
+
242
+ ![](assets/tty-logger-custom-log-types.png)
243
+
244
+ ### 2.2 Levels
245
+
246
+ The supported levels, ordered by precedence, are:
247
+
248
+ * `:debug` - for debug-related messages
249
+ * `:info` - for information of any kind
250
+ * `:warn` - for warnings
251
+ * `:error` - for errors
252
+ * `:fatal` - for fatal conditions
253
+
254
+ So the order is: `:debug` < `:info` < `:warn` < `:error` < `:fatal`
255
+
256
+ For example, `:info` takes precedence over `:debug`. If your log level is set to `:info`, `:info`, `:warn`, `:error` and `:fatal` will be printed to the console. If your log level is set to `:warn`, only `:warn`, `:error` and `:fatal` will be printed.
257
+
258
+ You can set level using the `level` configuration option. The value can be a symbol, a string or level constant. For example, `:info`, `INFO` or `TTY::Logger::INFO_LEVEL` will qualify as valid level value.
259
+
260
+ ```ruby
261
+ TTY::Logger.new do |config|
262
+ config.level = :info # or "INFO" or TTY::Logger::INFO_LEVEL
263
+ end
264
+ ```
265
+
266
+ Or you can specific level for each log events handler.
267
+
268
+ For example, to log messages above `:info` level to a stream and only `:error` level events to the console do:
269
+
270
+ ```ruby
271
+ logger = TTY::Logger.new do |config|
272
+ config.handlers = [
273
+ [:console, level: :error],
274
+ [:stream, level: :info]
275
+ ]
276
+ end
277
+ ```
278
+
279
+ You can also change the [output streams](#28-output-streams) for each handler.
280
+
281
+ #### 2.2.1 Scoped Level
282
+
283
+ You can temporarily change level, raise it or lower it by using the `log_at` call. By default messages are logged at `:info` level, but you can change this for the duration of a block:
26
284
 
27
285
  ```ruby
28
286
  logger = TTY::Logger.new
287
+
288
+ logger.info("not logged")
289
+
290
+ logger.log_at :debug do
291
+ logger.debug("logged")
292
+ end
293
+ # =>
294
+ # • debug logged
295
+ ```
296
+
297
+ Or elevate a level to an error with a constant `ERROR_LEVEL`:
298
+
299
+ ```ruby
300
+ logger.log_at TTY::Logger::ERROR_LEVEL do
301
+ logger.debug("not logged")
302
+ logger.error("logged")
303
+ end
304
+ # =>
305
+ # ⨯ error logged
306
+ ```
307
+
308
+ ### 2.3 Structured data
309
+
310
+ To add global data available for all logger calls:
311
+
312
+ ```ruby
313
+ logger = TTY::Logger.new(fields: {app: "myapp", env: "prod"})
314
+
315
+ logger.info("Deploying...")
316
+ # =>
317
+ # ℹ info Deploying... app=myapp env=prod
318
+ ```
319
+
320
+ To only add data for a single log event:
321
+
322
+ ```ruby
323
+ logger = TTY::Logger.new
324
+ logger.wait "Ready to deploy", app: "myapp", env: "prod"
325
+ # =>
326
+ # … waiting Ready to deploy app=myapp env=prod
327
+ ```
328
+
329
+ You can delay data evaluation until it's evaluated by passing it inside a block:
330
+
331
+ ```ruby
332
+ logger.wait { ["Ready to deploy", {app: "myapp", env: "prod"}] }
333
+ # =>
334
+ # … waiting Ready to deploy app=myapp env=prod
335
+ ```
336
+
337
+ ### 2.4 Configuration
338
+
339
+ All the configuration options can be changed globally via `configure` or per logger instance.
340
+
341
+ * `:filters` - the storage of placeholders to filter sensitive data out from the logs. Defaults to `{}`.
342
+ * `:formatter` - the formatter used to display structured data. Defaults to `:text`. See [Formatters](#27-formatters) for more details.
343
+ * `:handlers` - the handlers used to log messages. Defaults to `[:console]`. See [Handlers](#26-handlers) for more details.
344
+ * `:level` - the logging level. Any message logged below this level will be simply ignored. Each handler may have it's own default level. Defaults to `:info`
345
+ * `:max_bytes` - the maximum message size to be logged in bytes. Defaults to `8192` bytes. The truncated message will have `...` at the end.
346
+ * `:max_depth` - the maximum depth for nested structured data. Defaults to `3`.
347
+ * `:metadata` - the meta info to display before the message, can be `:pid`, `:date`, `:time` or `:file`. Defaults to empty array `[]`, no metadata. Setting this to `:all` will print all the metadata.
348
+ * `:types` - the new custom log types. Defaults to `{}`.
349
+ * `:date_format` - uses `strftime` format to display dates. Defaults to `"%F"`.
350
+ * `:time_format` - uses `strftime` format to display times. Defaults to `"%T.%3N"`.
351
+
352
+ For example, to configure `:max_bytes`, `:level` and `:metadata` for all logger instances do:
353
+
354
+ ```ruby
355
+ TTY::Logger.configure do |config|
356
+ config.max_bytes = 2**10
357
+ config.level = :error
358
+ config.metadata = [:time, :date]
359
+ end
360
+ ```
361
+
362
+ Or if you wish to setup configuration per logger instance use block:
363
+
364
+ ```ruby
365
+ logger = TTY::Logger.new do |config|
366
+ config.max_bytes = 2**20
367
+ config.metadata = [:all]
368
+ end
369
+ ```
370
+
371
+ You can also change the logger's configuration at runtime:
372
+
373
+ ```ruby
374
+ logger.configure do |config|
375
+ config.level = :debug
376
+ end
377
+ ```
378
+
379
+ ### 2.4.1 Metadata
380
+
381
+ The `:metdata` configuration option can include the following symbols:
382
+
383
+ * `:pid` - the log event process identifier
384
+ * `:date` - the log event date
385
+ * `:time` - the log event time
386
+ * `:file` - the file with a line number the log event is triggered from
387
+
388
+ ### 2.4.2 Filters
389
+
390
+ You can filter sensitive data out of log output with `filters` configuration option. The `filters` can be further configured to remove info from log message with `message` or structured data with `data`. Both methods, as a value accept a list of sensitive items to search for.
391
+
392
+ If you want to filter sensitive information from log messages use `message`:
393
+
394
+ ```ruby
395
+ logger = TTY::Logger.new(output: output) do |config|
396
+ config.filters.message = %w[secret password]
397
+ end
398
+ ```
399
+
400
+ Which by default will replace each matching string with `[FILTERED]` placeholder:
401
+
402
+ ```ruby
403
+ logger.info("Super secret info with password")
404
+ # =>
405
+ # ℹ info Super [FILTERED] info with [FILTERED]
406
+ ```
407
+
408
+ You can also replace each data item with a custom placeholder. To do so use a `:mask` keyword with a replacement placeholder.
409
+
410
+ For example, to replace "secret" content with placeholder `"<SECRET>"` do:
411
+
412
+ ```ruby
413
+ logger = TTY::Logger.new do |config|
414
+ config.filters.message = %w[secret]
415
+ config.filters.mask = "<SECRET>"
416
+ end
417
+ ```
418
+
419
+ When logged, it will produce:
420
+
421
+ ```ruby
422
+ logger.info("Super secret info")
423
+ # =>
424
+ # ℹ info Super <SECRET> info
425
+ ```
426
+
427
+ To filter out sensitive information out of structured data use `data` method. By default any value matching a parameter name will be filtered regardless of the level of nesting. If you wish to filter only a specific deeply nested key use a dot notation like `params.card.password` to only filter `{params: {card: {password: "Secret123"}}}`.
428
+
429
+ For example to filter out a `:password` from data do:
430
+
431
+ ```ruby
432
+ logger = TTY::Logger.new do |config|
433
+ config.filters.data = %i[password]
434
+ end
435
+ ```
436
+
437
+ This will filter out any key matching password:
438
+
439
+ ```ruby
440
+ logger.info("Secret info", password: "Secret123", email: "")
441
+ # =>
442
+ # ℹ info Secret info password="[FILTERED]" email="secret@example.com"
29
443
  ```
30
444
 
445
+ But also any nested data item:
446
+
447
+ ```ruby
448
+ logger.info("Secret info", params: {password: "Secret123", email: ""})
449
+ # =>
450
+ # ℹ info Secret info params={password="[FILTERED]" email="secret@example.com"}
451
+ ```
452
+
453
+ You're not limited to using only direct string comparison. You can also match based on regular expressions. For example, to match keys starting with `ba` we can add a following filter:
454
+
455
+ ```ruby
456
+ logger = TTY::Logger.new do |config|
457
+ config.filters.data = [/ba/]
458
+ end
459
+ ```
460
+
461
+ Then appropriate values will be masked:
462
+
463
+ ```ruby
464
+ logger.info("Filtering data", {"foo" => {"bar" => "val", "baz" => "val"}})
465
+ # =>
466
+ # ℹ info Filtering data foo={bar="[FILTERED]" baz="[FILTERED]"}
467
+ ```
468
+
469
+ You can mix and match. To filter keys based on pattern inside a deeply nested hash use dot notation with regular expression. For example, to find keys for the `:foo` parent key that starts with `:b` character, we could do:
470
+
471
+ ```ruby
472
+ logger = TTY::Logger.new do |config|
473
+ config.filters.data = [/^foo\.b/]
474
+ end
475
+ ```
476
+
477
+ Then only keys under the `:foo` key will be filtered:
478
+
479
+ ```ruby
480
+ logger.info("Filtering data", {"foo" => {"bar" => "val"}, "baz" => {"bar" => val"}})
481
+ # =>
482
+ # ℹ info Filtering data foo={bar="[FILTERED]"} baz={bar=val}
483
+ ```
484
+
485
+ ### 2.5 Cloning
486
+
487
+ You can create a copy of a logger with the current configuration using the `copy` method.
488
+
489
+ For example, given the following logger with `:app` and `:env` data:
490
+
491
+ ```ruby
492
+ logger = TTY::Logger.new(fields: {app: "parent", env: "prod"})
493
+ ```
494
+
495
+ We can create a copy with a custom configuration that changes filtered message content and `:app` data:
496
+
497
+ ```ruby
498
+ child_logger = logger.copy(app: "child") do |config|
499
+ config.filters = ["logging"]
500
+ end
501
+ ```
502
+
503
+ ```ruby
504
+ logger.info("Parent logging")
505
+ child_logger.warn("Child logging")
506
+ # =>
507
+ # ℹ info Parent logging app=parent env=prod
508
+ # ⚠ warning Child [FILTERED] app=child env=prod
509
+ ```
510
+
511
+ ### 2.6 Handlers
512
+
513
+ `TTY::Logger` supports many ways to handle log messages.
514
+
515
+ The available handlers by default are:
516
+
517
+ * `:console` - log messages to the console, enabled by default
518
+ * `:null` - discards any log messages
519
+ * `:stream` - log messages to an `IO` stream, a file, a socket or a console.
520
+
521
+ You can also implement your own [custom handler](#263-custom-handler).
522
+
523
+ The handlers can be configured via global or instance configuration with `handlers`. The handler can be a name or a class name:
524
+
525
+ ```ruby
526
+ TTY::Logger.new do |config|
527
+ config.handlers = [:console]
528
+ end
529
+ ```
530
+
531
+ Or using class name:
532
+
533
+ ```ruby
534
+ TTY::Logger.new do |config|
535
+ config.handlers = [TTY::Logger::Handlers::Console]
536
+ end
537
+ ```
538
+
539
+ Handlers can also be added/removed dynamically through `add_handler` or `remove_handler`.
540
+
541
+ ```ruby
542
+ logger = TTY::Logger.new
543
+ logger.add_handler(:console)
544
+ logger.remove_handler(:console)
545
+ ```
546
+
547
+ #### 2.6.1 Console Handler
548
+
549
+ The console handler prints log messages to the console. It supports the following options:
550
+
551
+ * `:styles` - a hash of styling options.
552
+ * `:formatter` - the formatter for log messages. Defaults to `:text`
553
+ * `:output` - the device to log error messages to. Defaults to `$stderr`
554
+ * `:message_format` - uses `sprintf` format to display messages. Defaults to `"%-25s"`.
555
+
556
+ The supported options in the `:styles` are:
557
+
558
+ * `:label` - the name for the log message.
559
+ * `:symbol` - the graphics to display before the log message label.
560
+ * `:color` - the color for the log message.
561
+ * `:levelpad` - the extra amount of padding used to display log label.
562
+
563
+ See the [TTY::Logger::Handlers::Console](https://github.com/piotrmurach/tty-logger/blob/master/lib/tty/logger/handlers/console.rb) for full list of styles.
564
+
565
+ Console handler has many default styles such as `success` and `error`:
566
+
567
+ ```ruby
568
+ logger = TTY::Logger.new
569
+ logger.success("Default success")
570
+ logger.error("Default error")
571
+ # =>
572
+ # ✔ success Default success
573
+ # ⨯ error Default error
574
+ ```
575
+
576
+ You can change the default styling with a tuple of handler name and options hash.
577
+
578
+ In our example, we want to change the styling of `success` and `error`:
579
+
580
+ ```ruby
581
+ new_styles = {
582
+ styles: {
583
+ success: {
584
+ symbol: "+",
585
+ label: "Ohh yes"
586
+ },
587
+ error: {
588
+ symbol: "!",
589
+ label: "Dooh",
590
+ levelpad: 3 # the amount of extra padding to align level names in a column
591
+ }
592
+ }
593
+ }
594
+ ```
595
+
596
+ And then use the `new_styles` when providing `handlers` configuration:
597
+
598
+ ```ruby
599
+ styled_logger = TTY::Logger.new do |config|
600
+ config.handlers = [[:console, new_styles]]
601
+ end
602
+
603
+ styled_logger.success("Custom success")
604
+ styled_logger.error("Custom error")
605
+ # =>
606
+ # + Ohh yes Custom success
607
+ # ! Dooh Custom error
608
+ ```
609
+
610
+ To increase message padding to a percentage of terminal width (depends on [tty-screen](https://github.com/piotrmurach/tty-screen/)):
611
+
612
+ ```ruby
613
+ TTY::Logger.new do |config|
614
+ padding = (TTY::Screen.columns * 0.4).to_i
615
+ config.handlers = [[:console, { message_format: "%-#{padding}s" }]]
616
+ end
617
+ ```
618
+
619
+ #### 2.6.2 Stream handler
620
+
621
+ To send log event data outside of console to another service or `IO` stream, you can use `:stream` handler.
622
+
623
+ ```ruby
624
+ logger = TTY::Logger.new(output: output) do |config|
625
+ config.handlers = [:stream]
626
+ config.metadata = [:all]
627
+ end
628
+ ```
629
+
630
+ By default, the output will be a plain text streamed to console. The text contains key and value pairs of all the metadata and the message of the log event.
631
+
632
+ ```ruby
633
+ logger.info("Info about the deploy", app:"myap", env:"prod")
634
+ # =>
635
+ # pid=18315 date="2019-07-21" time="15:42:12.463" path="examples/stream.rb:17:in`<main>`"
636
+ # level=info message="Info about the deploy" app=myapp env=prod
637
+ ```
638
+
639
+ You can change stream formatter for ease of working with external services such as `Logstash`. For example, to use `:stream` handler with `:json` format do:
640
+
641
+ ```ruby
642
+ logger = TTY::Logger.new(output: output) do |config|
643
+ config.handlers = [[:stream, formatter: :json]]
644
+ config.metadata = [:all]
645
+ end
646
+ ```
647
+
648
+ This will output JSON formatted text streamed to console.
649
+
650
+ ```ruby
651
+ logger.info("Info about the deploy", app="myap", env="prod")
652
+ # =>
653
+ # {"pid":18513,"date":"2019-07-21","time":"15:54:09.924","path":"examples/stream.rb:17:in`<main>`",
654
+ # "level":"info","message":"Info about the deploy","app":"myapp","env":"prod"}
655
+ ```
656
+
657
+ #### 2.6.3 Custom Handler
658
+
659
+ You can create your own log event handler if the default ones don't match your needs.
660
+
661
+ The design of your handler should include two calls:
662
+
663
+ * `initialize` - where all dependencies get injected
664
+ * `call` - where the log event is handled
665
+
666
+ We start with the implementation of the `initialize` method. This method by default is injected with `:config` key that includes all global configuration options. The `:output` key for displaying log message in the console and `:formatter`.
667
+
668
+ In our case we also add custom `:label`:
669
+
670
+ ```ruby
671
+ class MyHandler
672
+ def initialize(output: nil, config: nil, formatter: nil, label: nil)
673
+ @label = label
674
+ @output = output
675
+ end
676
+ end
677
+ ```
678
+
679
+ Next is the `call` method that accepts the log `event`.
680
+
681
+ The `event` has the following attributes:
682
+
683
+ * `message` - the array of message parts to be printed
684
+ * `fields` - the structured data supplied with the event
685
+ * `metadata` - the additional info about the event. See [metadata](#241-metadata) section for details.
686
+
687
+ We add implementation of `call`:
688
+
689
+ ```ruby
690
+ class MyHandler
691
+ def initialize(output: nil, config: nil, label: nil)
692
+ @label = label
693
+ @output = output
694
+ end
695
+
696
+ def call(event)
697
+ @output.puts "(#{@label}) #{event.message.join}"
698
+ end
699
+ end
700
+ ```
701
+
702
+ Once you have your custom handler, you need to register it with the logger. You can do so using the `handlers` configuration option:
703
+
704
+ ```ruby
705
+ logger = TTY::Logger.new do |config|
706
+ config.handlers = [[MyHandler, label: "myhandler"]]
707
+ end
708
+ ```
709
+
710
+ Or add your handler dynamically after logger initialization:
711
+
712
+ ```ruby
713
+ logger = TTY::Logger.new
714
+ logger.add_handler [MyHandler, label: "myhandler"]
715
+ ```
716
+
717
+ #### 2.6.4 Multiple Handlers
718
+
719
+ You can define as many handlers as you need. For example, you may log messages both to console and stream:
720
+
721
+ ```ruby
722
+ logger = TTY::Logger.new do |config|
723
+ config.handlers = [:console, :stream]
724
+ end
725
+ ```
726
+
727
+ Each handler can have its own configuration. For example, you can register `:console` handler to log messages above error level and `:stream` that logs any message with info or higher level:
728
+
729
+ ```ruby
730
+ logger = TTY::Logger.new do |config|
731
+ config.handlers = [
732
+ [:console, level: :error],
733
+ [:stream, level: :info]
734
+ ]
735
+ end
736
+ ```
737
+
738
+ ### 2.7 Formatters
739
+
740
+ The available formatters are:
741
+
742
+ * `:json`
743
+ * `:text`
744
+
745
+ You can configure format for all the handlers:
746
+
747
+ ```ruby
748
+ TTY::Logger.new do |config|
749
+ config.formatter = :json
750
+ end
751
+ ```
752
+
753
+ Or specify a different formatter for each handler. For example, let's say you want to log to console twice, once with default formatter and once with `:json` formatter:
754
+
755
+ ```ruby
756
+ TTY::Logger.new do |config|
757
+ config.handlers = [:console, [:console, formatter: :json]]
758
+ end
759
+ ```
760
+
761
+ ### 2.8 Output Streams
762
+
763
+ By default all log events are output to `stderr`. You can change this using configuration `output` option. Any `IO`-like stream such as file, socket or console can be used. For example, to log all messages to a file do:
764
+
765
+ ```ruby
766
+ logger = TTY::Logger.new do |config|
767
+ config.output = File.open("errors.log", "a")
768
+ end
769
+ ```
770
+
771
+ You can also specify multiple streams that all log messages will be sent to:
772
+
773
+ ```ruby
774
+ logger = TTY::Logger.new do |config|
775
+ config.output = [$stderr, File.open("errors.log", "a")]
776
+ end
777
+ ```
778
+
779
+ Conversely, you can specify different output for each of the handlers used. For example, you can output all messages above info level to a file with a stream handler and only show error messages in the console with a nicely formatted output.
780
+
781
+ ```ruby
782
+ logger = TTY::Logger.new do |config|
783
+ config.handlers = [
784
+ [:console, output: $stderr, level: :error],
785
+ [:stream, output: File.open("errors.log", "a"), level: :info)]
786
+ ]
787
+ end
788
+ ```
789
+
790
+ ## 3. Community Extensions
791
+
792
+ ### 3.1 Sentry Handler
793
+
794
+ [tty-logger-raven](https://github.com/ianks/tty-logger-raven) provides an extension for Sentry.io.
795
+
31
796
  ## Development
32
797
 
33
798
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.