Introduction
dry-logger provides a standalone, dependency-free logging solution suitable for any Ruby application.
- Structured logging by default
- Logging to multiple destinations via pluggable logging
backends
- Fine-grained log formatting using
formatters
- Customizable logging logic via log filtering
- Out-of-the-box exception logging
- Built-in support for text log templates with customizable colorized output
- Built-in support for tagged log entries
- Public API for adding your own
backends
andformatters
Basic setup
To configure a basic $stdout
logger simply use the main setup method Dry.Logger
:
logger = Dry.Logger(:my_app)
logger.info "Hello World"
# Hello World
The setup method accepts various options to configure the logger. You can change default formatter, provide customized text templates, and so on.
Let's use a more detailed logging template that gives more logging context in the output:
logger = Dry.Logger(:test, template: :details)
logger.info "Hello World"
# [test] [INFO] [2022-11-17 11:43:52 +0100] Hello World
Using multiple logging destinations
You can configure your logger to log to more than one destination. In case of the default logger,
the destination is set to $stdout
. Let's say you want to log both to $stdout
and a file:
logger = Dry.Logger(:test, template: :details).add_backend(stream: "logs/test.log")
# This goes to $stdout and logs/test.log too
logger.info "Hello World"
# [test] [INFO] [2022-11-17 11:46:12 +0100] Hello World
Conditional logging
You can tell your backends when exactly they should be logging using log_if
option. It can be set
to either a symbol that represents a method that Dry::Logger::Entry
implements or a custom proc.
Here's a simple example:
logger = Dry.Logger(:test, template: :details)
.add_backend(stream: "logs/requests.log", log_if: -> entry { entry.key?(:request) })
# This goes only to $stdout
logger.info "Hello World"
# [test] [INFO] [2022-11-17 11:50:12 +0100] Hello World
# This goes to $stdout and logs/requests.log
logger.info "GET /posts", request: true
# [test] [INFO] [2022-11-17 11:51:50 +0100] GET /posts request=true
Using custom templates
You can provide customized text log templates using regular Ruby syntax for tokenized string templates:
logger = Dry.Logger(:test, template: "[%<severity>s] %<message>s")
logger.info "Hello World"
# [INFO] Hello World
The following tokens are supported:
%<progname>s
- the name of your logger, ieDry.Logger(:test)
setsprogname
totest
%<severity>s
- log level name%<time>s
- log entry timestamp%<message>s
- log text message passed as a string, ielogger.info("Hello World")
setsmessage
to"Hello World"
%<payload>s
- optional log entry payload provided as keywords, ielogger.info(text: "Hello World")
setspayload
to{text: "Hello World"}
and its presentation depends on the formatter that was used
Furthermore, you can use payload keys that are expected to be passed to a specific logging backend. Here's an example:
logger = Dry.Logger(:test, template: "[%<severity>s] %<verb>s %<path>s")
logger.info verb: "GET", path: "/users"
# [INFO] GET /users
Using colorized text output
You can use simple color tags to colorize specific values in the text output:
logger = Dry.Logger(:test, template: "[%<severity>s] <blue>%<verb>s</blue> <green>%<path>s</green>")
# This is now colorized, you gotta trust us
logger.info verb: "GET", path: "/users"
# [INFO] GET /users
Following built-in color tags are supported:
- black
- red
- green
- yellow
- blue
- magenta
- cyan
- gray
Customizing formatters
There are three built-in formatters:
:string
- formats payload intokey=value
sequence and supports colorized output, suitable for development environmments:json
- suitable for production environments, formats timestamps intoUTC
:rack
- suitable for logging rack requests
To configure a specific formatter, use the formatter
option:
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