-
Notifications
You must be signed in to change notification settings - Fork 15
Logging
Logging is the process of capturing observables and processing them, including eventual output to the console or in a file. Log files are managed by Log rotation that can be configured how many files to keep and how large they can become.
We distinguish between two levels of logging: first, the capturing of observables using the contra-tracer
package, second the processing and routing of LogObject
via the switchboard in package iohk-monitoring
.
package contra-tracer
The simple package contra-tracer
does not depend on further packages and thus is lightweight in integration into libraries. It defines the central type Tracer m a
as a contravariant functor that can be passed to functions that need tracing of observables.
package iohk-monitoring
The more complex package is iohk-monitoring
which does the processing and routing of traced objects. Its central type is Trace m a
which is an alias for Tracer m (LogObject a)
where the a stands for the type of textual messages, either Text
or String
. This is a tracer that passes around instances of LogObject
that contains everything a log message requires: timestamp, severity level, named context, traced content.
1.) timestamp is taken when the LogObject is created
2.) severity level is on of Debug, Info, Notice, Warning, Error, .. (see Severity)
3.) named context defines where in the call graph this message has originated. We can enter a named context with the function appendName
.
4.) the traced content is the payload the message carries. It is usually created from tracer transformers Tracer m (LogObject b) -> Tracer m a
To convert from a traced object of type a to a LogObject
, either an instance of ToJSON
is available or an instance of ToObject a
is required. These instances can be implemented as orphans in a quasi declarative style.
Furthermore, instances for DefineSeverity
and DefinePrivacyAnnotation
are required.
example for a data structure Pet
:
data Pet = Pet { name :: Text, age :: Int}
deriving (Show)
the ToObject
instance returns a JSON Object of different complexity, depending on the chosen verbosity:
instance ToObject Pet where
toObject MinimalVerbosity _ = emptyObject -- do not log
toObject NormalVerbosity (Pet _ _) =
mkObject [ "kind" .= String "Pet"]
toObject MaximalVerbosity (Pet n a) =
mkObject [ "kind" .= String "Pet"
, "name" .= toJSON n
, "age" .= toJSON a ]
the rendering of the representation of the data structure depends on a chosen formatting. The trStructured
transformer will call the toObject
function (see above):
instance Transformable Text IO Pet where
-- transform to JSON Object
trTransformer StructuredLogging verb tr = trStructured verb tr
-- transform to textual representation using |show|
trTransformer TextualRepresentation _v tr = Tracer $ \pet -> do
meta <- mkLOMeta Info Public
traceWith tr $ LogObject "pet" meta $ (LogMessage . pack . show) pet
trTransformer _ _verb _tr = nullTracer -- do not log
annotations (severity level, privacy) are defined with the following instances:
-- default privacy annotation: Public
instance DefinePrivacyAnnotation Pet
-- default severity: Debug
instance DefineSeverity Pet
The switchboard takes care of routing every traced object to its configured backend. It does so by looking up this information in the configuration for the context name of the LogObject
.
Several backends have been implemented, and user-defined ones can easily added.
(see list in https://github.com/input-output-hk/iohk-monitoring-framework/tree/master/iohk-monitoring/src/Cardano/BM/Backend)