The Simple Logging Facade for Pascal serves as a simple facade or abstraction for various logging frameworks (e.g. Log4D, LazLogger), allowing the end user to plug in the desired logging framework at build time.
Developed with Delphi 2009 and Lazarus 4.4, tested with DUnit and FPCUnit.
To register a specific logging framework, add one of the djLogOver... units to the project.
djLogOverNOPLoggerfor logging over NOPLoggerdjLogOverSimpleLoggerfor logging over SimpleLoggerdjLogOverLog4Dfor logging over Log4DdjLogOverLazLoggerfor logging over LazLogger
One of the LogOver... units must be added to the project. When no unit is added, a NOPLogger factory will be used as a fallback, and a message indicating the fallback will be printed.
Before deciding which logging tool to use, it’s important to understand what each one does.
SLF4P is not a logging implementation on its own. It’s an abstraction layer that lets you plug in a logging framework at runtime, such as Log4D or LazLogger. You write your code against the SLF4P API and then link it to a logging backend via the source path.
Log4D, by contrast, is a complete logging implementation. It provides its own APIs, configuration mechanisms for generating logs, and powerful built-in features, including filtering, custom appenders, and advanced formatting.
Since no unit for registering a logger factory is used, a factory for NOP loggers will be registered.
program HelloWorld;
uses
djLoggerFactory, djLogAPI;
procedure RunDemo;
var
Log: ILogger;
begin
Log := TLoggerFactory.GetLogger;
Log.Debug('Using slf4p %s', [SLF4P_VERSION]);
Log.Info('Hello, World!');
Log.Debug('Hit any key');
ReadLn;
end;
begin
RunDemo;
end.SLF4P: Logger factory is not assigned
SLF4P: Defaulting to no-operation (NOP) logger implementationThe first unit used, djLogOverSimpleLogger, registers a factory for console loggers.
program HelloWorld;
uses
djLogOverSimpleLogger,
djLoggerFactory, djLogAPI;
procedure RunDemo;
var
Log: ILogger;
begin
Log := TLoggerFactory.GetLogger;
Log.Debug('Using slf4p %s', [SLF4P_VERSION]);
Log.Info('Hello, World!');
Log.Debug('Hit any key');
ReadLn;
end;
begin
RunDemo;
end.[12:05:46.732] DEBUG - Using slf4p 1.0.8
[12:05:46.732] INFO - Hello, World!
[12:05:46.733] DEBUG - Hit any keyThe first unit used, djLogOverLog4D, registers a logger factory which created Log4D loggers.
program HelloWorld;
uses
djLogOverLog4D,
djLoggerFactory, djLogAPI,
LogConsoleAppender, Log4d;
procedure RunDemo;
var
Log: ILogger;
ConsoleAppender: ILogAppender;
begin
ConsoleAppender := TLogConsoleAppender.Create('console');
TLogBasicConfigurator.Configure(ConsoleAppender);
TLogLogger.GetRootLogger.Level := Debug;
WriteLn('Logging with Log4D version ' + Log4DVersion);
Log := TLoggerFactory.GetLogger('slf4p/log4d');
Log.Debug('Using slf4p %s', [SLF4P_VERSION]);
Log.Info('Hello, World!');
Log.Debug('Hit any key');
ReadLn;
end;
begin
RunDemo;
end.Logging with Log4D version 1.2.12
debug - Using slf4p 1.0.8
info - Hello, World!
debug - Hit any keyThe first unit used, djLogOverLazLogger, registers a logger factory which creates LazLogger loggers.
program HelloWorld;
uses
djLogOverLazLogger,
djLoggerFactory, djLogAPI;
var
Log: ILogger;
begin
Log := TLoggerFactory.GetLogger;
Log.Debug('Using slf4p %s', [SLF4P_VERSION]);
Log.Info('Hello, World!');
Log.Debug('Hit any key');
ReadLn;
end.0 DEBUG - Using slf4p 1.0.8
0 INFO - Hello, World!
0 DEBUG - Hit any keyThe example uses named loggers in the classes TFirstClass and TSecondClass. The logger is created in the constructor of each class, using the class type as a parameter for the GetLogger method. With the help of classic published RTTI, the example classes write their unit name and class name to the log.
program HelloWorld;
uses
djLogOverSimpleLogger, SimpleLogger,
djLoggerFactory, djLogAPI,
MyClasses in 'MyClasses.pas';
procedure RunDemo;
var
Log: ILogger;
Obj1: TFirstClass;
Obj2: TSecondClass;
begin
SimpleLogger.Configure('defaultLogLevel', 'trace');
SimpleLogger.Configure('showDateTime', 'false');
Log := TLoggerFactory.GetLogger;
Log.Info('Using slf4p %s', [SLF4P_VERSION]);
Obj1 := TFirstClass.Create;
Obj2 := TSecondClass.Create;
try
Log.Info('Instances created');
finally
Obj2.Free;
Obj1.Free;
end;
Log.Info('Hit any key');
ReadLn;
end;
begin
RunDemo;
end.With the help of classic published RTTI, the example classes write their unit name and class name to the log.
unit MyClasses;
interface
uses
djLoggerFactory, djLogAPI;
type
{$TYPEINFO ON}
TFirstClass = class(TObject)
private
Log: ILogger;
public
constructor Create;
destructor Destroy; override;
end;
TSecondClass = class(TFirstClass)
private
Log: ILogger;
public
constructor Create;
destructor Destroy; override;
end;
{$TYPEINFO OFF}
implementation
uses
slf4p;
{ TFirstClass }
constructor TFirstClass.Create;
begin
Log := TLoggerFactory.GetLogger(TFirstClass);
Log.Debug('in constructor');
end;
destructor TFirstClass.Destroy;
begin
Log.Debug('in destructor');
end;
{ TSecondClass }
constructor TSecondClass.Create;
begin
Log := TLoggerFactory.GetLogger(TSecondClass);
if Log.IsTraceEnabled then
Log.Trace('entering constructor');
inherited;
if Log.IsTraceEnabled then
Log.Trace('leaving constructor');
end;
destructor TSecondClass.Destroy;
begin
if Log.IsTraceEnabled then
Log.Trace('entering destructor');
inherited;
if Log.IsTraceEnabled then
Log.Trace('leaving destructor');
end;
end.0 INFO - Using slf4p 1.0.8
0 DEBUG MyClasses.TFirstClass in constructor
0 TRACE MyClasses.TSecondClass entering constructor
0 DEBUG MyClasses.TFirstClass in constructor
0 TRACE MyClasses.TSecondClass leaving constructor
0 INFO - Instances created
0 TRACE MyClasses.TSecondClass entering destructor
0 DEBUG MyClasses.TFirstClass in destructor
0 TRACE MyClasses.TSecondClass leaving destructor
0 DEBUG MyClasses.TFirstClass in destructor
0 INFO - Hit any key