Provide a proper logging effect that filters messages by log level before generating them.
3.4 KiB
Effects utilities
Contains utility functions extending the functionality of the eff
package.
module Util.Eff
import Control.Eff
import Text.ANSI
import System
import System.File
%default total
Logging
Log Levels
Basic enumeration describing log levels, we define some (hidden) utility functions for working with these.
public export
data Level = Err | Warn | Info | Debug | Trace | Other Nat
Convert a Level
into a colorized tag
export
levelToTag : Level -> String
levelToTag Err =
show . bolden . show . colored BrightRed $ "[Error]"
levelToTag Warn =
show . bolden . show . colored BrightYellow $ "[Warning]"
levelToTag Info =
show . bolden . show . colored Green $ "[Info]"
levelToTag Debug =
show . bolden . show . colored Magenta $ "[Debug]"
levelToTag Trace =
show . bolden . show . colored Cyan $ "[Trace]"
levelToTag (Other k) =
show . bolden . show . colored BrightWhite $ "[\{show k}]"
Logger effect
This is a basic data structure that captures a lazy log message (so we don't have to pay any of the costs associated with generating the log message when it is filtered)
public export
data Logger : Type -> Type where
Log : (level : Level) -> (msg : Lazy String) -> Logger ()
We'll also provide some basic accessors, and an ignore
function useful for writing handlers.
export
(.level) : Logger t -> Level
(.level) (Log level msg) = level
export
(.msg) : Logger t -> Lazy String
(.msg) (Log level msg) = msg
export
ignore : Logger t -> t
ignore (Log level msg) = ()
Handler
Because we know that we will only be using logger
in an IO
context, we aren't currently going to provide a runLogger
or the like, instead we'll define a function, suitable for use as a runEff
handler, that filters log messages and prints them to stderr
over IO
.
In the event a log message is filtered out, it's inner message is never inspected, avoiding evaluation.
export
handleLoggerIO :
(max_level : Level) -> Logger t -> IO t
handleLoggerIO max_level x =
if x.level <= max_level
then do
_ <- fPutStrLn stderr "\{levelToTag x.level}: \{x.msg}"
pure . ignore $ x
else pure . ignore $ x
Use the WriterL "log" String
effect like a logging library. We'll provide a few "log levels" as verbs for the effect, but no filtering is done, when logging is enabled, all logs are always displayed, however the log level is indicated with a colored tag.
export
error : Has Logger fs => Lazy String -> Eff fs ()
error x = send $ Log Err x
export
warn : Has Logger fs => Lazy String -> Eff fs ()
warn x = send $ Log Warn x
export
info : Has Logger fs => Lazy String -> Eff fs ()
info x = send $ Log Info x
export
debug : Has Logger fs => Lazy String -> Eff fs ()
debug x = send $ Log Debug x
export
trace : Has Logger fs => Lazy String -> Eff fs ()
trace x = send $ Log Trace x