Safe Haskell | Safe |
---|---|
Language | Haskell2010 |
Intended module usage:
import Di (Di) import qualified Di
- data Di path msg
- mkDi :: (MonadIO m, Monoid path) => (Level -> UTCTime -> path -> msg -> IO ()) -> m (Di path msg)
- push :: Di path msg -> path -> Di path msg
- path :: Di path' msg -> (path -> path') -> Di path msg
- msg :: Di path msg' -> (msg -> msg') -> Di path msg
- level :: Di path msg -> Level -> Di path msg
- data Level
- dbg :: MonadIO m => Di path msg -> msg -> m ()
- inf :: MonadIO m => Di path msg -> msg -> m ()
- wrn :: MonadIO m => Di path msg -> msg -> m ()
- err :: MonadIO m => Di path msg -> msg -> m ()
- dbg' :: MonadIO m => Di path msg -> msg -> m ()
- inf' :: MonadIO m => Di path msg -> msg -> m ()
- wrn' :: MonadIO m => Di path msg -> msg -> m ()
- err' :: MonadIO m => Di path msg -> msg -> m ()
- mkDiTextStderr :: MonadIO m => m (Di Text Text)
- mkDiTextFileHandle :: MonadIO m => Handle -> m (Di Text Text)
Documentation
allows you to to log messages of type Di
path msgmsg
, under a scope
identified by path
(think of path
as a filesystem path).
Each msg
gets logged together with its Level
, path
and the
UTCTime
timestamp stating when the logging requests was made.
Even though logging is usually associated with rendering text, Di
makes no
assumption about the types of the msg
values being logged, nor the path
values that convey their scope. Instead, it delays conversion from these
precise types into the ultimately desired raw representation as much as
possible. This makes it possible to log more precise information (for
example, logging a datatype of your own without having to convert it to text
first), richer scope paths (for example, the scope could be a
Map
that gets enriched with more information as we push
down the path
). This improves type safety, as well as the composability of
the path
and msg
values. In particular, path
and msg
are
contravariant values (see the path
and msg
functions).
Contrary to other logging approaches based on monadic interfaces, a Di
is a
value that is expected to be passed around explicitly. A Di
can be safely
used concurrently, and messages are rendered in the order they were submitted
for logging, both in the case of synchronous logging (e.g., err
) and
asynchronous logging (e.g., err'
).
Di
is pronounced as "dee" (not "die" nor "dye" nor "day"). "Di" is
the spanish word for an imperative form of the verb "decir", which in
english means "to say".
Build a Di
from a logging function.
push :: Di path msg -> path -> Di path msg Source #
Push a new path
to the Di
.
The passed in Di
can continue to be used even after using push
or the
returned Di
.
See mkDiTextStderr
for an example behaviour.
path :: Di path' msg -> (path -> path') -> Di path msg Source #
A Di
is contravariant in its path
argument.
This function is used to go from a more general to a more specific type
of path
. For example, [
is a more specific type than Int
][
,
since the former clearly conveys the idea of a list of numbers, whereas the
latter could be a list of anything that is representable as String
]String
, such as
dictionary words. We can convert from the more general to the more specific
path
type using this path
function:
path
(x ::Di
[String
] msg) (map
show
) ::Di
[Int
] msg
The Monoid
al behavior of the original path'
is preserved in the resulting
Di
.
msg :: Di path msg' -> (msg -> msg') -> Di path msg Source #
A Di
is contravariant in its msg
argument.
This function is used to go from a more general to a more specific type
of msg
. For example,
is a more specific type than Int
, since
the former clearly conveys the idea of a numbers, whereas the latter could be
a anything that is representable as String
String
, such as a dictionary word. We
can convert from the more general to the more specific msg
type using this
msg
function:
msg
(x ::Di
pathString
)show
::Di
pathInt
level :: Di path msg -> Level -> Di path msg Source #
Returns a new Di
on which messages below the given Level
are not
logged, where ther ordering of levels is as follow:
DBG
<INF
<WRN
<ERR
For example,
will prevent level
x WRN
DBG
and INF
from being logged.
Notice that
will allow messages with a level greater than or
equal to level
di xx
even if they had been previously silenced in the given di
.
Synchronous logging
Asynchronous logging
dbg' :: MonadIO m => Di path msg -> msg -> m () Source #
Asynchronously log a message with DBG
level by queueing it in FIFO
order to be logged in a different thread as soon as possible. The timestamp
of the logged message will correctly represent the time of the dbg'
call.
WARNING This function returns immediately, which makes it ideal for usage in tight loops. However, if logging the message fails later, you won't be able to catch the relevant exception.
inf' :: MonadIO m => Di path msg -> msg -> m () Source #
Asynchronously log a message with INF
level by queueing it in FIFO
order to be logged in a different thread as soon as possible. The timestamp
of the logged message will correctly represent the time of the inf'
call.
WARNING This function returns immediately, which makes it ideal for usage in tight loops. However, if logging the message fails later, you won't be able to catch the relevant exception.
wrn' :: MonadIO m => Di path msg -> msg -> m () Source #
Asynchronously log a message with WRN
level by queueing it in FIFO
order to be logged in a different thread as soon as possible. The timestamp
of the logged message will correctly represent the time of the wrn'
call.
WARNING This function returns immediately, which makes it ideal for usage in tight loops. However, if logging the message fails later, you won't be able to catch the relevant exception.
err' :: MonadIO m => Di path msg -> msg -> m () Source #
Asynchronously log a message with ERR
level by queueing it in FIFO
order to be logged in a different thread as soon as possible. The timestamp
of the logged message will correctly represent the time of the err'
call.
WARNING This function returns immediately, which makes it ideal for usage in tight loops. However, if logging the message fails later, you won't be able to catch the relevant exception.
Backends
mkDiTextStderr :: MonadIO m => m (Di Text Text) Source #
Text
is written to stderr
using the system's locale encoding.
> d0 <-mkDiTextStderr
>dbg
d0 "a" DBG 2017-05-06T19:01:27:306168750000Z: a > let d1 = push d0 "f/oo" -- '/' is converted to '.' >inf
d1 "b" INF 2017-05-06T19:01:27:314333636000Z f.oo: b > let d2 = push d1 "b ar" -- ' ' is converted to '_' >wrn
d2 "c" WRN 2017-05-06T19:01:27:322092498000Z f.oo/b_ar: c > let d3 = push d2 "qux" >err
d3 "d" ERR 2017-05-06T19:01:27:326704385000Z f.oo/b_ar/qux: d >err
d0 "e\nf" -- d0, of course, still works ERR 2017-05-06T19:01:27:823167007000Z: e\nf