API Documentation Website

Extensions to Crystal's Log class.

And everything is optional so if you only want the JSON formatter you can just use that. Dexter does not break the existing Log and is a very small library.


  1. Add the dependency to your shard.yml:

        github: luckyframework/dexter
        version: ~> 0.3
  2. Run shards install

Getting started example

require "dexter"

backend =
backend.formatter = Dexter::JSONLogFormatter.proc
# Equivalent to: Log.builder.bind "*", :info, backend
Log.dexter.configure(:info, backend)

# These examples use 'info' but you can use 'debug', 'warn', and 'error' as well.
# Logs timestamp, severity and {foo: "bar"} as JSON { {foo: "bar"} }

# You can pass an exception *and* key/value data
Log.dexter.error(exception: my_exception) { {foo: "bar"} }

# Fully compatible with built-in Crystal Log
# Logs timestamp, severity and {message: "My message"} as JSON { "My message" }

Type-safe Log configuration

Use {LogClass}.dexter.configure to configure{LogClass}` and its child logs

Rather than pass a string source to Log.builder.bind you can configure a log using its class. This is a type-safe and simpler alternative to using Log.builder.bind.


Note: the backend can be left off and it will use the {LogClass}'s existing backend or a new Log::IOBackend

# Configure all logs.
# Similar to `Log.builder.bind "*"`
Log.dexter.configure(:info, backend)

# Configure Avram::Log and all child logs
# Similar to `Log.builder.bind "avram.*"

# Can further customize child Logs

{LogClass}.dexter.configure sets all child logs to the given level/backend . If you want to configure a Log and leave its children alone it is best to set the level or backend directly:

MyShard::Log.level = :error
MyShard::Log.backend =

Test helpers

This will temporarily configure the given log with a Log::IOBackend with an IO::Memory that is yielded. The log level is also temporarily set to :debug to log all messages

MyShard::Log.dexter.temp_config do |log_io| { "log me" }
  log_io.to_s.should contain("log me")

There are more options for changing the level, passing your own IO, etc. See the documentation for more details

Built-in formatters

Dexter works with any Log::Formatter, but has a JSON formatter built-in that works especially well.

  "exception": { "class": "RuntimeError", "message": "Something broke", backtrace: [""] }

Create your own formatter

Included is a Dexter::JSONLogFormatter, but you can create your own formatter to format and output log data however you want. For example, Lucky has a PrettyLogFormatter that formats data in a human readable format during development, and uses the JSONLogFormatter in production.

See an example formatter in Dexter::JSONLogFormatter


  1. Fork it (
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request