heavy-logger README
This is Haskell logging library, which prefers functionality and extendability
over light weight and simplicity.
It can use fast-logger as backend and is compatible with monad-logger
interface, so it can be used in projects that already use monad-logger.
heavy-logger is integrated with text-format-heavy string formatting library.
Most notable features of heavy-logger are:
- Several backends and possibility to write your own backends. The provided
backends are:
- Fast-logger backend. It allows to write messages to stdout, stderr or
arbitrary file.
- Syslog backend.
- Chan backend. Writes messages to a Chan, so they can be read from the other
side.
- Possiblity to write messages to several backends in parallel.
- Logging backend settings can be defined dynamically; it is not necessary to
hardcode which backend you will use, you can load settings in runtime.
- It is possible to change backend or it's settings in runtime (more precisely,
you can change underlying backend if you use
DynamicBackend
as a backend,
or you can change backend's filter if you use FilteringM
as a backend).
- Sane default set of logging message severity levels and possibility to define
custom severity levels.
- Logging context stacks support (aka mapped diagnostic contexts, MDC). Each
logging context stack frame contains a set of named variables. These
variables can be writen to the log.
- Possibility to define log message format in the output file. For example, do
you want to see event severity level first, and then time, or vice versa? It
is possible to use variables from logging context stack in the formatting
string.
- Flexible events filtering mechanism. Messages are filtered based on message
source and severity level. For example, you may want to write only Info
messages, but also Debug messages from one module. Filtering can be
performed on two stages:
- Before event is passed to backend. This stage is context-sensitive; for
example, you can enable logging only for events that happened during
transaction. Context-level filters also support negation; for example, it
is possible to explicitly forbid debug messages from one contexts, while
debug is enabled for the whole system.
- In the backend. For example, you can forbid to write any debug into file,
but allow to write all debug into syslog.
- Text formatting library integration. Formatting of messages by
text-format-heavy
is done lazily; so, you can issue a lot of debug
messages, that include data that take time to present as a string; the
formatting will be executed only in the case when debug output for this
module is actually enabled by the filter.
This package is mostly writen with ideas of "open architecture". It exposes all
internal logical pieces, so they can be combined in other order in specific
applications.
All functions provided by the package work within any monad, which should be an
instance of one of type classes defined by package: HasLogger
, HasLogBackend
,
HasLogContext
. Each function's signature declares only specific constraint, so
if you do not need all functionality, you can implement instances only of that
classes that you actually need.
There are, in general, following ways to use this package:
- Use
LoggingT
monad transformer. It can be the simplest, if you already have
monadic transformers stack of 1-2 transformers and you do not mind to add yet
another. With LoggingT
, you do not need to write any adapter instances, since
LoggingT
is already an instance of all required classes. This implementation
automatically solves all threading-related problems, since in fact it does not
have any shared state.
- Use
System.Log.Heavy.IO
module. If you do not have monadic transformers at all,
and your application works in pure IO, this may be the simplest way. However,
this is a bit fragile, because you have to be sure that you always call logging
functions only when logging state is initialized, i.e. within withLoggingIO
call. This implementation stores required state in thread-local storage.
- Implement required class instances for monadic stack that you already use in
your application. For example, if you already have something like
ReaderT StateT ExceptT IO
, it will be probably better to add a couple of
fields to StateT's state to track logging state, than change your stack to
ReaderT StateT LoggingT ExceptT IO
. If you wish to store logging state in some
kind of shared storage (global IORef or whatever), then you should think about
thread-safety by yourself.
Please refer to Haddock documentation and examples in the examples/
directory
for more detailed information.