Skip to content

Code Based Configuration

jduquennoy edited this page Jul 8, 2016 · 13 revisions

Configuring the logging system by code

Pros

  • Allows you to change the configuration on the fly while running
  • Can be bound to a UI

Cons

  • Quite verbose when building complexe configurations, not super easy to get an overview of the configuration
  • Requires to build a UI to modify the configuration at run time
  • Not fully accessible in Objective-C

One line configuration (swift only)

One line configuration is available for some classical situations. All those configurations are set by calling one of the configureFor... methods of the LoggerFactory class. This is meant to simplify as much as possible the use for simple, typical situations.

  • configureForXcodeConsole(thresholdLevel: LogLevel = .Debug)
    will send logs to stderr, which means it will appear in Xcode's console when running your project from the IDE. Log will be colored if you have XcodeColors installed (dark red for fatal, red for error, orange for warning, blue for info, and grey for debug).
    This configuration is not meant to be used in a production environment.

  • configureForNSLogger(remoteHost: String = "127.0.0.1", remotePort: UInt32 = 50000, thresholdLevel: LogLevel = .Debug)
    will send logs to an NSLogger client. It will use and SSL connection, and local cache will be enabled.
    This configuration is not meant to be used in a production environment.

  • configureForSystemConsole(thresholdLevel: LogLevel = .Warning)
    will send logs to the system logging service, which means it will be available in the Console.app application, and in the system.log file.
    This configuration can fit a production use.

Configuration of loggers

Configuring the root logger

The root logger is the one that will be used in last resort if no other logger matches your requested identifier. Therefor, if you have to define only one logger, define this one : your settings will apply to all loggers you will request.

The root logger is created and hold by the logger factory. You cannot replace it, but you can change all aspects of its configuration, as you can for any logger you would create.

So configuring the root logger is exactly the same as configuring a custom logger (see bellow, but using the logger created by the factory :

let rootLogger = LoggerFactory.sharedInstance().rootLogger;
// insert here your custom configurations

Configuring a custom logger

You have two ways to create and configure a new logger :

  • using the factory to get a pre-configured and pre-registered logger
let newLogger = LoggerFactory.sharedInstance.getLogger("newLoggerIdentifier");
// insert here your custom configurations

The created logger's configuration will be based on the closest available logger (see documentation on The logger factory for more details), you will just have to customize it.

  • create a new one manually, and register it to the factory
let newLogger = Logger("newLoggerIdentifier);
// insert here your custom configurations
LoggerFactory.sharedInstance.registerLogger(newLogger);

The created logger will use a default empty configuration.

Properties to configure on a logger

  • identifier: requested by the init, it cannot be changed afterwards. See
  • appenders: defines where the logs will be sent
  • thresholdLevel: defines the log level below which logs will be ignored.
  • asynchronous: defines wether the messages sent to the logger should be handled synchronously or asynchronously. By default, loggers are synchronous.

Configuration of appenders

The only way to create appenders is the manual way : call its constructor. Once created, the appender can be added to a logger to be used.

let logger = LoggerFactory.sharedInstance.getLogger("alreadyConfiguredLogger");
let newAppender = StdOutAppender("stdOutAppender");
// insert here your appender configuration
logger.appenders = [newAppender];

All appenders have some base properties, and each kind of appender has its own ones. See the list of provided appenders for a complete list.

Properties common to all appenders

  • identifier: this identifier is used for the dictionary-based configuration, it is useless in the case of a code based configuration.
  • thresholdLevel: defines the log level below which logs will be ignored.
  • formatter: the optional formatter that will be used to process the messages before sending them to their final destination. If formatter is nil, the the message will be written to its destination without formatting.

Configuration of formatters

The only way to create formatters is the manual way : call its constructor. Once created, the formatter can be added to an appender to be used.

All formatters have an identifier (as for the appenders, that identifier is not used in the case of code-based configuration), and each kind of formatter has its own settings. See the list of provided formatters for a complete list.

let appender = StdOutAppender("stdOutAppender");
let consoleFormatter = PatternFormatter("consoleFormatter");
// insert here your formatter configuration
appender.formatter = consoleFormatter;

Complete example

In this example, we setup the logging system to issue all logs but debug ones to the console, and error logs to a specific file. A formatter is used to add the current date to the log entry, and a custom logger called "application.feature" is defined to also print its debug messages to the console.

let sharedFactory = LoggerFactory.sharedInstance;

let defaultFormatter = try! PatternFormatter(identifier: "default formatter", pattern: "%d - %m");

let stdOutAppender = StdOutAppender("stdOutAppender");
stdOutAppender.formatter = defaultFormatter;

let fileAppender = FileAppender(identifier: "fileAppender", filePath: "/var/log/errors.log");
fileAppender.formatter = defaultFormatter;
fileAppender.thresholdLevel = .Error;

sharedFactory.rootLogger.appenders = [stdOutAppender, fileAppender];
sharedFactory.rootLogger.thresholdLevel = .Info;

let debugLogger = sharedFactory.getLogger("application.feature");
debugLogger.thresholdLevel = .Debug;