Copyright | (c) 2019 Version Cloud |
---|---|
License | BSD3 |
Maintainer | Jorah Gao <gqk007@gmail.com> |
Stability | experimental |
Portability | portable |
Safe Haskell | None |
Language | Haskell2010 |
A python logging style log library.
A full example:
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TemplateHaskell #-}
module Main (main) where
import Data.Aeson.QQ.Simple (aesonQQ)
import Prelude hiding (error)
import Logging (runJson, debug, info, warn, error, fatal, logv)
main :: IO ()
main = runJson
manager app
myLogger = "MyLogger.Main"
app :: IO ()
app = do
$(debug) myLogger "this message should print into MyLogger"
$(info) myLogger "this message should print into MyLogger"
$(warn) myLogger "this message should print into MyLogger"
$(error) myLogger "this message should print into MyLogger"
$(fatal) myLogger "this message should print into MyLogger"
$(logv) myLogger "LEVEL 100" "this message should print into MyLogger"
-- The best practice is putting all config into a separate file,
-- e.g "Logging.json"
manager = [aesonQQ|{
"loggers": {
"root": {
"level": "DEBUG",
"handlers": ["console"],
"propagate": false
},
"MyLogger": {
"level": "INFO",
"filterer": ["MyLogger.Main"],
"handlers": ["file"],
"propagate": false
}
},
"handlers": {
"console": {
"type": "StreamHandler",
"stream": "stderr",
"level": "DEBUG",
"formatter": "defaultFormatter"
},
"file": {
"type": "FileHandler",
"level": "INFO",
"formatter": "defaultFormatter",
"file": "./default.log"
}
},
"formatters": {
"defaultFormatter": {
"fmt": "%(asctime)s - %(level)s - %(logger)s - %(pathname)s/%(filename)s:%(lineno)d] %(message)s"
}
}
}|]
Synopsis
- run :: Manager -> IO a -> IO a
- runJson :: Value -> IO a -> IO a
- jsonToManager :: Value -> IO Manager
- stderrHandler :: StreamHandler
- stdoutHandler :: StreamHandler
- defaultRoot :: Sink
- logv :: ExpQ
- debug :: ExpQ
- info :: ExpQ
- warn :: ExpQ
- error :: ExpQ
- fatal :: ExpQ
- class Handler a where
- getLevel :: a -> Level
- setLevel :: a -> Level -> a
- getFilterer :: a -> Filterer
- setFilterer :: a -> Filterer -> a
- getFormatter :: a -> Formatter
- setFormatter :: a -> Formatter -> a
- acquire :: a -> IO ()
- release :: a -> IO ()
- with :: a -> (a -> IO b) -> IO b
- emit :: a -> LogRecord -> IO ()
- flush :: a -> IO ()
- close :: a -> IO ()
- handle :: a -> LogRecord -> IO Bool
- data Manager = Manager {}
- data Sink = Sink {}
- data HandlerT where
- data StreamHandler = StreamHandler {}
- data Formatter = Formatter {}
- type Filterer = [Filter]
- data Filter = Filter {}
- data LogRecord = LogRecord {}
- newtype Level = Level Int
- type Logger = String
Documentation
run :: Manager -> IO a -> IO a Source #
Run a logging environment.
You should always write you application inside a logging environment.
- rename "main" function to "originMain" (or whatever you call it)
- write "main" as below
main :: IO () main = run manager originMain ...
runJson :: Value -> IO a -> IO a Source #
Run a logging environment from JSON Value
.
A combinator of run
and jsonToManager
.
stderrHandler :: StreamHandler Source #
A StreamHandler
bound to stderr
stdoutHandler :: StreamHandler Source #
A StreamHandler
bound to stdout
defaultRoot :: Sink Source #
Default root sink which is used by jsonToManager
when root is missed.
You can use it when you make Manager
manually.
Logging THs
Types
class Handler a where Source #
A type class that abstracts the characteristics of a Handler
getLevel, setLevel, getFilterer, setFilterer, getFormatter, setFormatter, acquire, release, emit, flush, close
getLevel :: a -> Level Source #
setLevel :: a -> Level -> a Source #
getFilterer :: a -> Filterer Source #
setFilterer :: a -> Filterer -> a Source #
getFormatter :: a -> Formatter Source #
setFormatter :: a -> Formatter -> a Source #
acquire :: a -> IO () Source #
release :: a -> IO () Source #
with :: a -> (a -> IO b) -> IO b Source #
Instances
Handler StreamHandler Source # | |
Defined in Logging.Types getLevel :: StreamHandler -> Level Source # setLevel :: StreamHandler -> Level -> StreamHandler Source # getFilterer :: StreamHandler -> Filterer Source # setFilterer :: StreamHandler -> Filterer -> StreamHandler Source # getFormatter :: StreamHandler -> Formatter Source # setFormatter :: StreamHandler -> Formatter -> StreamHandler Source # acquire :: StreamHandler -> IO () Source # release :: StreamHandler -> IO () Source # with :: StreamHandler -> (StreamHandler -> IO b) -> IO b Source # emit :: StreamHandler -> LogRecord -> IO () Source # flush :: StreamHandler -> IO () Source # close :: StreamHandler -> IO () Source # |
There is under normal circumstances just one Manager, which holds the hierarchy of sinks.
Sink
represents a single logging channel.
A "logging channel" indicates an area of an application. Exactly how an "area" is defined is up to the application developer. Since an application can have any number of areas, logging channels are identified by a unique string. Application areas can be nested (e.g. an area of "input processing" might include sub-areas "read CSV files", "read XLS files" and "read Gnumeric files"). To cater for this natural nesting, channel names are organized into a namespace hierarchy where levels are separated by periods, much like the Haskell module namespace. So in the instance given above, channel names might be Input for the upper level, and Input.Csv, Input.Xls and Input.Gnu for the sub-levels. There is no arbitrary limit to the depth of nesting.
Note: The namespaces are case sensitive.
A GADT represents any Handler
instance
data StreamHandler Source #
A handler type which writes logging records, appropriately formatted, to a stream.
Note that this class does not close the stream when the stream is a
terminal device, e.g. stderr
and stdout
.
Instances
Handler StreamHandler Source # | |
Defined in Logging.Types getLevel :: StreamHandler -> Level Source # setLevel :: StreamHandler -> Level -> StreamHandler Source # getFilterer :: StreamHandler -> Filterer Source # setFilterer :: StreamHandler -> Filterer -> StreamHandler Source # getFormatter :: StreamHandler -> Formatter Source # setFormatter :: StreamHandler -> Formatter -> StreamHandler Source # acquire :: StreamHandler -> IO () Source # release :: StreamHandler -> IO () Source # with :: StreamHandler -> (StreamHandler -> IO b) -> IO b Source # emit :: StreamHandler -> LogRecord -> IO () Source # flush :: StreamHandler -> IO () Source # close :: StreamHandler -> IO () Source # |
Formatter
s are used to convert a LogRecord to text.
Formatter
s need to know how a LogRecord
is constructed. They are
responsible for converting a LogRecord
to (usually) a string which can
be interpreted by either a human or an external system. The base Formatter
allows a formatting string to be specified. If none is supplied, the
default value, "%(message)s" is used.
The Formatter
can be initialized with a format string which makes use of
knowledge of the LogRecord
attributes - e.g. the default value mentioned
above makes use of a LogRecord'
s message attribute. Currently, the useful
attributes in a LogRecord
are described by:
%(logger)s
- Name of the logger (logging channel)
%(level)s
- Numeric logging level for the message (DEBUG, INFO, WARN, ERROR, FATAL, LEVEL v)
%(pathname)s
- Full pathname of the source file where the logging call was issued (if available)
%(filename)s
- Filename portion of pathname
%(module)s
- Module (name portion of filename)
%(lineno)d
- Source line number where the logging call was issued (if available)
%(created)f
- Time when the LogRecord was created (picoseconds since '1970-01-01 00:00:00')
%(asctime)s
- Textual time when the
LogRecord
was created %(msecs)d
- Millisecond portion of the creation time
%(message)s
- The main message passed to
logv
debug
info
..
Filter
s are used to perform arbitrary filtering of LogRecord
s.
Sink
s and Handler
s can optionally use Filter
to filter records
as desired. It allows events which are below a certain point in the
sink hierarchy. For example, a filter initialized with A.B will allow
events logged by loggers A.B, A.B.C, A.B.C.D, A.B.D etc.
but not A.BB, B.A.B etc.
If initialized name with the empty string, all events are passed.
A LogRecord
represents an event being logged.
LogRecord
s are created every time something is logged. They
contain all the information related to the event being logged.
It includes the main message as well as information such as when the record was created, the source line where the logging call was made.