public struct Logging
This type provides access to the App’s loggers.
Logging in Flint is slightly different and solves several problems:
- Excessively noisy logs in non-development builds (a separate logger for debug logging, always silenced in production)
- The inability to tell what actual user activity a log entry relates to (see: topic paths, contextual logging)
- The typical reliance on a specific logging framework. Wire up whatever implementation you like here.
- Focusing on logs only related to specific application features, e.g. drill down into just your
Abstracting logging is one of the more laughable and tedious things in computing, after all how many ways do we need to log text? However nothing out there supports contextual logging and topic paths which are crucial for Flint. So here we are.
Flint’s logging is somewhat decoupled from the rest of Flint and works like this:
- Something in the App calls
Logging.production.contextualLogger(...)to get a logger that has information about what the user is doing.
- The resulting
ContextSpecificLogger, if not nil is passed to subsystems that require logging. This is the biggest difference with other logging systems that assume the logger never changes.
- The subsystems call one of the logging functions on the logger.
ContextualLoggerdelegates the actual logging to a
ContextualLoggerTarget, which can filter events or log levels as desired
DefaultContextualLoggerTargetfilters events according to Focus rules, and sends output to a
LoggerOutputinstance which is the final output of the log text.
The chain of execution is along these lines:
LoggerOutput is the only think you need to implement for your logging framework, e.g. a layer that uses CocoaLumberjack or Apple’s log systems,
CLS_LOG rolling log buffer.
Production logging is always available, so that logger factory is not optional. Debug logging can be entirely disabled for production builds, resulting is close to zero overheads due to the optional dereferencing.
This solves the problem of polluting production logs with excessive internal debug info, without having to dial down log levels in production.
The implementation of
ContextualLoggerTarget can peform filtering of events by topic path or other properties of the
DefaultLogger) and those
ContextSpecificLogger implementations then pass the logging info on to the
LoggerOutput implementation which writes to whatever output you desire.
There is an
AggregatingLoggerOutput provided so you can compose multiple log outputs easily and drive them from
the same contextual loggers, e.g. to output to Console as well as an ASL log file.
DefaultLoggerFactory.setup()for the simple console logging used by default when using
Code using this logger always causes some overhead, as there must be a production logger set. Loggers should always test the log level first before evaluation the log text, so that @autoclosure can be used to avoid evaluation of the input data if the log level is not appropriate.
public static var production: ContextualLoggerFactory!