A custom formatter for the logger application with LFE logging macros and human-readable output
The default formatter for Erlang is very difficult to read at a glance making troubleshooting and debugging of applications via log output during development phases rather cumbersome or even difficult.
With logjam, you get something nice and easy to read:
Previous versions of logjam wrapped older versions of the lager logging library. As of Erlang 21.0, Erlang has a new (and excellent) logging library, yet the same output is used (and thus the same problems regarding developer readability persist). The flatlog library was created to provide structured logging support for the new logger library, and this project was used as the basis of logjam 1.0. Logjam provides additional configuration on top of the code inherited from flatlog, and while it does support much of the same structured logging that flatlog provides, its goals are completely different.
For versions of Erlang older than 21.0 (and for LFE 1.2), you may be able to use the 0.6.0 release of logjam.
There are two ways to use logjam:
- Simply as a formatter, in which case it should be to the release apps and not included as a dependency. This assumes you will be using the logger macros included with Erlang/OTP.
- As both a formatter as well as taking advantage of the logjam logging macros that have Lisp-style names (e.g.,
log-debug
). In this case, you will want to include logjam as a dependency.
Once the project is added, replace the formatter of the default handler (or add a custom handler) for structured logging to your sys.config
file:
[
{kernel, [
{logger, [
{handler, default, logger_std_h,
#{level => info,
formatter => {logjam,
#{colored => true,
time_designator => $\s,
time_offset => "",
time_unit => second,
strip_tz => true,
level_capitalize => true
}
}
}
}
]}
]}
].
This configuration was used to produce the screenshot above.
Note that if you are building a release, you will need to manually add
the logjam
dependency to your relx
configuration, since it is
technically not a direct dependency of any application in your system.
If you're not using an OTP release and just want to set up logging based upon a config file with the above entry in it, you can do the following:
(logjam:set-config #(path "./path/to/thing.config"))
This is what is done in ./scripts/demo.lfe
.
If you have the config data already in above format (proplist with a kernel
entry), you can just do this:
(logjam:set-config config-data)
If you call the logger functions directly, your log output will not have reference to the module, function, arity, or line number where the logging call was made. For this info, you need to use the logger
or logjam
macros.
Include the logger
calls with either:
(include-lib "kernel/include/logger.hrl")
or
-include_lib("kernel/include/logger.hrl").
This will let you call the logging macros such as (LOG_DEBUG "my message")
or ?LOG_DEBUG("my message").
If you'd like to use the logjam
macros, use these instead:
(include-lib "logjam/include/logjam.hrl")
or
-include_lib("logjam/include/logjam.hrl").
This will let you call the logging macros such as (log-debug "my message")
or ?'log-debug'("my message").
Here is some example LFE usage:
(log-debug "This is a debug-level message")
(log-info "This is an info-level message")
(log-notice "This is a notice-level message")
(log-warn "This is a warning-level message")
(log-error "This is an error-level message")
(log-crit "This is a critical-level message")
(log-alert "This is an alert-level message")
(log-emergency "This is an emergency-level message")
(log-info #m(some "structured" logging "examples" might "be useful too")))
rebar3 demo
rebar3 check