tty-logger 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/README.md +200 -40
- data/examples/child.rb +9 -0
- data/examples/console.rb +4 -4
- data/examples/custom_type.rb +27 -0
- data/examples/log.rb +9 -0
- data/examples/stream.rb +2 -2
- data/lib/tty/logger.rb +116 -50
- data/lib/tty/logger/config.rb +32 -2
- data/lib/tty/logger/handlers/base.rb +13 -0
- data/lib/tty/logger/handlers/console.rb +1 -1
- data/lib/tty/logger/levels.rb +32 -17
- data/lib/tty/logger/version.rb +1 -1
- data/spec/perf/json_formatter_spec.rb +29 -0
- data/spec/perf/log_spec.rb +21 -0
- data/spec/perf/text_formatter_spec.rb +29 -0
- data/spec/unit/config_spec.rb +3 -1
- data/spec/unit/copy_spec.rb +27 -0
- data/spec/unit/filter_spec.rb +32 -0
- data/spec/unit/log_at_spec.rb +34 -0
- data/spec/unit/log_spec.rb +71 -12
- data/tasks/spec.rake +12 -7
- data/tty-logger.gemspec +3 -0
- metadata +11 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 31142537abe01781e199d8b551eea32bdc802c1e9a46bec7947b3240249df798
|
4
|
+
data.tar.gz: 33b6816da36b2c41651452a9efa82b8e69b62eef6dbdfdc136c5195140b76d4b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d5b65cbbe0a3c9cefcb3fe082242a47e6090626c41531fbd6f97dfc528e795b2e2f56f2ce5f27f1a0404620ce2a12139745e028a9d3a31a6bf630bb7c600f3fb
|
7
|
+
data.tar.gz: 9e19ee528817ea3ef0d4ccf5c4a9601857b69e3b2120ad8ca7b5715ca57ea164a346ecd7cd90ad253cc81b707820098a019b77ea54dff547e12e8384b7154477
|
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,20 @@
|
|
1
1
|
# Change log
|
2
2
|
|
3
|
+
## [v0.2.0] - 2019-09-30
|
4
|
+
|
5
|
+
### Added
|
6
|
+
* Add ability to add structured data inside logging block
|
7
|
+
* Add ability to filter sensitive data
|
8
|
+
* Add ability to define custom log types
|
9
|
+
* Add ability to temporarily log at different level
|
10
|
+
* Add performance tests
|
11
|
+
|
12
|
+
### Changed
|
13
|
+
* Change to dynamically define log types
|
14
|
+
|
3
15
|
## [v0.1.0] - 2019-07-21
|
4
16
|
|
5
17
|
* Initial implementation and release
|
6
18
|
|
19
|
+
[v0.2.0]: https://github.com/piotrmurach/tty-logger/compare/v0.1.0..v0.2.0
|
7
20
|
[v0.1.0]: https://github.com/piotrmurach/tty-logger/compare/v0.1.0
|
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
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>
|
3
3
|
</div>
|
4
4
|
|
5
|
-
# TTY::Logger
|
5
|
+
# TTY::Logger [![Gitter](https://badges.gitter.im/Join%20Chat.svg)][gitter]
|
6
6
|
|
7
7
|
[![Gem Version](https://badge.fury.io/rb/tty-logger.svg)][gem]
|
8
8
|
[![Build Status](https://secure.travis-ci.org/piotrmurach/tty-logger.svg?branch=master)][travis]
|
@@ -30,6 +30,8 @@
|
|
30
30
|
* Intuitive console output for an increased readability
|
31
31
|
* Ability to stream data to any IO object
|
32
32
|
* Supports structured data logging
|
33
|
+
* Filters sensitive data
|
34
|
+
* Allows to define custom log types
|
33
35
|
* Formats and truncates messages to avoid clogging logging output
|
34
36
|
* Customizable styling of labels and symbols for console output
|
35
37
|
* Includes metadata information: time, location, scope
|
@@ -58,17 +60,21 @@ Or install it yourself as:
|
|
58
60
|
* [2. Synopsis](#2-synopsis)
|
59
61
|
* [2.1 Logging](#21-logging)
|
60
62
|
* [2.1.1 Exceptions](#211-exceptions)
|
63
|
+
* [2.1.2 Types](#212-types)
|
61
64
|
* [2.2 Levels](#22-levels)
|
65
|
+
* [2.2.1 Scoped Level](#22-scoped-levels)
|
62
66
|
* [2.3 Structured Data](#23-structured-data)
|
63
67
|
* [2.4 Configuration](#24-configuration)
|
64
68
|
* [2.4.1 Metadata](#241-metadata)
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
* [2.
|
69
|
-
* [2.
|
70
|
-
|
71
|
-
|
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)
|
72
78
|
|
73
79
|
## 1. Usage
|
74
80
|
|
@@ -78,7 +84,7 @@ Create logger:
|
|
78
84
|
logger = TTY::Logger.new
|
79
85
|
```
|
80
86
|
|
81
|
-
And log information using any of the logger [types](#
|
87
|
+
And log information using any of the logger [built-in types](#212-types):
|
82
88
|
|
83
89
|
```ruby
|
84
90
|
logger.info "Deployed successfully"
|
@@ -89,7 +95,7 @@ logger.info { "Dynamically generated info" }
|
|
89
95
|
Include structured data:
|
90
96
|
|
91
97
|
```ruby
|
92
|
-
logger.
|
98
|
+
logger.success "Deployed successfully", myapp: "myapp", env: "prod"
|
93
99
|
# =>
|
94
100
|
# ✔ success Deployed successfully app=myapp env=prod
|
95
101
|
```
|
@@ -105,7 +111,7 @@ logger.info "Deployed successfully", myapp: "myapp", env: "prod"
|
|
105
111
|
# [2019-07-17] [23:21:55.287] › ℹ info Info about the deploy app=myapp env=prod
|
106
112
|
```
|
107
113
|
|
108
|
-
Or change structured data [formatting](#
|
114
|
+
Or change structured data [formatting](#27-formatters) display to `JSON`:
|
109
115
|
|
110
116
|
```ruby
|
111
117
|
logger = TTY::Logger.new do |config|
|
@@ -148,13 +154,23 @@ logger.success "Deployed", "successfully"
|
|
148
154
|
|
149
155
|
You can delay message evaluation by passing it inside a block:
|
150
156
|
|
157
|
+
```ruby
|
158
|
+
logger.success { "Dynamically generated info" }
|
159
|
+
# =>
|
160
|
+
# ✔ success Dynamically generated info
|
151
161
|
```
|
152
|
-
|
162
|
+
|
163
|
+
Similar to regular logging, you cal split your message into chunks inside a block:
|
164
|
+
|
165
|
+
```ruby
|
166
|
+
logger.success { ["Dynamically", "generated", "info"] }
|
153
167
|
# =>
|
154
|
-
# ✔ success
|
168
|
+
# ✔ success Dynamically generated info
|
155
169
|
```
|
156
170
|
|
157
|
-
|
171
|
+
The above comes handy when paired with [structured data](#23-structured-data).
|
172
|
+
|
173
|
+
#### 2.1.1 Exceptions
|
158
174
|
|
159
175
|
You can also report on exceptions.
|
160
176
|
|
@@ -164,7 +180,7 @@ For example, let's say you caught an exception about incorrect data format and u
|
|
164
180
|
begin
|
165
181
|
raise ArgumentError, "Wrong data"
|
166
182
|
rescue => ex
|
167
|
-
logger.fatal("Error:",
|
183
|
+
logger.fatal("Error:", ex)
|
168
184
|
end
|
169
185
|
```
|
170
186
|
|
@@ -178,6 +194,51 @@ This will result in a message followed by a full backtrace:
|
|
178
194
|
# rspec-core-3.8.2/lib/rspec/core/example.rb:257:in `block in run'
|
179
195
|
```
|
180
196
|
|
197
|
+
#### 2.1.2 Types
|
198
|
+
|
199
|
+
You can define custom log types via the `types` configuration option:
|
200
|
+
|
201
|
+
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:
|
202
|
+
|
203
|
+
```ruby
|
204
|
+
logger = TTY::Logger.new do |config|
|
205
|
+
config.types = {
|
206
|
+
thanks: {level: :info},
|
207
|
+
done: {level: :info}
|
208
|
+
}
|
209
|
+
config.handlers = [
|
210
|
+
[:console, {
|
211
|
+
styles: {
|
212
|
+
thanks: {
|
213
|
+
symbol: "❤️ ",
|
214
|
+
label: "thanks",
|
215
|
+
color: :magenta,
|
216
|
+
levelpad: 0
|
217
|
+
},
|
218
|
+
done: {
|
219
|
+
symbol: "!!",
|
220
|
+
label: "done",
|
221
|
+
color: :green,
|
222
|
+
levelpad: 2
|
223
|
+
}
|
224
|
+
}
|
225
|
+
}]
|
226
|
+
]
|
227
|
+
end
|
228
|
+
```
|
229
|
+
|
230
|
+
Once defined, you can call new log types:
|
231
|
+
|
232
|
+
```ruby
|
233
|
+
logger.thanks("Great work!")
|
234
|
+
logger.done("Work done!")
|
235
|
+
# =>
|
236
|
+
# ❤️ thanks Great work!
|
237
|
+
# !! done Work done!
|
238
|
+
```
|
239
|
+
|
240
|
+
![](assets/tty-logger-custom-log-types.png)
|
241
|
+
|
181
242
|
### 2.2 Levels
|
182
243
|
|
183
244
|
The supported levels, ordered by precedence, are:
|
@@ -192,17 +253,17 @@ So the order is: `:debug` < `:info` < `:warn` < `:error` < `:fatal`
|
|
192
253
|
|
193
254
|
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.
|
194
255
|
|
195
|
-
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
|
256
|
+
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.
|
196
257
|
|
197
258
|
```ruby
|
198
259
|
TTY::Logger.new do |config|
|
199
|
-
config.level = :info # or "INFO"
|
260
|
+
config.level = :info # or "INFO" or TTY::Logger::INFO_LEVEL
|
200
261
|
end
|
201
262
|
```
|
202
263
|
|
203
264
|
Or you can specific level for each log events handler.
|
204
265
|
|
205
|
-
For example, to log messages above info level to a stream and only error level events to the console do:
|
266
|
+
For example, to log messages above `:info` level to a stream and only `:error` level events to the console do:
|
206
267
|
|
207
268
|
```ruby
|
208
269
|
logger = TTY::Logger.new do |config|
|
@@ -213,7 +274,34 @@ logger = TTY::Logger.new do |config|
|
|
213
274
|
end
|
214
275
|
```
|
215
276
|
|
216
|
-
You can also change the [output streams](#
|
277
|
+
You can also change the [output streams](#28-output-streams) for each handler.
|
278
|
+
|
279
|
+
#### 2.2.1 Scoped Level
|
280
|
+
|
281
|
+
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:
|
282
|
+
|
283
|
+
```ruby
|
284
|
+
logger = TTY::Logger.new
|
285
|
+
|
286
|
+
logger.info("not logged")
|
287
|
+
|
288
|
+
logger.log_at :debug do
|
289
|
+
logger.debug("logged")
|
290
|
+
end
|
291
|
+
# =>
|
292
|
+
# • debug logged
|
293
|
+
```
|
294
|
+
|
295
|
+
Or elevating level to error with a constant `ERROR_LEVEL`:
|
296
|
+
|
297
|
+
```ruby
|
298
|
+
logger.log_at TTY::Logger::ERROR_LEVEL do
|
299
|
+
logger.debug("not logged")
|
300
|
+
logger.error("logged")
|
301
|
+
end
|
302
|
+
# =>
|
303
|
+
# ⨯ error logged
|
304
|
+
```
|
217
305
|
|
218
306
|
### 2.3 Structured data
|
219
307
|
|
@@ -236,16 +324,26 @@ logger.wait "Ready to deploy", app: "myapp", env: "prod"
|
|
236
324
|
# … waiting Ready to deploy app=myapp env=prod
|
237
325
|
```
|
238
326
|
|
327
|
+
You can delay data evaluation until it's evaluated by passing it inside a block:
|
328
|
+
|
329
|
+
```ruby
|
330
|
+
logger.wait { ["Ready to deploy", {app: "myapp", env: "prod"}] }
|
331
|
+
# =>
|
332
|
+
# … waiting Ready to deploy app=myapp env=prod
|
333
|
+
```
|
334
|
+
|
239
335
|
### 2.4 Configuration
|
240
336
|
|
241
337
|
All the configuration options can be changed globally via `configure` or per logger instance via object initialization.
|
242
338
|
|
243
|
-
* `:
|
244
|
-
* `:
|
339
|
+
* `:filters` - the storage of placeholders to filter sensitive data out from the logs. Defaults to `{}`.
|
340
|
+
* `:formatter` - the formatter used to display structured data. Defaults to `:text`. See [Formatters](#27-formatters) for more details.
|
341
|
+
* `:handlers` - the handlers used to log messages. Defaults to `[:console]`. See [Handlers](#26-handlers) for more details.
|
245
342
|
* `: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`
|
246
343
|
* `:max_bytes` - the maximum message size to be logged in bytes. Defaults to `8192` bytes. The truncated message will have `...` at the end.
|
247
344
|
* `:max_depth` - the maximum depth for nested structured data. Defaults to `3`.
|
248
345
|
* `: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.
|
346
|
+
* `:types` - the new custom log types. Defaults to `{}`.
|
249
347
|
|
250
348
|
For example, to configure `:max_bytes`, `:level` and `:metadata` for all logger instances do:
|
251
349
|
|
@@ -275,7 +373,69 @@ The `:metdata` configuration option can include the following symbols:
|
|
275
373
|
* `:time` - the log event time
|
276
374
|
* `:file` - the file with a line number the log event is triggered from
|
277
375
|
|
278
|
-
### 2.
|
376
|
+
### 2.4.2 Filters
|
377
|
+
|
378
|
+
You can filter sensitive data out of log output with `filters` configuration option. As a value provide a list of sensitive data items:
|
379
|
+
|
380
|
+
```ruby
|
381
|
+
logger = TTY::Logger.new(output: output) do |config|
|
382
|
+
config.filters = ["secret", "password"]
|
383
|
+
end
|
384
|
+
```
|
385
|
+
|
386
|
+
Which by default will replace each data item with `[FILTERED]` placeholder:
|
387
|
+
|
388
|
+
```ruby
|
389
|
+
logger.info("Super secret info with password")
|
390
|
+
# =>
|
391
|
+
# ℹ info Super [FILTERED] info with [FILTERED]
|
392
|
+
```
|
393
|
+
|
394
|
+
You can also replace each data item with a custom placeholder. To do so use a hash with pairs of matched text and replacement placeholder.
|
395
|
+
|
396
|
+
For example, to replace "secret" content with placeholder "<SECRET>" do:
|
397
|
+
|
398
|
+
```ruby
|
399
|
+
logger = TTY::Logger.new do |config|
|
400
|
+
config.filters = { "secret" => "<SECRET>" }
|
401
|
+
end
|
402
|
+
```
|
403
|
+
|
404
|
+
When logged, it will produce:
|
405
|
+
|
406
|
+
```ruby
|
407
|
+
logger.info("Super secret info")
|
408
|
+
# =>
|
409
|
+
# ℹ info Super <SECRET> info
|
410
|
+
```
|
411
|
+
|
412
|
+
### 2.5 Cloning
|
413
|
+
|
414
|
+
You can create a copy of a logger with the current configuration using the `copy` method.
|
415
|
+
|
416
|
+
For example, given the following logger with `:app` and `:env` data:
|
417
|
+
|
418
|
+
```ruby
|
419
|
+
logger = TTY::Logger.new(fields: {app: "parent", env: "prod"})
|
420
|
+
```
|
421
|
+
|
422
|
+
We can create a copy with a custom configuration that changes filtered message content and `:app` data:
|
423
|
+
|
424
|
+
```ruby
|
425
|
+
child_logger = logger.copy(app: "child") do |config|
|
426
|
+
config.filters = ["logging"]
|
427
|
+
end
|
428
|
+
```
|
429
|
+
|
430
|
+
```ruby
|
431
|
+
logger.info("Parent logging")
|
432
|
+
child_logger.warn("Child logging")
|
433
|
+
# =>
|
434
|
+
# ℹ info Parent logging app=parent env=prod
|
435
|
+
# ⚠ warning Child [FILTERED] app=child env=prod
|
436
|
+
```
|
437
|
+
|
438
|
+
### 2.6 Handlers
|
279
439
|
|
280
440
|
`TTY::Logger` supports many ways to handle log messages.
|
281
441
|
|
@@ -285,7 +445,7 @@ The available handlers by default are:
|
|
285
445
|
* `:null` - discards any log messages
|
286
446
|
* `:stream` - log messages to an `IO` stream, a file, a socket or a console.
|
287
447
|
|
288
|
-
You can also implement your own [custom handler](#
|
448
|
+
You can also implement your own [custom handler](#263-custom-handler).
|
289
449
|
|
290
450
|
The handlers can be configured via global or instance configuration with `handlers`. The handler can be a name or a class name:
|
291
451
|
|
@@ -311,7 +471,7 @@ logger.add_handler(:console)
|
|
311
471
|
logger.remove_handler(:console)
|
312
472
|
```
|
313
473
|
|
314
|
-
#### 2.
|
474
|
+
#### 2.6.1 Console Handler
|
315
475
|
|
316
476
|
The console handler prints log messages to the console. It supports the following options:
|
317
477
|
|
@@ -326,9 +486,9 @@ The supported options in the `:styles` are:
|
|
326
486
|
* `:color` - the color for the log message.
|
327
487
|
* `:levelpad` - the extra amount of padding used to display log label.
|
328
488
|
|
329
|
-
See the [TTY::Logger::Handlers::Console]() for full list of styles.
|
489
|
+
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.
|
330
490
|
|
331
|
-
Console handler has many
|
491
|
+
Console handler has many default styles such as `success` and `error`:
|
332
492
|
|
333
493
|
```ruby
|
334
494
|
logger = TTY::Logger.new
|
@@ -339,7 +499,7 @@ logger.error("Default error")
|
|
339
499
|
# ⨯ error Default error
|
340
500
|
```
|
341
501
|
|
342
|
-
You can change
|
502
|
+
You can change the default styling with a tuple of handler name and options hash.
|
343
503
|
|
344
504
|
In our example, we want to change the styling of `success` and `error`:
|
345
505
|
|
@@ -353,7 +513,7 @@ new_styles = {
|
|
353
513
|
error: {
|
354
514
|
symbol: "!",
|
355
515
|
label: "Dooh",
|
356
|
-
levelpad: 3
|
516
|
+
levelpad: 3 # the amount of extra padding to align level names in a column
|
357
517
|
}
|
358
518
|
}
|
359
519
|
}
|
@@ -362,18 +522,18 @@ new_styles = {
|
|
362
522
|
And then use the `new_styles` when providing `handlers` configuration:
|
363
523
|
|
364
524
|
```ruby
|
365
|
-
|
366
|
-
config.handlers = [:console, new_styles]
|
525
|
+
styled_logger = TTY::Logger.new do |config|
|
526
|
+
config.handlers = [[:console, new_styles]]
|
367
527
|
end
|
368
528
|
|
369
|
-
|
370
|
-
|
529
|
+
styled_logger.success("Custom success")
|
530
|
+
styled_logger.error("Custom error")
|
371
531
|
# =>
|
372
|
-
+ Ohh yes Custom success
|
373
|
-
! Dooh Custom error
|
532
|
+
# + Ohh yes Custom success
|
533
|
+
# ! Dooh Custom error
|
374
534
|
```
|
375
535
|
|
376
|
-
#### 2.
|
536
|
+
#### 2.6.2 Stream handler
|
377
537
|
|
378
538
|
To send log event data outside of console to another service or `IO` stream, you can use `:stream` handler.
|
379
539
|
|
@@ -387,7 +547,7 @@ end
|
|
387
547
|
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.
|
388
548
|
|
389
549
|
```ruby
|
390
|
-
loggger.info("Info about the deploy", app
|
550
|
+
loggger.info("Info about the deploy", app:"myap", env:"prod")
|
391
551
|
# =>
|
392
552
|
# pid=18315 date="2019-07-21" time="15:42:12.463" path="examples/stream.rb:17:in`<main>`"
|
393
553
|
# level=info message="Info about the deploy" app=myapp env=prod
|
@@ -411,7 +571,7 @@ loggger.info("Info about the deploy", app="myap", env="prod")
|
|
411
571
|
# "level":"info","message":"Info about the deploy","app":"myapp","env":"prod"}
|
412
572
|
```
|
413
573
|
|
414
|
-
#### 2.
|
574
|
+
#### 2.6.3 Custom Handler
|
415
575
|
|
416
576
|
You can create your own log event handler if the default ones don't match your needs.
|
417
577
|
|
@@ -471,7 +631,7 @@ logger = TTY::Logger.new
|
|
471
631
|
logger.add_handler [MyHandler, label: "myhandler"]
|
472
632
|
```
|
473
633
|
|
474
|
-
#### 2.
|
634
|
+
#### 2.6.4 Multiple Handlers
|
475
635
|
|
476
636
|
You can define as many handlers as you need. For example, you may log messages both to console and stream:
|
477
637
|
|
@@ -492,7 +652,7 @@ logger = TTY::Logger.new do |config|
|
|
492
652
|
end
|
493
653
|
```
|
494
654
|
|
495
|
-
### 2.
|
655
|
+
### 2.7 Formatters
|
496
656
|
|
497
657
|
The available formatters are:
|
498
658
|
|
@@ -514,7 +674,7 @@ TTY::Logger.new do |config|
|
|
514
674
|
config.handlers = [:console, [:console, formatter: :json]]
|
515
675
|
end
|
516
676
|
```
|
517
|
-
### 2.
|
677
|
+
### 2.8 Output Streams
|
518
678
|
|
519
679
|
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:
|
520
680
|
|