co-log is a composable and configurable logging framework. It
combines all the benefits of Haskell idioms to provide a reasonable
and convenient interface. Although the library design uses some advanced
concepts in its core, we are striving to provide beginner-friendly API. The
library also provides the complete documentation with a lot of beginner-friendly
examples, explanations and tutorials to guide users. The combination of a
pragmatic approach to logging and fundamental Haskell abstractions allows us to
create a highly composable and configurable logging framework.
If you're interested in how different Haskell typeclasses are used to
implement core functions of co-log, you can read the following blog
post which goes into detail about the internal implementation specifics:
Logging library based on co-log-core
package. Provides ready-to-go implementation of logging. This README contains
How to tutorial on using this library. This tutorial explains step by step how
to integrate co-log into small basic project, specifically how to replace
putStrLn used for logging with library provided logging.
All code below can be compiled and run with the following commands:
$ cabal build
$ cabal exec readme
Preamble: imports and language extensions
Since this is a literate haskell file, we need to specify all our language
extensions and imports up front.
Consider the following function that reads lines from stdin and outputs
different feedback depending on the line size.
processLinesBasic::IO()
processLinesBasic =do
line <-TextIO.getLinecaseText.length line of0->do-- here goes loggingTextIO.putStrLn">>>> Empty input"
processLinesBasic
n ->doTextIO.putStrLn">>>> Correct input"TextIO.putStrLn$"Line length: "<>Text.pack (show n)
This code mixes application logic with logging of the steps. It's convenient to
have logging to observe behavior of the application. But putStrLn is very
simple and primitive way to log things.
Using co-log library
In order to use co-log library, we need to refactor processLinesBasic
function in the following way:
processLinesLog:: (WithLogenvMessagem, MonadIOm) =>m()
processLinesLog =do
line <- liftIO TextIO.getLinecaseText.length line of0->do-- here goes logging
logWarning "Empty input"
processLinesLog
n ->do
logDebug "Correct line"
logInfo $"Line length: "<>Text.pack (show n)
Let's summarize required changes:
Make type more polymorphic: (WithLog env Message m, MonadIO m) => m ()
Add liftIO to all IO functions.
Replace putStrLn with proper log* function.
Running actions
Let's run both functions:
main::IO()
main =do
processLinesBasic
let action = cmap fmtMessage logTextStdout
usingLoggerT action processLinesLog
And here is how output looks like:
More Tutorials
To provide a more user-friendly introduction to the library, we've
created the tutorial series which introduces the main concepts behind co-log
smoothly:
co-log also cares about concurrent logging. For this purpose we have the concurrent-playground
executable where we experiment with different multithreading scenarios to test the library's behavior.
You can find it here:
请发表评论