File: index.html.md

package info (click to toggle)
ruby-dry-logger 1.2.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 444 kB
  • sloc: ruby: 2,170; makefile: 4; sh: 4
file content (314 lines) | stat: -rw-r--r-- 7,784 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
---
title: Introduction
description: Standalone, structured logging for Ruby
layout: gem-single
type: gem
name: dry-logger
sections:
  - backends
  - formatters
  - templates
  - filtering
  - context
  - tagging
  - crash-handling
  - testing
  - examples
---

dry-logger is a standalone, dependency-free logging solution for Ruby applications.

## Features

- **Structured logging** - First-class support for key-value payloads
- **Multiple destinations** - Log to stdout, files, or multiple backends simultaneously
- **Flexible formatting** - String, JSON, and Rack formatters included
- **Data filtering** - Redact sensitive information from logs
- **Exception handling** - Automatic formatting of exceptions with backtraces
- **Customizable templates** - Control log format with colorization support
- **Extensible** - Add custom backends and formatters

## Installation

Add dry-logger to your Gemfile:

```ruby
gem "dry-logger"
```

## Getting started

Create a logger and start logging:

```ruby
require "dry/logger"

logger = Dry.Logger(:my_app)

logger.info("Application started")
# Application started

logger.warn("Low memory warning")
# Low memory warning

logger.error("Failed to connect to database")
# Failed to connect to database
```

### Log levels

Set the minimum severity level to control which messages are logged:

```ruby
logger = Dry.Logger(:my_app, level: :warn)

logger.debug("Debug message")  # Won't be logged
logger.info("Info message")    # Won't be logged
logger.warn("Warning message") # Will be logged
logger.error("Error message")  # Will be logged
```

Available levels (lowest to highest): `:debug`, `:info` (default), `:warn`, `:error`, `:fatal`, `:unknown`

### Structured logging

Attach key-value data to log entries:

```ruby
logger = Dry.Logger(:my_app)

# Log with structured data
logger.info("User logged in", user_id: 42, ip: "192.168.1.1")
# User logged in user_id=42 ip="192.168.1.1"

# Log only structured data (no message)
logger.info(action: "signup", user_id: 123, plan: "premium")
# action="signup" user_id=123 plan="premium"
```

### Logging exceptions

Exceptions are automatically formatted with their message, class, and backtrace:

```ruby
begin
  1 / 0
rescue => e
  logger.error(e)
  # ZeroDivisionError: divided by 0
  #   /path/to/file.rb:10:in `/'
  #   /path/to/file.rb:10:in `<main>'
end
```

### Block-based logging

For expensive operations, use blocks to avoid computing messages unless they'll actually be logged:

```ruby
logger = Dry.Logger(:my_app, level: :info)

# Block is NOT evaluated (debug < info)
logger.debug { expensive_debug_info }

# Block IS evaluated
logger.info { "User count: #{User.count}" }
# User count: 42
```

Blocks can also return structured data:

```ruby
logger.info { {action: "cache_miss", key: "user:123"} }
# action="cache_miss" key="user:123"
```

### Customizing progname per entry

Override the logger's default progname for specific log entries:

```ruby
logger = Dry.Logger(:my_app)

# Use progname keyword
logger.info("Request received", progname: "http_server", path: "/api/users")
# Logs with progname "http_server" instead of "my_app"

# Or pass as first argument with block-based logging
logger.info("worker") { "Job completed" }
# Logs with progname "worker"
```

## Output streams

### Standard output (default)

```ruby
logger = Dry.Logger(:my_app)  # Logs to $stdout
```

### Files

```ruby
logger = Dry.Logger(:my_app, stream: "logs/application.log")  # Relative path
logger = Dry.Logger(:my_app, stream: "/var/log/app.log")      # Absolute path
```

### StringIO (testing)

```ruby
require "stringio"

output = StringIO.new
logger = Dry.Logger(:my_app, stream: output)

logger.info("Test message")

puts output.string
# Test message
```

## Multiple destinations

### Using add_backend

Add backends to the default logger:

```ruby
logger = Dry.Logger(:test, template: :details)
  .add_backend(stream: "logs/test.log")

logger.info "Hello World"
# Logs to both $stdout and logs/test.log
# [test] [INFO] [2022-11-17 11:46:12 +0100] Hello World
```

### Block-based configuration

For more control, configure all backends in a block:

```ruby
logger = Dry.Logger(:test) do |setup|
  setup.add_backend(stream: "logs/test.log", template: :details)
  setup.add_backend(stream: "logs/errors.log", log_if: :error?)
end

logger.info "Hello World"
# Only logs to the files you configured (no stdout)
```

When you use a block, dry-logger skips creating the default stdout backend, giving you complete control.

### Conditional logging

Route logs to specific backends based on conditions using `log_if`:

```ruby
logger = Dry.Logger(:test, template: :details)
  .add_backend(stream: "logs/requests.log", log_if: -> entry { entry.key?(:request) })

logger.info "Hello World"
# Only to $stdout: [test] [INFO] [2022-11-17 11:50:12 +0100] Hello World

logger.info "GET /posts", request: true
# To both $stdout and logs/requests.log
# [test] [INFO] [2022-11-17 11:51:50 +0100] GET /posts request=true
```

## Templates and formatting

### Custom templates

Customize the log format using sprintf-style templates:

```ruby
logger = Dry.Logger(:test, template: "[%<severity>s] %<message>s")

logger.info "Hello World"
# [INFO] Hello World
```

The following tokens are supported:

- `%<progname>s` - Logger identifier
- `%<severity>s` - Log level (DEBUG, INFO, WARN, ERROR, FATAL)
- `%<time>s` - Timestamp
- `%<message>s` - Log message
- `%<payload>s` - Structured data as key=value pairs

You can also use payload keys directly in templates:

```ruby
logger = Dry.Logger(:test, template: "[%<severity>s] %<verb>s %<path>s")

logger.info verb: "GET", path: "/users"
# [INFO] GET /users
```

### Colorized output

Use color tags in templates for better readability:

```ruby
logger = Dry.Logger(:test, template: "[%<severity>s] <blue>%<verb>s</blue> <green>%<path>s</green>")

logger.info verb: "GET", path: "/users"
# [INFO] GET /users (with blue verb and green path)
```

Available colors: `black`, `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, `gray`

### Formatters

dry-logger includes three formatters:

- `:string` - Human-readable `key=value` format with color support (development)
- `:json` - Structured JSON with UTC timestamps (production)
- `:rack` - Optimized for HTTP request logging

Use the `formatter` option:

```ruby
logger = Dry.Logger(:test, formatter: :rack)

logger.info verb: "GET", path: "/users", elapsed: "12ms", ip: "127.0.0.1", status: 200, length: 312, params: {}
# [test] [INFO] [2022-11-17 12:04:30 +0100] GET 200 12ms 127.0.0.1 /users 312
```

## Log rotation

Rotate logs by size or time period:

**Size-based rotation:**

```ruby
# Keep 5 files, max 10MB each
logger = Dry.Logger(:test,
  stream: "logs/test.log",
  shift_age: 5,
  shift_size: 10_485_760
)
```

**Time-based rotation:**

```ruby
# Rotate daily, weekly, or monthly
logger = Dry.Logger(:test, stream: "logs/test.log", shift_age: "daily")
```

See Ruby's [Logger documentation](https://rubyapi.org/o/logger#class-Logger-label-Log+File+Rotation) for details.

## Next steps

Now that you understand the basics, explore more features:

- [Backends](docs::backends) - Configure multiple logging destinations
- [Formatters](docs::formatters) - Control output format (string, JSON, Rack)
- [Templates](docs::templates) - Customize log message format
- [Filtering](docs::filtering) - Filter sensitive data from logs
- [Context](docs::context) - Add request-scoped data to log entries
- [Tagged logging](docs::tagging) - Mark and filter log entries with tags
- [Crash handling](docs::crash-handling) - Customize behavior when logging itself crashes
- [Testing](docs::testing) - Test your application's logging
- [Examples](docs::examples) - Complete, realistic configuration examples