AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Projekte Open Source "Logging Facade" für Pascal auf Github

Open Source "Logging Facade" für Pascal auf Github

Ein Thema von mjustin · begonnen am 27. Jan 2016 · letzter Beitrag vom 7. Feb 2016
Antwort Antwort
Seite 2 von 2     12
mjustin
Registriert seit: 14. Apr 2008
Unter https://github.com/michaelJustin/slf4p entwickle ich seit kurzem eine Open Source Bibliothek zur Integration von Logging Frameworks über eine Abstraktionsschicht ('Facade').

Wer schon mal schnuppern möchte, kann nun den Source Code und DUnit Tests von Github herunterladen. Für die Unit Tests wird das Log4D Open Source Framework benötigt, das auf Sourceforge gehostet wird.

Da die Logging Facade auch in einem oder zwei meiner anderen Projekte eingesetzt werden soll, wird unter anderem auch Free Pascal Unterstützung und FPCUnit Tests folgen.

Die Bibliothek steht unter der Apache 2.0 Lizenz. Über Vorschläge, welches (Open Source-) Logging Framework noch integriert werden sollte, freue ich mich natürlich.
 
Benutzerbild von Uwe Raabe
Uwe Raabe

 
Delphi 10.4 Sydney
 
#11
  Alt 30. Jan 2016, 08:49
Leider funktioniert das hier bei Delphi 2009 nicht im Fall von Interface - Methoden, der blaue Punkt bleibt bestehen:
Noch was: Mal abgesehen davon, daß inline in der DPR nicht funktioniert, könnte man für das Logger-Interface auch einen Wrapper-Record definieren, der die Aufrufe unter IFDEF an das Interface weiterreicht. Damit wird keine der inlined Record-Methoden aufgerufen, wenn das entsprechende IFDEF nicht zutrifft. Einziger etwas unschöner Nebeneffekt ist, daß eine nicht verwendete Variable T in Main angemeckert wird.

Delphi-Quellcode:
unit Unit58;

interface

{.$DEFINE Log}

type
  ILog = interface
  ['{76BA1F8A-D171-4817-BB3D-337295B03CE0}']
    procedure Log(AText: string);
  end;

  TLog = record
  private
    {$IFDEF Log}
    FLog: ILog;
    {$ENDIF}
  public
    procedure Init(const AName: string); inline;
    procedure Log(AText: string); inline;
  end;

implementation

type
  TLogConsole = class(TInterfacedObject, ILog)
  public
    procedure Log(AText: string);
  end;

procedure TLogConsole.Log(AText: string);
begin
  Writeln(AText);
end;

procedure TLog.Init(const AName: string);
begin
  {$IFDEF Log}
  // der Einfachheit halber
  FLog := TLogConsole.Create;
  {$ENDIF}
end;

procedure TLog.Log(AText: string);
begin
  {$IFDEF Log}
  if FLog <> nil then begin
    FLog.Log(AText);
  end;
  {$ENDIF}
end;

end.
Delphi-Quellcode:
program Project67;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  Unit58 in 'Unit58.pas';

procedure Main;
var
  T: TLog;
begin
  T.Init('TLogConsole');
  T.Log('Hallo Welt');
  Writeln('Wie geht''s?');
  Readln;
end;

begin
  Main;
end.
Uwe Raabe
  Mit Zitat antworten Zitat
mjustin

 
Delphi 2009 Professional
 
#12
  Alt 30. Jan 2016, 11:50
Noch was: Mal abgesehen davon, daß inline in der DPR nicht funktioniert, könnte man für das Logger-Interface auch einen Wrapper-Record definieren, der die Aufrufe unter IFDEF an das Interface weiterreicht. Damit wird keine der inlined Record-Methoden aufgerufen, wenn das entsprechende IFDEF nicht zutrifft. Einziger etwas unschöner Nebeneffekt ist, daß eine nicht verwendete Variable T in Main angemeckert wird.
Bei meinen Versuchen, ein 'NOP' Logger Implementierung des Logger Interfaces mit leeren Prozeduren zu schreiben und sie mit inline zu 'optimieren' hatte ich die blauen Punkte bei den Aufrufern. Ich teste es daher noch mal mit diesem Beispiel (in Delphi 2009). Vielen Dank für die Anregungen!
Michael
Michael Justin
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

 
Delphi 10 Seattle Enterprise
 
#13
  Alt 30. Jan 2016, 12:42
Wenn du einen Logger implementierst, dann musst du immer ganz schön viel Boilerplate-Code schreiben.

Da würde ich noch ein Interface mit Wrapper dazwischen schieben:
Delphi-Quellcode:
unit djLogWriter;

interface

uses
  System.SysUtils,
  djLogAPI;

type
  TLogLevel = ( llTrace, llDebug, llInfo, llWarn, llError );
  TLogLevels = set of TLogLevel;

type
  IWriteLog = interface
    procedure WriteMessage( const ALevel: TLogLevel; const AName, AMessage: string; const AException: Exception );
  end;

  TLogWriterWrapper = class( TInterfacedObject, ILogger )
  private { fields }
    FName : string;
    FWriter : IWriteLog;
    FLogFilter: TLogLevels;
    procedure SendToWriter( const ALevel: TLogLevel; const AMessage: string; const AException: Exception ); inline;
  private { ILogger }
    procedure Debug( const AMsg: string ); overload;
    procedure Debug( const AFormat: string; const AArgs: array of const ); overload;
    procedure Debug( const AMsg: string; const AException: Exception ); overload;

    procedure Error( const AMsg: string ); overload;
    procedure Error( const AFormat: string; const AArgs: array of const ); overload;
    procedure Error( const AMsg: string; const AException: Exception ); overload;

    procedure Info( const AMsg: string ); overload;
    procedure Info( const AFormat: string; const AArgs: array of const ); overload;
    procedure Info( const AMsg: string; const AException: Exception ); overload;

    procedure Warn( const AMsg: string ); overload;
    procedure Warn( const AFormat: string; const AArgs: array of const ); overload;
    procedure Warn( const AMsg: string; const AException: Exception ); overload;

    procedure Trace( const AMsg: string ); overload;
    procedure Trace( const AFormat: string; const AArgs: array of const ); overload;
    procedure Trace( const AMsg: string; const AException: Exception ); overload;

    function IsDebugEnabled: Boolean;
    function IsErrorEnabled: Boolean;
    function IsInfoEnabled: Boolean;
    function IsWarnEnabled: Boolean;
    function IsTraceEnabled: Boolean;

    function Name: string;
  public
    constructor Create( const AName: string; const AWriter: IWriteLog; const ALogFilter: TLogLevels );
  end;

implementation

{ TLogWriterWrapper }

constructor TLogWriterWrapper.Create( const AName: string; const AWriter: IWriteLog; const ALogFilter: TLogLevels );
begin
  inherited Create;
  FName := AName;
  FWriter := AWriter;
  FLogFilter := ALogFilter;
end;

procedure TLogWriterWrapper.Debug( const AMsg: string );
begin
  SendToWriter( llDebug, AMsg, nil );
end;

procedure TLogWriterWrapper.Debug( const AMsg: string; const AException: Exception );
begin
  SendToWriter( llDebug, AMsg, AException );
end;

procedure TLogWriterWrapper.Debug( const AFormat: string; const AArgs: array of const );
begin
  SendToWriter( llDebug, Format( AFormat, AArgs ), nil );
end;

procedure TLogWriterWrapper.Error( const AMsg: string );
begin
  SendToWriter( llError, AMsg, nil );
end;

procedure TLogWriterWrapper.Error( const AFormat: string; const AArgs: array of const );
begin
  SendToWriter( llError, Format( AFormat, AArgs ), nil );
end;

procedure TLogWriterWrapper.Error( const AMsg: string; const AException: Exception );
begin
  SendToWriter( llError, AMsg, AException );
end;

procedure TLogWriterWrapper.Info( const AFormat: string; const AArgs: array of const );
begin
  SendToWriter( llInfo, Format( AFormat, AArgs ), nil );
end;

procedure TLogWriterWrapper.Info( const AMsg: string );
begin
  SendToWriter( llInfo, AMsg, nil );
end;

procedure TLogWriterWrapper.Info( const AMsg: string; const AException: Exception );
begin
  SendToWriter( llInfo, AMsg, AException );
end;

function TLogWriterWrapper.IsDebugEnabled: Boolean;
begin
  Result := not( llDebug in FLogFilter );
end;

function TLogWriterWrapper.IsErrorEnabled: Boolean;
begin
  Result := not( llError in FLogFilter );
end;

function TLogWriterWrapper.IsInfoEnabled: Boolean;
begin
  Result := not( llInfo in FLogFilter );
end;

function TLogWriterWrapper.IsTraceEnabled: Boolean;
begin
  Result := not( llTrace in FLogFilter );
end;

function TLogWriterWrapper.IsWarnEnabled: Boolean;
begin
  Result := not( llWarn in FLogFilter );
end;

function TLogWriterWrapper.Name: string;
begin
  Result := FName;
end;

procedure TLogWriterWrapper.SendToWriter( const ALevel: TLogLevel; const AMessage: string; const AException: Exception );
begin
  if not( ALevel in FLogFilter )
  then
    FWriter.WriteMessage( ALevel, FName, AMessage, AException );
end;

procedure TLogWriterWrapper.Trace( const AMsg: string );
begin
  SendToWriter( llTrace, AMsg, nil );
end;

procedure TLogWriterWrapper.Trace( const AFormat: string; const AArgs: array of const );
begin
  SendToWriter( llTrace, Format( AFormat, AArgs ), nil );
end;

procedure TLogWriterWrapper.Trace( const AMsg: string; const AException: Exception );
begin
  SendToWriter( llTrace, AMsg, AException );
end;

procedure TLogWriterWrapper.Warn( const AMsg: string; const AException: Exception );
begin
  SendToWriter( llWarn, AMsg, AException );
end;

procedure TLogWriterWrapper.Warn( const AMsg: string );
begin
  SendToWriter( llWarn, AMsg, nil );
end;

procedure TLogWriterWrapper.Warn( const AFormat: string; const AArgs: array of const );
begin
  SendToWriter( llWarn, Format( AFormat, AArgs ), nil );
end;

end.
Mit einem Wrapper, kann man jetzt ganz kleine süße Log-Writer erstellen, die einfach nur IWriteLog implementieren.
  Mit Zitat antworten Zitat
mjustin

 
Delphi 2009 Professional
 
#14
  Alt 7. Feb 2016, 10:00
Wenn du einen Logger implementierst, dann musst du immer ganz schön viel Boilerplate-Code schreiben.
Mit einem Wrapper, kann man jetzt ganz kleine süße Log-Writer erstellen, die einfach nur IWriteLog implementieren.
Da stimme ich natürlich zu, das ist sicher (gerade für OOP Anhänger wie mich) eine Vereinfachung. Ich überlege aber auch, was für einen gelegentlichen Leser des Quellcodes angenehmer ist: den gesamten Quelltext in einer Unit mit 180 Zeilen zu studieren, oder den Code über zwei bis drei Vererbungsstufen auf drei Units verteilt, was beim Lesen etwas weniger "eindimensional" verläuft (eindimensional = Auf- und Abscrollen).

Unter diesem Aspekt müsste ich auch, um den Quellcode nicht unnötig kompliziert zu machen, die Logger Factory und deren Registrierung nicht auf zwei Units aufteilen sondern in einer einzigen Datei zusammenfassen. Dann gibt es je unterstütztem Framework nur eine statt zwei Units.

Aktuell sieht die Registrierungsunit z.B. für das Log4D Bindung so aus:

Delphi-Quellcode:
unit djLogOverLog4D;

{$IFDEF FPC}{$MODE DELPHI}{$ENDIF}

interface

implementation

uses
  djLoggerFactory, Log4DLogger;

initialization
  RegisterFactory(TLog4DLoggerFactory.Create);

end.
Diese Unit könnte problemlos mit dem Binding Code (Unit Log4DLogger) zusammengefasst werden.
Michael Justin
  Mit Zitat antworten Zitat
mjustin

 
Delphi 2009 Professional
 
#15
  Alt 7. Feb 2016, 10:18
SLF4P Update:

das Lazarus LCL Logging über LazLogger wird unterstützt und enthält Beispielprojekte ("Hello World") für das LazLogger Binding und für das Log4D Binding.

Logging over Log4D beschreibt wie das Log4D Framework initialisiert und konfiguriert wird.

Das Hello World Beispielprojekt für das Log4D Binding enthält mit LogConsoleAppender eine Unit mit einem Appender für Log4D, der die Logging Ausgaben auf der Konsole ausgibt.
Michael Justin
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:52 Uhr.
Powered by vBulletin® Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2020 by Daniel R. Wolf