nxLogging Source Ansicht

Source Code Ansicht "nxLogging.pas"

Zur Ansicht: die Quellen von nxLogging, direkt im Browser:

{ **************************************************************************** }
{ ***** Dateiname               : nxLogging.pas ****************************** }
{ ***** Autor                   : Navimatix GmbH, Matthias Heunecke ********** }
{ ***** Erstellt am             : 08.07.2012 ********************************* }
{ ***** Letzte Änderung         : 05.05.2015 ********************************* }
{ ***** Zugehörigkeit           : nxLogging ********************************** }
{ ***** Beschreibung            : Enthält Klassen, Komponenten, Funktionen *** }
{ ******************************* für das Logging von Hinweisen, Fehlern,...** }
{ **************************************************************************** }
{ ***** Gruppe                  : Freeware *********************************** }
{ ******************************* Freie Nutzung privat und kommerziell ******* }
{ **************************************************************************** }
{ ***** Version                 : 1.3.1.1 ************************************ }
{ **************************************************************************** }
{ ***** Status                  : aktiv ************************************** }
{ **************************************************************************** }
{ ***** URL                     : https://www.navimatix.de ******************** }
{ ***** URL                     : https://www.navimatix.de/loesungen/log-server }
{ ***** Email                   : info@navimatix.de ************************** }
{ ***** Adresse                 : Navimatix GmbH, Moritz-von-Rohr-Str. 1a, *** }
{ *****                           07745 Jena, Germany ************************ }
{ **************************************************************************** }
{ ***** Tutorial:  https://www.navimatix.de/loesungen/log-server/ ************* }
{ *****            logging-fuer-delphi-nxlogging/tutorial/ ******************* }
{ **************************************************************************** }
unit nxLogging;
interface
uses Classes, Types, SyncObjs, SysUtils, IdTCPClient, IdThreadSafe;
const
/// 
/// Diese Konstante gibt die maximale Anzahl der zwischenzuspeichernden (auf Clientseite) Logeinträge an.
/// Beim Überlauf dieses Puffers gehen die weiteren Logeinträge verloren.
/// 
IC_DEFAULTMAXTCPENTRIES           = 5000;   // Maximale Anzahl an Logeinträgen
// für den TCP-Puffer
/// 
/// Gibt den Namensteil für eine Logdatei im Modus "NXLFS_SINGLEFILE" an.
/// 
SC_ALLFILETAIL                    = 'all';  // Additional Name-Part for single logfiles
/// 
/// Gibt den Namensteil der aktuellen Logdatei im Modus "NXLFS_RENAME" an.
/// 
SC_CURRENTFILETAIL                = 'current';  // Additional Name-Part for a current logfile
/// 
/// Gibt den Namensteil der bereits umbenannten Logdateien im Modus "NXLFS_RENAME" an.
/// 
SC_FILEFROM                       = 'from'; // Additional Name-Part for renamed logfiles
// Konstanten für nxLogProtokoll-TCP...
NXLOGPTCP_OK                            = 200;
NXLOGPTCP_BADREQUEST                    = 400;
NXLOGPTCP_UNAUTHORIZED                  = 401;
NXLOGPTCP_PAYMENTREQUIRED               = 402;
NXLOGPTCP_FORBIDDEN                     = 403;
NXLOGPTCP_NOTFOUND                      = 404;
NXLOGPTCP_METHODNOTALLOWED              = 405;
NXLOGPTCP_INTERNALSERVERERROR           = 500;
NXLOGPTCP_NOTIMPLEMENTED                = 501;
NXLOGPTCP_SERVICETEMPORARYUNAVAILABLE   = 503;
SC_WRONGSTRINGLENGTHSHOULDBEEVEN         =
'the string to convert is of wrong length, should be even.';
type
///  
///  
///  Die Werte dieser Enumeration definieren für einen Logentry die Kategorie, zu dieser gehört.
///  Die Kategorie kann optional bei den Methoden zum Loggen angegeben werden, default ist NONE.
///  
///  
TNxLoggerCategory = (   NXLCAT_NONE,
NXLCAT_OPTIONS,      // Fehler bei den Einstellungen
NXLCAT_RUNNING,      // Fehler während des "normalen" Laufens
NXLCAT_CALCULATING,  // Fehler während eine komplexen Rechenoperation.
NXLCAT_FASTRUNNING,  // Fehler während des Laufens, der jedoch extrem oft, oder ständig auftauchen kann.
NXLCAT_STARTUP,      // Fehler beim Erzeugen von Dingen
NXLCAT_SHUTDOWN,     // Fehler beim Aufräumen
NXLCAT_REFERENCE,    // ungültige, falsche Objektreferenz
NXLCAT_COM,          // Fehler im COM-Server
NXLCAT_DCOM,         // Fehler im DCOM-Server
NXLCAT_PLUGIN        // Fehler in einem Plugin
);
///  
///  
///  Die Werte dieser Enumeration definieren für einen Logentry das Level, zu dem dieser gehört.
///  Das Level ist nicht optional und muss immer mit angegeben werden.
///  Die Methoden trace(), info(), error(), etc... geben das entsprechende Level bereits vor.
///  
///  
TNxLoggerLevel    = (   NXLL_TRACE,       // ganz zartes Fehlerchen.. :-)
NXLL_DEBUG,       // Fehlerchen zum/beim Debuggen
NXLL_INFO,        // Information über Unregelmäßigkeit
NXLL_WARN,        // Warnung, es ist etwas unschönes passiert, aber keine Panik..
NXLL_ERROR,       // kritischer Fehler, kann Absturz zur Folge haben
NXLL_FATAL        // fataler Fehler, eigentlich hat es keinen Zweck mehr, Programm töten !
);
///  
///  
///  Das ist eine Menge von Logleveln, diese wird z.B. in Filtern genutzt.
///  
///  
TNxLoggerLevelSet = set of TNxLoggerLevel;
///  
///  
///  Diese Klasse kapselt eine Lognachricht. Jede Logausgabe erzeugt eine Instanz dieser Klasse und gibt diese intern an die
///  entsprechenden Appender weiter. Hier sind alle wichtigen Informationen zu einer Nachricht enthalten.
///  
///  
/// 
/// Eine solche Instanz kann selbst erzeugt werden, oder sie wird automatisch von den Methoden trace(), info(), etc... erzeugt.
/// Erbt von TPersistent und kann mit der Methode Assign() Inhalte (nicht nur die Referenz) einer anderen Instanz zuweisen.
/// 
TNxLoggerMessage = class(TPersistent)
private
fApplicationId      : String;
fInstanceId         : String;
fLogUser            : String;
fThreadId           : String;
fLevel              : TNxLoggerLevel;
fCategory           : String;
fModule             : String;
fMessage            : String;
fTimestamp          : TDateTime;
fException          : Exception;
fExceptionClassName : String;
fLanguage           : String;     // ISO 639-2
fStackTrace         : String;
protected
procedure AssignTo(Dest: TPersistent); override;
procedure setApplicationId(aValue : String);
procedure setInstanceId(aValue : String);
procedure setLogUser(aValue : String);
procedure setThreadId(aValue : String);
procedure setLevel(aValue  : TNxLoggerLevel);
procedure setCategory(aValue : String);
procedure setModule(aValue : String);
procedure setMessage(aValue  : String);
procedure setTimestamp(aValue  : TDateTime);
procedure setException(aValue  : Exception);
procedure setLanguage(aValue : String);
procedure setExceptionClassName(aValue : String);
procedure setStackTrace(aValue : String);
public
constructor Create(const aApplicationId, aInstanceId, aLogUser : String; aLevel : TNxLoggerLevel; const aMessage : String); overload; virtual;
constructor Create(const aApplicationId, aInstanceId, aLogUser : String; aLevel : TNxLoggerLevel; const aModule, aMessage : String; const aCategory, aLanguage : String; const aException : Exception); overload; virtual;
constructor Create(const aApplicationId, aInstanceId, aLogUser : String; aLevel : TNxLoggerLevel; const aModule, aMessage : String; const aCategory, aLanguage, aThreadId : String; const aException : Exception); overload; virtual;
destructor Destroy; override;
function getApplicationId       : String;
function getInstanceId          : String;
function getLogUser             : String;
function getThreadId            : String;
function getLevel               : TNxLoggerLevel;
function getCategory            : String;
function getModule              : String;
function getMessage             : String;
function getTimestamp           : TDateTime;
function getException           : Exception;
function getLanguage            : String;
function getExceptionClassName  : String;
function getStackTrace          : String;
property ApplicationId          : String read getApplicationId write setApplicationId;
property InstanceId             : String read getInstanceId write setInstanceId;
property LogUser                : String read getLogUser write setLogUser;
property ThreadId               : String read getThreadId write setThreadId;
property LogLevel               : TNxLoggerLevel read fLevel write setLevel;
property LogCategory            : String read fCategory write setCategory;
property LogModule              : String read getModule write setModule;
property LogMessage             : String read getMessage write setMessage;
property LogTimestamp           : TDateTime read getTimestamp write setTimestamp;
property LogException           : Exception read getException write setException;
property LogExceptionClassName  : String read getExceptionClassName write setExceptionClassName;
property Language               : String read getLanguage write setLanguage;
property StackTrace             : String read getStackTrace write setStackTrace;
end;
TNxLoggerMessageEvent = procedure(aSender : TObject; aMessage : TNxLoggerMessage) of object;
///  
///  
///  Das ist die Grundklasse für alle Filter. Weitere Filter müssen von dieser Klasse erben.
///  
///  
///  
///  
///  Die Methode match() muss überschrieben werden. Hier wird per Rückgabe definiert, ob die übergebene Nachricht zum Filter passt oder nicht.
///  
///  
///  Mit loadFromStream() und saveToStream erhält ein Filter die Möglichkeit persistent zu bleiben, oder übermittelt zu werden.
///  
///  
TNxLoggerMessageFilter = class(TPersistent)
public
procedure reset; virtual; abstract;
function  match(aMessage : TNxLoggerMessage) : Boolean; virtual; abstract;
procedure saveToStream(aStream : TStream); virtual; abstract;
procedure loadFromStream(aStream : TStream); virtual; abstract;
end;
///  
///  
///  Dieser Filter entscheidet nach einer Menge von LogLeveln. Ist das Loglevel der übergebenen Nachricht in der Menge enthalten, so
///  liefert match() true zurück.
///  
///  
///  
///  
///  Mit setLevelAndAbove() kann einfach eine untere Schwelle angegeben werden.
///  
///  
///  setLevel(), unsetLevel() und setLevelSet() dienen der Mengenverwaltung.
///  
///  
TNxLoggerMessageFilterLevelSet = class(TNxLoggerMessageFilter)
private
fLevelSet       : TNxLoggerLevelSet;
protected
procedure AssignTo(Dest: TPersistent); override;
public
constructor Create;
destructor Destroy; override;
procedure saveToStream(aStream : TStream); override;
procedure loadFromStream(aStream : TStream); override;
procedure setLevel(aLevel : TNxLoggerLevel);
procedure unsetLevel(aLevel : TNxLoggerLevel);
procedure setLevelAndAbove(aLevel : TNxLoggerLevel);
procedure setLevelSet(aLevelSet : TNxLoggerLevelSet);
function  isLevelInSet(aLevel : TNxLoggerLevel) : Boolean;
procedure reset; override;
function  match(aMessage : TNxLoggerMessage) : Boolean; override;
property LevelSet : TNxLoggerLevelSet read fLevelSet;
end;
///  
///  
///  Dieser Filter ist eine Grundklasse für alle, welche nach einem gegebenen Text entscheidet
///  Die Grundklasse hält lediglich den zu testenden Text als Attribut und Property.
///  Die abgeleiteten Klassen müssen die Methode match() überschreiben.
///  
///  
///  
///  
///  setText(), getText() und reset() dienen der Texthandhabung.
///  
///  
TNxLoggerMessageFilterByText = class(TNxLoggerMessageFilter)
private
fText     : String;
protected
procedure AssignTo(Dest: TPersistent); override;
public
constructor Create;
destructor Destroy; override;
procedure saveToStream(aStream : TStream); override;
procedure loadFromStream(aStream : TStream); override;
procedure setText(aValue : String);
function  getText : String;
procedure reset; override;
property FilterText : String read fText write fText;
end;
///  
///  
///  Dieser Filter ist ein Textfilter, er entscheidet nach TNxLoggerMessage.LogModule.
///  Dabei muss der Text darin gleich zum Filtertext sein.
///  
///  
///  
///  
///  Testeigenschaft der Nachricht ist: TNxLoggerMessage.LogModule
///  
///  
///  Der Textvergleich ist nicht case sensitive, Groß-Kleinschreibung ist egal.
///  
///  
TNxLoggerMessageFilterModuleEquals = class(TNxLoggerMessageFilterByText)
public
function  match(aMessage : TNxLoggerMessage) : Boolean; override;
end;
///  
///  
///  Dieser Filter ist ein Textfilter, er entscheidet nach TNxLoggerMessage.LogModule.
///  Dabei muss der Text darin mit dem Filtertext anfangen.
///  
///  
///  
///  
///  Testeigenschaft der Nachricht ist: TNxLoggerMessage.LogModule
///  
///  
///  Der Textvergleich ist nicht case sensitive, Groß-Kleinschreibung ist egal.
///  
///  
TNxLoggerMessageFilterModuleStarting = class(TNxLoggerMessageFilterByText)
public
function  match(aMessage : TNxLoggerMessage) : Boolean; override;
end;
///  
///  
///  Dieser Filter ist ein Textfilter, er entscheidet nach TNxLoggerMessage.LogModule.
///  Dabei muss der Filtertext irgendwo im LogModule enthalten sein.
///  
///  
///  
///  
///  Testeigenschaft der Nachricht ist: TNxLoggerMessage.LogModule
///  
///  
///  Der Textvergleich ist nicht case sensitive, Groß-Kleinschreibung ist egal.
///  
///  
TNxLoggerMessageFilterModuleContains = class(TNxLoggerMessageFilterByText)
public
function  match(aMessage : TNxLoggerMessage) : Boolean; override;
end;
///  
///  
///  Dieser Filter ist ein Textfilter, er entscheidet nach TNxLoggerMessage.LogMessage.
///  Dabei muss der Text darin gleich zum Filtertext sein.
///  
///  
///  
///  
///  Testeigenschaft der Nachricht ist: TNxLoggerMessage.LogMessage
///  
///  
///  Der Textvergleich ist nicht case sensitive, Groß-Kleinschreibung ist egal.
///  
///  
TNxLoggerMessageFilterMessageEquals = class(TNxLoggerMessageFilterByText)
public
function  match(aMessage : TNxLoggerMessage) : Boolean; override;
end;
///  
///  
///  Dieser Filter ist ein Textfilter, er entscheidet nach TNxLoggerMessage.LogMessage.
///  Dabei muss der Text darin mit dem Filtertext anfangen.
///  
///  
///  
///  
///  Testeigenschaft der Nachricht ist: TNxLoggerMessage.LogMessage
///  
///  
///  Der Textvergleich ist nicht case sensitive, Groß-Kleinschreibung ist egal.
///  
///  
TNxLoggerMessageFilterMessageStarting = class(TNxLoggerMessageFilterByText)
public
function  match(aMessage : TNxLoggerMessage) : Boolean; override;
end;
///  
///  
///  Dieser Filter ist ein Textfilter, er entscheidet nach TNxLoggerMessage.LogMessage.
///  Dabei muss der Filtertext irgendwo im LogModule enthalten sein.
///  
///  
///  
///  
///  Testeigenschaft der Nachricht ist: TNxLoggerMessage.LogMessage
///  
///  
///  Der Textvergleich ist nicht case sensitive, Groß-Kleinschreibung ist egal.
///  
///  
TNxLoggerMessageFilterMessageContains = class(TNxLoggerMessageFilterByText)
public
function  match(aMessage : TNxLoggerMessage) : Boolean; override;
end;
///  
///  
///  Dieser Filter ist ein Textfilter, er entscheidet nach TNxLoggerMessage.MachineIdent.
///  Dabei muss der Text darin gleich zum Filtertext sein.
///  
///  
///  
///  
///  Testeigenschaft der Nachricht ist: TNxLoggerMessage.MachineIdent
///  
///  
///  Der Textvergleich ist nicht case sensitive, Groß-Kleinschreibung ist egal.
///  
///  
TNxLoggerMessageFilterMachineEquals = class;
TNxLoggerMessageFilterMachineEqualsMIREvent = procedure(Sender : TNxLoggerMessageFilterMachineEquals; LogMessage : TNxLoggerMessage; var MachineIdent : String) of object;
TNxLoggerMessageFilterMachineEquals = class(TNxLoggerMessageFilterByText)
private
fOnMachineIdentRequired       : TNxLoggerMessageFilterMachineEqualsMIREvent;
protected
procedure AssignTo(Dest: TPersistent); override;
public
function  match(aMessage : TNxLoggerMessage) : Boolean; override;
property OnMachineIdentRequired       : TNxLoggerMessageFilterMachineEqualsMIREvent read fOnMachineIdentRequired write fOnMachineIdentRequired;
end;
///  
///  
///  Dieser Filter ist ein Textfilter, er entscheidet nach TNxLoggerMessage.ApplicationId.
///  Dabei muss der Text darin gleich zum Filtertext sein.
///  
///  
///  
///  
///  Testeigenschaft der Nachricht ist: TNxLoggerMessage.ApplicationId
///  
///  
///  Der Textvergleich ist nicht case sensitive, Groß-Kleinschreibung ist egal.
///  
///  
TNxLoggerMessageFilterApplicationEquals = class(TNxLoggerMessageFilterByText)
public
function  match(aMessage : TNxLoggerMessage) : Boolean; override;
end;
///  
///  
///  Das ist die Grundklasse aller LogFormater. Diese haben die Aufgabe, eine
///  Lognachricht nach bestimmten Kriterien zu formatieren. Entweder eine Lognachricht in
///  einen String (formatMessage()), oder einen String zurück in eine Lognachricht (parseMessage()).
///  
///  
///  
///  
///  Die Klassenmethoden "convert***()" dienen der Umwandlung von Level, bzw. Kategorie in Strings und zurück.
///  
///  
TNxLogFormater = class(TPersistent)
public
function  formatMessage(aMessage : TNxLoggerMessage) : String; virtual; abstract;
function  parseMessage(aMessageText : String) : TNxLoggerMessage; virtual; abstract;
function  formatMessageBase64(aMessage : TNxLoggerMessage) : String; virtual; abstract;
function  parseMessageBase64(aMessageText : String) : TNxLoggerMessage; virtual; abstract;
class function convertToLevel(aString : String) : TNxLoggerLevel;
class function convertLevelToString(const aLevel : TNxLoggerLevel; const isException : Boolean = false) : String;
class function convertToCategory(aString : String) : TNxLoggerCategory;
class function convertCategoryToString(const aCategory : TNxLoggerCategory) : String;
end;
///  
///  
///  Dieser LogFormater dient als Grundlage für unbekannte Log-Formate.
///  Die einzelnen Werte einer Lognachricht werden eventuell mit "|" getrennt,
///  werden aber nicht danach getrennt.
///  die Lognachrichten selbst müssen mit CR LF getrennt sein.
///  
///  
///  Format: Die ganze Zeile geht in "Message"
///  
///  
///  
///  
///  LogFormater haben die Aufgabe, eine Lognachricht nach bestimmten Kriterien zu formatieren.
///  Entweder eine Lognachricht in einen String (formatMessage()), oder einen String zurück in eine Lognachricht (parseMessage()).
///  
///  
///  Es existieren jeweils Varianten zur Base64-kodierung der Teilwerte, ACHTUNG!
///  Hier wird nicht der ganze String kodiert, nur die Teile applicationid, module und message.
///  
///  
TNxLogFormaterPlain = class(TNxLogFormater)
private
fFormatSettings   : TFormatSettings;
public
constructor Create;
destructor Destroy; override;
function  formatMessage(aMessage : TNxLoggerMessage) : String; override;
function  formatMessageBase64(aMessage : TNxLoggerMessage) : String; override;
function  parseMessage(aMessageText : String) : TNxLoggerMessage; override;
function  parseMessageBase64(aMessageText : String) : TNxLoggerMessage; override;
end;
///  
///  
///  Dieser LogFormater dient als Standard, z.B. für Dateien.
///  Die einzelnen Werte einer Lognachricht werden jeweils mit "|" getrennt,
///  die Lognachrichten selbst mit CR LF.
///  
///  
///  Format: applicationid|timestamp|level.module|messagetext
///  
///  
///  
///  
///  LogFormater haben die Aufgabe, eine Lognachricht nach bestimmten Kriterien zu formatieren.
///  Entweder eine Lognachricht in einen String (formatMessage()), oder einen String zurück in eine Lognachricht (parseMessage()).
///  
///  
///  Es existieren jeweils Varianten zur Base64-kodierung der Teilwerte, ACHTUNG!
///  Hier wird nicht der ganze String kodiert, nur die Teile applicationid, module und message.
///  
///  
TNxLogFormaterDefault = class(TNxLogFormater)
private
fFormatSettings   : TFormatSettings;
public
constructor Create;
destructor Destroy; override;
function  formatMessage(aMessage : TNxLoggerMessage) : String; override;
function  formatMessageBase64(aMessage : TNxLoggerMessage) : String; override;
function  parseMessage(aMessageText : String) : TNxLoggerMessage; override;
function  parseMessageBase64(aMessageText : String) : TNxLoggerMessage; override;
end;
///  
///  
///  Dieser LogFormater dient zur Übermittlung von Lognachrichten per Netzwerk.
///  Die einzelnen Werte einer Lognachricht werden jeweils mit "|" getrennt,
///  die Lognachrichten selbst mit CR LF.
///  
///  
///  Dieser Formater führt einen Wert "MachineIdent" neu ein, dieser soll einen
///  eindeutigen Wert beinhalten, welcher den Logclient identifiziert, z.B. der Rechnername.
///  Da hier die Lognachrichten per Netzwerk übertragen werden, ist es wichtig von wo diese kommen.
///  
///  
///  Format: applicationid|timestamp|level.module|messagetext
///  
///  
///  
///  
///  Es existieren jeweils Varianten zur Base64-kodierung der Teilwerte, ACHTUNG!
///  Hier wird nicht der ganze String kodiert, nur die Teile applicationid, module und message.
///  
///  
///  Bei den format***()-Methoden wird der Wert "MachineIdent" mit in den String kodiert, da dieser beim Parsen auch
///  verfügbar sein muss, gibt es die beiden zusätzlichen parse***()-Methoden mir den Rückgabeparametern "ResMachineIdent".
///  Beim Aufruf wird hier der im String kodierte MachineIdent-Wert übergeben.
///  
///  
///  LogFormater haben die Aufgabe, eine Lognachricht nach bestimmten Kriterien zu formatieren.
///  Entweder eine Lognachricht in einen String (formatMessage()), oder einen String zurück in eine Lognachricht (parseMessage()).
///  
///  
TNxLogFormaterTCP = class(TNxLogFormater)
private
fFormatSettings   : TFormatSettings;
fMachineIdent     : String;
public
constructor Create;
destructor Destroy; override;
function  formatMessage(aMessage : TNxLoggerMessage) : String; override;
function  formatMessageBase64(aMessage : TNxLoggerMessage) : String; override;
function  formatMessageExtra(aMessage : TNxLoggerMessage; aExtraDataId : Int64; aExtraData : TBytes) : String;
function  formatMessageExtraBase64(aMessage : TNxLoggerMessage; aExtraDataId : Int64; aExtraData : TBytes) : String;
function  parseMessage(aMessageText : String) : TNxLoggerMessage; override;
function  parseMessageBase64(aMessageText : String) : TNxLoggerMessage; override;
function  parseMessageMachine(aMessageText : String; var ResMachineIdent : String) : TNxLoggerMessage;
function  parseMessageMachineBase64(aMessageText : String; var ResMachineIdent : String) : TNxLoggerMessage;
function  parseMessageMachineExtra(aMessageText : String; var ResMachineIdent : String; var ResExtraID : Int64; var ResExtra : TBytes) : TNxLoggerMessage;
function  parseMessageMachineExtraBase64(aMessageText : String; var ResMachineIdent : String; var ResExtraID : Int64; var ResExtra : TBytes) : TNxLoggerMessage;
property MachineIdent     : String read fMachineIdent write fMachineIdent;
end;
TNxLogAppender = class(TComponent)
private
public
procedure append(const aEvent : TNxLoggerMessage); virtual; abstract;
end;
TNxLogAppenderFileStrategy = (NXLFS_SINGLEFILE, NXLFS_NEWFILES, NXLFS_RENAME);
TNxLogAppenderFile = class(TNxLogAppender)
private
fFormater       : TNxLogFormater;
fFormatSettings : TFormatSettings;
fDirectory      : String;
fFilenameBase   : String;
fRetryCount     : Integer;
fStrategy       : TNxLogAppenderFileStrategy;
fLastDate       : TDate;
protected
function  isNextDay : Boolean;
procedure appendSingleFile(const aEvent : TNxLoggerMessage); virtual;
procedure appendNewFiles(const aEvent : TNxLoggerMessage); virtual;
procedure appendRename(const aEvent : TNxLoggerMessage); virtual;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure append(const aEvent : TNxLoggerMessage); override;
property Strategy : TNxLogAppenderFileStrategy read fStrategy write fStrategy;
end;
TNxLogger = class;
TNxLogAppenderChain = class(TNxLogAppender)
private
fChainedLogger    : TNxLogger;
protected
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure append(const aEvent : TNxLoggerMessage); override;
property ChainedLogger : TNxLogger read fChainedLogger write fChainedLogger;
end;
INxLogAppenderTCPThreadAdapter = interface
['{0B98E7CF-DA90-4FC2-A530-F5516DF0CCA7}']
function  consumeEntry : String;
end;
TNxLogAppenderTCPThread = class(TThread)
private
fTCP            : TIdTCPClient;
fFormatSettings : TFormatSettings;
fMachineIdent   : String;
fHostOrIP       : String;
fPort           : Integer;
fRetryCount     : Integer;
fUsername       : String;
fPassword       : String;
fAdapter        : INxLogAppenderTCPThreadAdapter;
protected
procedure Execute; override;
public
constructor Create(CreateSuspended: Boolean);
destructor Destroy; override;
property FormatSettings : TFormatSettings read fFormatSettings write fFormatSettings;
property MachineIdent   : String read fMachineIdent write fMachineIdent;
property HostOrIP       : String read fHostOrIP write fHostOrIP;
property Port           : Integer read fPort write fPort;
property RetryCount     : Integer read fRetryCount write fRetryCount;
property Username       : String read fUsername write fUsername;
property Password       : String read fPassword write fPassword;
property Adapter        : INxLogAppenderTCPThreadAdapter read fAdapter write fAdapter;
end;
TNxLogAppenderOverflowEvent = procedure(aMaxCount : Integer) of object;
TNxLogAppenderTCP = class(TNxLogAppender, INxLogAppenderTCPThreadAdapter)
private
fFormatSettings : TFormatSettings;
fMachineIdent   : String;
fHostOrIP       : String;
fPort           : Integer;
fRetryCount     : Integer;
fUsername       : String;
fPassword       : String;
fMaxEntries     : TIdThreadSafeInteger;
fLevelFilter    : TNxLoggerMessageFilterLevelSet;
fUserFilter     : TNxLoggerMessageFilter;
fFormater       : TNxLogFormaterTCP;
fBuffer         : TIdThreadSafeStringList;
fWorker         : TNxLogAppenderTCPThread;
fOnOverflow     : TNxLogAppenderOverflowEvent;
procedure setMachineIdent(aIdent : String);
procedure setMaxEntries(aValue : Integer);
function  getMaxEntries : Integer;
function  getCurrentEntries : Integer;
protected
function  consumeEntry : String; virtual;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function  isStarted : Boolean;
procedure start; virtual;
procedure stop; virtual;
procedure clearBuffer; virtual;
procedure append(const aEvent : TNxLoggerMessage); override;
property LevelFilter    : TNxLoggerMessageFilterLevelSet read fLevelFilter;
property UserFilter     : TNxLoggerMessageFilter read fUserFilter write fUserFilter;
property MaxEntries     : Integer read getMaxEntries write setMaxEntries;
property CurrentEntries : Integer read getCurrentEntries;
property OnOverflow     : TNxLogAppenderOverflowEvent read fOnOverflow write fOnOverflow;
end;
TNxLoggerCollectionItem = class(TCollectionItem)
private
fAppender   : TNxLogAppender;
public
constructor Create(Collection: TCollection); override;
destructor Destroy; override;
procedure append(const aEvent : TNxLoggerMessage);
published
property Appender   : TNxLogAppender read fAppender write fAppender;
end;
TNxLoggerCollection = class(TCollection)
private
protected
public
published
end;
TNxLoggerLogEvent = procedure(const aLevel : TNxLoggerLevel; const aModule, aMessage : String; aCategory : TNxLoggerCategory; aException : Exception; aLanguage : String) of object;
INxLogger = interface
['{95CD2F15-2680-4740-9EC2-DEBDC79021DC}']
procedure log(const aEvent : TNxLoggerMessage); overload;
procedure log(const aLevel : TNxLoggerLevel; const aMessage : String); overload;
procedure log(const aLevel : TNxLoggerLevel; const aModule, aMessage : String); overload;
procedure log(const aLevel : TNxLoggerLevel; const aModule, aMessage : String; const aCategory : TNxLoggerCategory; const aException : exception); overload;
procedure log(const aLevel : TNxLoggerLevel; const aModule, aMessage : String; const aCategoryAsString : String; const aException : exception); overload;
procedure log(const aLevel : TNxLoggerLevel; const aModule, aMessage : String; const aCategoryAsString, aLanguage : String; const aException : exception); overload;
procedure fatal(const aMessage : String); overload;
procedure fatal(const aModule, aMessage : String); overload;
procedure fatal(const aModule, aMessage : String; const aCategory : TNxLoggerCategory; const aException : exception = nil); overload;
procedure error(const aMessage : String); overload;
procedure error(const aModule, aMessage : String); overload;
procedure error(const aModule, aMessage : String; const aCategory : TNxLoggerCategory; const aException : exception = nil); overload;
procedure warn(const aMessage : String); overload;
procedure warn(const aModule, aMessage : String); overload;
procedure warn(const aModule, aMessage : String; const aCategory : TNxLoggerCategory; const aException : exception = nil); overload;
procedure info(const aMessage : String); overload;
procedure info(const aModule, aMessage : String); overload;
procedure info(const aModule, aMessage : String; const aCategory : TNxLoggerCategory; const aException : exception = nil); overload;
procedure debug(const aMessage : String); overload;
procedure debug(const aModule, aMessage : String); overload;
procedure debug(const aModule, aMessage : String; const aCategory : TNxLoggerCategory; const aException : exception = nil); overload;
procedure trace(const aMessage : String); overload;
procedure trace(const aModule, aMessage : String); overload;
procedure trace(const aModule, aMessage : String; const aCategory : TNxLoggerCategory; const aException : exception = nil); overload;
function  isTrace : Boolean;
function  isDebug : Boolean;
function  isInfo  : Boolean;
function  isWarn  : Boolean;
function  isError : Boolean;
function  isFatal : Boolean;
end;
TNxLogger = class(TComponent, INxLogger)
private
fCSLog                : TCriticalSection;
fLogFormatSettings    : TFormatSettings;
fApplicationID        : String;
fInstanceID           : String;
fUserIdent            : String;
fLanguage             : String;
fCurrentLevel         : TNxLoggerLevel;
fCSCurrentLevel       : TCriticalSection;
fAppenders            : TNxLoggerCollection;
fFilters              : TIdThreadSafeList;
fOnAppend             : TNxLoggerMessageEvent;
fOnLog                : TNxLoggerMessageEvent;
function  getAppenderCount : Integer;
function  getAppender(aIndex : Integer) : TNxLogAppender;
function  getCurrentLevel : TNxLoggerLevel;
procedure setCurrentLevel(aLevel : TNxLoggerLevel);
protected
function  matchFilters(const aEvent : TNxLoggerMessage) : Boolean; virtual;
function  getMachineIdent : String; virtual;
public
constructor Create(AOwner : TComponent); override;
destructor  Destroy; override;
class function isImportantLogLevel(const aRelativeBaseLevel, aLevelToTest : TNxLoggerLevel) : Boolean;
procedure initializeFileLogging(const aApplicationId, aLogDirectory, aBaseFilename : String; aRetryCount : Integer = 10; aStrategy : TNxLogAppenderFileStrategy = NXLFS_NEWFILES);
procedure initializeServerTCPLogging(const aApplicationId, aHostOrIP : String; aPort : Integer; aMachineIdent : String = ''; aRetryCount : Integer = 10; aUsername : String = ''; aPassword : String = ''; aLevelFilter : TNxLoggerLevelSet = [NXLL_FATAL, NXLL_ERROR, NXLL_WARN]);
procedure addAppender(aAppender : TNxLogAppender);
function  deleteAppender(aIndex : Integer) : TNxLogAppender;
procedure clearAppenders;
procedure log(const aEvent : TNxLoggerMessage); overload;
procedure log(const aLevel : TNxLoggerLevel; const aMessage : String); overload;
procedure log(const aLevel : TNxLoggerLevel; const aModule, aMessage : String); overload;
procedure log(const aLevel : TNxLoggerLevel; const aModule, aMessage : String; const aCategory : TNxLoggerCategory; const aException : exception); overload;
procedure log(const aLevel : TNxLoggerLevel; const aModule, aMessage : String; const aCategoryAsString : String; const aException : exception); overload;
procedure log(const aLevel : TNxLoggerLevel; const aModule, aMessage : String; const aCategoryAsString, aLanguage : String; const aException : exception); overload;
procedure fatal(const aMessage : String); overload;
procedure fatal(const aModule, aMessage : String); overload;
procedure fatal(const aModule, aMessage : String; const aCategory : TNxLoggerCategory; const aException : exception = nil); overload;
procedure error(const aMessage : String); overload;
procedure error(const aModule, aMessage : String); overload;
procedure error(const aModule, aMessage : String; const aCategory : TNxLoggerCategory; const aException : exception = nil); overload;
procedure warn(const aMessage : String); overload;
procedure warn(const aModule, aMessage : String); overload;
procedure warn(const aModule, aMessage : String; const aCategory : TNxLoggerCategory; const aException : exception = nil); overload;
procedure info(const aMessage : String); overload;
procedure info(const aModule, aMessage : String); overload;
procedure info(const aModule, aMessage : String; const aCategory : TNxLoggerCategory; const aException : exception = nil); overload;
procedure debug(const aMessage : String); overload;
procedure debug(const aModule, aMessage : String); overload;
procedure debug(const aModule, aMessage : String; const aCategory : TNxLoggerCategory; const aException : exception = nil); overload;
procedure trace(const aMessage : String); overload;
procedure trace(const aModule, aMessage : String); overload;
procedure trace(const aModule, aMessage : String; const aCategory : TNxLoggerCategory; const aException : exception = nil); overload;
function  isTrace : Boolean;
function  isDebug : Boolean;
function  isInfo  : Boolean;
function  isWarn  : Boolean;
function  isError : Boolean;
function  isFatal : Boolean;
property AppenderCount  : Integer read getAppenderCount;
property Appenders[index : Integer] : TNxLogAppender read getAppender;
property CurrentLevel         : TNxLoggerLevel read getCurrentLevel write setCurrentLevel;
property OnAppend             : TNxLoggerMessageEvent read fOnAppend write fOnAppend;
property OnLog                : TNxLoggerMessageEvent read fOnLog write fOnLog;
end;
ENxLoggingConvertError  = class(Exception)
end;
// ***** Funktionen und Prozeduren...
procedure Register;
procedure initLoggerFormatSettings(var FormatSettings : TFormatSettings);
function Logger : TNxLogger;
implementation
uses Windows, IdHashMessageDigest, IdGlobal, IdCoderMIME, TypInfo, Math,
DateUtils;
var
fDefaultLogger : TNxLogger;
{ **************************************************************************** }
{ ***** allgemeine Funktionen ************************************************ }
{ **************************************************************************** }
procedure Register;
begin
RegisterComponents('Logging', [TNxLogger]);
end;
function NowUTC: TDateTime;
var
SystemTime: TSystemTime;
begin
GetSystemTime(SystemTime);
Result := SystemTimeToDateTime (SystemTime);
end;
function decodeBase64(const EncodedText: string): String;
var cCoder: TIdDecoderMIME;
zs8   : UTF8String;
begin
cCoder := TIdDecoderMIME.Create(nil);
try
zs8  := UTF8String(cCoder.DecodeString(EncodedText));
result  := String(zs8);
finally
FreeAndNil(cCoder);
end;
end;
{$if CompilerVersion > 24}
function encodeBase64(const aText: string): String;
var cCoder: TIdEncoderMIME;
begin
cCoder := TIdEncoderMIME.Create(nil);
try
result  := cCoder.EncodeString(aText, IndyTextEncoding_UTF8);
finally
FreeAndNil(cCoder);
end;
end;
{$else}
function encodeBase64(const aText: string): String;
var cCoder: TIdEncoderMIME;
begin
cCoder := TIdEncoderMIME.Create(nil);
try
result  := cCoder.EncodeString(aText, TEncoding.UTF8);
finally
FreeAndNil(cCoder);
end;
end;
{$ifend}
function convertBytesToString(aBytes : TBytes) : String;
var zbr: RawByteString;
pas, pad: PAnsiChar;
begin
setlength(zbr, length(aBytes) * 2);
pas := PAnsiChar(@aBytes[0]);
pad := PAnsiChar(@zbr[1]);
BinToHex(pas, pad, length(aBytes));
result := trim(String(zbr));
end;
function convertStringToBytes(aString : String) : TBytes;
var size, len     : longint;
pc            : PByte;
begin
len := length(aString);
if (len mod 2) = 0 then
begin
// ok...
size  := len div 2;
setlength(result, size);
pc  := @result[0];
HexToBin(pchar(aString), pc, size);
end else
begin
raise ENxLoggingConvertError.Create(SC_WRONGSTRINGLENGTHSHOULDBEEVEN);
end;
end;
function _TryStrToDateTime(const S: string; out Value: TDateTime; const aFormatSettings: TFormatSettings) : Boolean;
var ind   : Integer;
msts  : String;
begin
result  := TryStrToDateTime(s, Value, aFormatSettings);
if result then
begin
ind := Pos(' ', s);
if ind > 0 then
begin
// mit Zeit...
msts  := Copy(s, ind+1, length(s)-ind);
ind := Pos('.', msts);
if ind > 0 then
begin
// Mit Millisekunden...
msts  := Copy(msts, ind+1, length(msts)-ind);
Value := DateUtils.IncMilliSecond(Value, StrToIntDef(msts, 0));
end;
end;
end;
end;
function  Logger : TNxLogger;
begin
result  := fDefaultLogger;
end;
procedure initLoggerFormatSettings(var FormatSettings : TFormatSettings);
begin
with FormatSettings do
begin
CurrencyFormat:=3;
NegCurrFormat:=8;
ThousandSeparator:='.';
DecimalSeparator:=',';
CurrencyDecimals:=2;
DateSeparator:='.';
TimeSeparator:=':';
ListSeparator:=';';
CurrencyString:='€';
ShortDateFormat:='yyyy.MM.dd';//'dd.MM.yyyy';
LongDateFormat:='dddd, d. MMMM yyyy';
TimeAMString:='';
TimePMString:='';
ShortTimeFormat:='hh:mm';
LongTimeFormat:='hh:mm:ss.zzz';
ShortMonthNames[1]:='Jan';
ShortMonthNames[2]:='Feb';
ShortMonthNames[3]:='Mrz';
ShortMonthNames[4]:='Apr';
ShortMonthNames[5]:='Mai';
ShortMonthNames[6]:='Jun';
ShortMonthNames[7]:='Jul';
ShortMonthNames[8]:='Aug';
ShortMonthNames[9]:='Sep';
ShortMonthNames[10]:='Okt';
ShortMonthNames[11]:='Nov';
ShortMonthNames[12]:='Dez';
LongMonthNames[1]:='Januar';
LongMonthNames[2]:='Februar';
LongMonthNames[3]:='März';
LongMonthNames[4]:='April';
LongMonthNames[5]:='Mai';
LongMonthNames[6]:='Juni';
LongMonthNames[7]:='Juli';
LongMonthNames[8]:='August';
LongMonthNames[9]:='September';
LongMonthNames[10]:='Oktober';
LongMonthNames[11]:='November';
LongMonthNames[12]:='Dezember';
ShortDayNames[1]:='So';
ShortDayNames[2]:='Mo';
ShortDayNames[3]:='Di';
ShortDayNames[4]:='Mi';
ShortDayNames[5]:='Do';
ShortDayNames[6]:='Fr';
ShortDayNames[7]:='Sa';
LongDayNames[1]:='Sonntag';
LongDayNames[2]:='Montag';
LongDayNames[3]:='Dienstag';
LongDayNames[4]:='Mittwoch';
LongDayNames[5]:='Donnerstag';
LongDayNames[6]:='Freitag';
LongDayNames[7]:='Samstag';
TwoDigitYearCenturyWindow:=0;
end;
end;
procedure StrResetLength(var S: WideString);
begin
SetLength(S, StrLen(PWideChar(S)));
end;
function GetLocalComputerName: string;
var
Count: DWORD;
zws : widestring;
begin
Count := MAX_COMPUTERNAME_LENGTH + 1;
SetLength(zws, Count);
if GetComputerName(PWideChar(zws), Count) then
StrResetLength(zws)
else
zws := '';
result := zws;
end;
{ **************************************************************************** }
{ ***** TNxLogFormater ******************************************************* }
{ **************************************************************************** }
class function TNxLogFormater.convertToLevel(aString : String) : TNxLoggerLevel;
var csec  : String;
begin
csec  := lowercase(aString);
result  := NXLL_FATAL;
if csec = 'trace' then
begin
result  := NXLL_TRACE;
exit;
end;
if csec = 'finest' then
begin
result  := NXLL_TRACE;
exit;
end;
if csec = 'debug' then
begin
result  := NXLL_DEBUG;
exit;
end;
if csec = 'info' then
begin
result  := NXLL_INFO;
exit;
end;
if csec = 'warn' then
begin
result  := NXLL_WARN;
exit;
end;
if csec = 'warning' then
begin
result  := NXLL_WARN;
exit;
end;
if csec = 'error' then
begin
result  := NXLL_ERROR;
exit;
end;
if csec = 'exception' then
begin
result  := NXLL_ERROR;
exit;
end;
if csec = 'fatal' then
begin
result  := NXLL_FATAL;
exit;
end;
if csec = 'critical' then
begin
result  := NXLL_FATAL;
exit;
end;
end;
class function TNxLogFormater.convertLevelToString(const aLevel : TNxLoggerLevel; const isException : Boolean = false) : String;
begin
case aLevel of
NXLL_TRACE: result  := 'trace';
NXLL_DEBUG: result  := 'debug';
NXLL_INFO: result  := 'info';
NXLL_WARN: result  := 'warn';
NXLL_ERROR:
begin
if isException then
begin
result  := 'exception';
end else
begin
result  := 'error';
end;
end;
NXLL_FATAL: result  := 'fatal';
end;
end;
class function TNxLogFormater.convertToCategory(aString : String) : TNxLoggerCategory;
var csec  : String;
begin
csec  := lowercase(aString);
result  := NXLCAT_NONE;
if csec = 'options' then
begin
result  := NXLCAT_OPTIONS;
exit;
end;
if csec = 'running' then
begin
result  := NXLCAT_RUNNING;
exit;
end;
if csec = 'calculating' then
begin
result  := NXLCAT_CALCULATING;
exit;
end;
if csec = 'fastrunning' then
begin
result  := NXLCAT_FASTRUNNING;
exit;
end;
if csec = 'startup' then
begin
result  := NXLCAT_STARTUP;
exit;
end;
if csec = 'shutdown' then
begin
result  := NXLCAT_SHUTDOWN;
exit;
end;
if csec = 'reference' then
begin
result  := NXLCAT_REFERENCE;
exit;
end;
if csec = 'com' then
begin
result  := NXLCAT_COM;
exit;
end;
if csec = 'dcom' then
begin
result  := NXLCAT_DCOM;
exit;
end;
if csec = 'plugin' then
begin
result  := NXLCAT_PLUGIN;
exit;
end;
end;
class function  TNxLogFormater.convertCategoryToString(const aCategory : TNxLoggerCategory) : String;
begin
case aCategory of
NXLCAT_NONE: result := 'none';
NXLCAT_OPTIONS: result := 'options';
NXLCAT_RUNNING: result := 'running';
NXLCAT_CALCULATING: result := 'calculating';
NXLCAT_FASTRUNNING: result := 'fastrunning';
NXLCAT_STARTUP: result := 'startup';
NXLCAT_SHUTDOWN: result := 'shutdown';
NXLCAT_REFERENCE: result := 'reference';
NXLCAT_COM: result := 'com';
NXLCAT_DCOM: result := 'dcom';
NXLCAT_PLUGIN: result := 'plugin';
else
result := ''
end;
end;
{ **************************************************************************** }
{ ***** TNxLogFormaterPlain ************************************************** }
{ **************************************************************************** }
constructor TNxLogFormaterPlain.Create;
begin
inherited Create;
initLoggerFormatSettings(fFormatSettings);
fFormatSettings.ShortDateFormat:='yyyy-MM-dd';
fFormatSettings.LongTimeFormat:='hh:mm:ss,zzz';
end;
destructor TNxLogFormaterPlain.Destroy;
begin
inherited Destroy;
end;
function  TNxLogFormaterPlain.formatMessage(aMessage : TNxLoggerMessage) : String;
begin
if aMessage.LogModule <> '' then
begin
result  := Format('1:s|2:s|5:s|7:s|9:s',
[ StringReplace(aMessage.ApplicationId, '|', '-', [rfReplaceAll]),                        // 0
TNxLogFormater.convertLevelToString(aMessage.LogLevel, aMessage.LogException <> nil),   // 1
StringReplace(aMessage.LogModule, '|', '-', [rfReplaceAll]),                            // 2
DateTimeToStr(aMessage.LogTimestamp, fFormatSettings),                                  // 3
StringReplace(aMessage.LogMessage, '|', '-', [rfReplaceAll]),                           // 4
StringReplace(aMessage.InstanceId, '|', '-', [rfReplaceAll]),                           // 5
StringReplace(aMessage.LogUser, '|', '-', [rfReplaceAll]),                              // 6
StringReplace(aMessage.LogCategory, '|', '-', [rfReplaceAll]),                          // 7
StringReplace(aMessage.Language, '|', '-', [rfReplaceAll]),                             // 8
StringReplace(aMessage.ThreadId, '|', '-', [rfReplaceAll])                              // 9
]);
end else
begin
result  := Format('1:s|3:s|5:s|7:s|%8:s',
[ StringReplace(aMessage.ApplicationId, '|', '-', [rfReplaceAll]),                        // 0
TNxLogFormater.convertLevelToString(aMessage.LogLevel, aMessage.LogException <> nil),   // 1
DateTimeToStr(aMessage.LogTimestamp, fFormatSettings),                                  // 2
StringReplace(aMessage.LogMessage, '|', '-', [rfReplaceAll]),                           // 3
StringReplace(aMessage.InstanceId, '|', '-', [rfReplaceAll]),                           // 4
StringReplace(aMessage.LogUser, '|', '-', [rfReplaceAll]),                              // 5
StringReplace(aMessage.LogCategory, '|', '-', [rfReplaceAll]),                          // 6
StringReplace(aMessage.Language, '|', '-', [rfReplaceAll]),                             // 7
StringReplace(aMessage.ThreadId, '|', '-', [rfReplaceAll])                              // 8
]);
end;
end;
function  TNxLogFormaterPlain.formatMessageBase64(aMessage : TNxLoggerMessage) : String;
begin
if aMessage.LogModule <> '' then
begin
result  := Format('1:s|2:s|5:s|7:s|9:s',
[ encodeBase64(aMessage.ApplicationId),                         // 0
TNxLogFormater.convertLevelToString(aMessage.LogLevel, aMessage.LogException <> nil),   // 1
encodeBase64(aMessage.LogModule),                             // 2
DateTimeToStr(aMessage.LogTimestamp, fFormatSettings),        // 3
encodeBase64(aMessage.LogMessage),                            // 4
encodeBase64(aMessage.InstanceId),                            // 5
encodeBase64(aMessage.LogUser),                               // 6
encodeBase64(aMessage.LogCategory),                           // 7
StringReplace(aMessage.Language, '|', '-', [rfReplaceAll]),   // 8
StringReplace(aMessage.ThreadId, '|', '-', [rfReplaceAll])    // 9
]);
end else
begin
result  := Format('1:s|3:s|5:s|7:s|%8:s',
[ encodeBase64(aMessage.ApplicationId),                        // 0
TNxLogFormater.convertLevelToString(aMessage.LogLevel, aMessage.LogException <> nil),   // 1
DateTimeToStr(aMessage.LogTimestamp, fFormatSettings),                                  // 2
encodeBase64(aMessage.LogMessage),                            // 3
encodeBase64(aMessage.InstanceId),                            // 4
encodeBase64(aMessage.LogUser),                               // 5
encodeBase64(aMessage.LogCategory),                           // 6
StringReplace(aMessage.Language, '|', '-', [rfReplaceAll]),   // 7
StringReplace(aMessage.ThreadId, '|', '-', [rfReplaceAll])    // 8
]);
end;
end;
function  TNxLogFormaterPlain.parseMessage(aMessageText : String) : TNxLoggerMessage;
var sl        : TStrings;
cAppId    : String;
cInstId   : String;
cUser     : String;
cThreadId : String;
cLevel    : TNxLoggerLevel;
cModule,
cMessage  : String;
cLanguage : String;
cCategory : String;
cTime     : TDateTime;
i         : Integer;
cLevelWasSet  : Boolean;
begin
cAppId    := '';
cInstId   := '';
cUser     := '';
cThreadId := '';
cLevel    := nxLogging.NXLL_FATAL;
cModule   := '';
cMessage  := '';
cLanguage := '';
cCategory := '';
cTime     := nan;
result    := nil;
if aMessageText <> '' then
begin
sl  := TStringList.Create;
try
sl.LineBreak  := ' ';
sl.Text := aMessageText;
if sl.Count >= 2 then
begin
// Timestamp...
if not _TryStrToDateTime(sl[0], cTime, fFormatSettings) then
begin
// irgendwo eine Zeit suchen...
for i := 1 to sl.Count - 1 do
begin
if _TryStrToDateTime(sl[i], cTime, fFormatSettings) then
begin
break;
end;
end;
if IsNan(cTime) then
begin
//exit;
end;
end;
// Level...
cLevelWasSet  := false;
for i := 1 to sl.Count - 1 do
begin
cLevel  := nxLogging.TNxLogFormater.convertToLevel(sl[i]);
if cLevel <> NXLL_FATAL then
begin
cLevelWasSet  := true;
break;
end;
end;
if cLevelWasSet then
begin
cCategory := nxLogging.TNxLogFormater.convertLevelToString(cLevel);
end;
cMessage  := aMessageText;
result  := TNxLoggerMessage.Create(cAppId, cInstId, cUser, cLevel, cModule, cMessage, cCategory, cLanguage, cThreadId, nil);
result.fTimestamp := cTime;
end else
begin
cMessage  := aMessageText;
cLevelWasSet  := false;
if (not cLevelWasSet) and (Pos('fatal', cMessage) > 0) then begin cLevel := NXLL_FATAL; cLevelWasSet := true; end;
if (not cLevelWasSet) and (Pos('error', cMessage) > 0) then begin cLevel := NXLL_ERROR; cLevelWasSet := true; end;
if (not cLevelWasSet) and (Pos('warn', cMessage) > 0) then begin cLevel := NXLL_WARN; cLevelWasSet := true; end;
if (not cLevelWasSet) and (Pos('warning', cMessage) > 0) then begin cLevel := NXLL_WARN; cLevelWasSet := true; end;
if (not cLevelWasSet) and (Pos('info', cMessage) > 0) then begin cLevel := NXLL_INFO; cLevelWasSet := true; end;
if (not cLevelWasSet) and (Pos('debug', cMessage) > 0) then begin cLevel := NXLL_DEBUG; cLevelWasSet := true; end;
if (not cLevelWasSet) and (Pos('fine', cMessage) > 0) then begin cLevel := NXLL_DEBUG; cLevelWasSet := true; end;
if (not cLevelWasSet) and (Pos('trace', cMessage) > 0) then begin cLevel := NXLL_TRACE; cLevelWasSet := true; end;
if (not cLevelWasSet) and (Pos('finer', cMessage) > 0) then begin cLevel := NXLL_TRACE; cLevelWasSet := true; end;
if (not cLevelWasSet) and (Pos('finest', cMessage) > 0) then begin cLevel := NXLL_TRACE; cLevelWasSet := true; end;
if cLevelWasSet then
begin
cCategory := nxLogging.TNxLogFormater.convertLevelToString(cLevel);
end;
result  := TNxLoggerMessage.Create(cAppId, cInstId, cUser, cLevel, cModule, cMessage, cCategory, cLanguage, cThreadId, nil);
result.fTimestamp := nan;
end;
finally
FreeAndNil(sl);
end;
end;
end;
function  TNxLogFormaterPlain.parseMessageBase64(aMessageText : String) : TNxLoggerMessage;
var sl        : TStrings;
cAppId    : String;
cInstId   : String;
cUser     : String;
cThreadId : String;
cLevel    : TNxLoggerLevel;
cModule,
cMessage  : String;
cLanguage : String;
cCategory : String;
cTime     : TDateTime;
i         : Integer;
cLevelWasSet  : Boolean;
begin
cAppId    := '';
cInstId   := '';
cUser     := '';
cThreadId := '';
cLevel    := nxLogging.NXLL_FATAL;
cModule   := '';
cMessage  := '';
cLanguage := '';
cCategory := '';
cTime     := nan;
result    := nil;
if aMessageText <> '' then
begin
sl  := TStringList.Create;
try
sl.LineBreak  := '|';
try
sl.Text := decodeBase64(aMessageText);
except
on e : exception do
begin
// vermutlich kein Base64...
sl.Text := aMessageText;
end;
end;
if sl.Count >= 1 then
begin
// Timestamp...
if not _TryStrToDateTime(sl[0], cTime, fFormatSettings) then
begin
// irgendwo eine Zeit suchen...
for i := 1 to sl.Count - 1 do
begin
if _TryStrToDateTime(sl[i], cTime, fFormatSettings) then
begin
break;
end;
end;
if IsNan(cTime) then
begin
exit;
end;
end;
// Level...
cLevelWasSet  := false;
for i := 1 to sl.Count - 1 do
begin
cLevel  := nxLogging.TNxLogFormater.convertToLevel(sl[i]);
if cLevel <> NXLL_FATAL then
begin
cLevelWasSet  := true;
break;
end;
end;
if cLevelWasSet then
begin
cCategory := nxLogging.TNxLogFormater.convertLevelToString(cLevel);
end;
result  := TNxLoggerMessage.Create(cAppId, cInstId, cUser, cLevel, cModule, cMessage, cCategory, cLanguage, cThreadId, nil);
result.fTimestamp := cTime;
end else
begin
cMessage  := decodeBase64(aMessageText);
cLevelWasSet  := false;
if (not cLevelWasSet) and (Pos('fatal', cMessage) > 0) then begin cLevel := NXLL_FATAL; cLevelWasSet := true; end;
if (not cLevelWasSet) and (Pos('error', cMessage) > 0) then begin cLevel := NXLL_ERROR; cLevelWasSet := true; end;
if (not cLevelWasSet) and (Pos('warn', cMessage) > 0) then begin cLevel := NXLL_WARN; cLevelWasSet := true; end;
if (not cLevelWasSet) and (Pos('warning', cMessage) > 0) then begin cLevel := NXLL_WARN; cLevelWasSet := true; end;
if (not cLevelWasSet) and (Pos('info', cMessage) > 0) then begin cLevel := NXLL_INFO; cLevelWasSet := true; end;
if (not cLevelWasSet) and (Pos('debug', cMessage) > 0) then begin cLevel := NXLL_DEBUG; cLevelWasSet := true; end;
if (not cLevelWasSet) and (Pos('fine', cMessage) > 0) then begin cLevel := NXLL_DEBUG; cLevelWasSet := true; end;
if (not cLevelWasSet) and (Pos('trace', cMessage) > 0) then begin cLevel := NXLL_TRACE; cLevelWasSet := true; end;
if (not cLevelWasSet) and (Pos('finer', cMessage) > 0) then begin cLevel := NXLL_TRACE; cLevelWasSet := true; end;
if (not cLevelWasSet) and (Pos('finest', cMessage) > 0) then begin cLevel := NXLL_TRACE; {cLevelWasSet := true;} end;
result  := TNxLoggerMessage.Create(cAppId, cInstId, cUser, cLevel, cModule, cMessage, cCategory, cLanguage, cThreadId, nil);
result.fTimestamp := nan;
end;
finally
FreeAndNil(sl);
end;
end;
end;
{ **************************************************************************** }
{ ***** TNxLogFormaterDefault ************************************************ }
{ **************************************************************************** }
constructor TNxLogFormaterDefault.Create;
begin
inherited Create;
initLoggerFormatSettings(fFormatSettings);
end;
destructor TNxLogFormaterDefault.Destroy;
begin
inherited Destroy;
end;
function  TNxLogFormaterDefault.formatMessage(aMessage : TNxLoggerMessage) : String;
begin
if aMessage.LogModule <> '' then
begin
result  := Format('3:s|%1:s.4:s|6:s|8:s|%9:s',
[ StringReplace(aMessage.ApplicationId, '|', '-', [rfReplaceAll]),                        // 0
TNxLogFormater.convertLevelToString(aMessage.LogLevel, aMessage.LogException <> nil),   // 1
StringReplace(aMessage.LogModule, '|', '-', [rfReplaceAll]),                            // 2
DateTimeToStr(aMessage.LogTimestamp, fFormatSettings),                                  // 3
StringReplace(aMessage.LogMessage, '|', '-', [rfReplaceAll]),                           // 4
StringReplace(aMessage.InstanceId, '|', '-', [rfReplaceAll]),                           // 5
StringReplace(aMessage.LogUser, '|', '-', [rfReplaceAll]),                              // 6
StringReplace(aMessage.LogCategory, '|', '-', [rfReplaceAll]),                          // 7
StringReplace(aMessage.Language, '|', '-', [rfReplaceAll]),                             // 8
StringReplace(aMessage.ThreadId, '|', '-', [rfReplaceAll])                              // 9
]);
end else
begin
result  := Format('2:s|3:s|5:s|7:s|%8:s',
[ StringReplace(aMessage.ApplicationId, '|', '-', [rfReplaceAll]),                        // 0
TNxLogFormater.convertLevelToString(aMessage.LogLevel, aMessage.LogException <> nil),   // 1
DateTimeToStr(aMessage.LogTimestamp, fFormatSettings),                                  // 2
StringReplace(aMessage.LogMessage, '|', '-', [rfReplaceAll]),                           // 3
StringReplace(aMessage.InstanceId, '|', '-', [rfReplaceAll]),                           // 4
StringReplace(aMessage.LogUser, '|', '-', [rfReplaceAll]),                              // 5
StringReplace(aMessage.LogCategory, '|', '-', [rfReplaceAll]),                          // 6
StringReplace(aMessage.Language, '|', '-', [rfReplaceAll]),                             // 7
StringReplace(aMessage.ThreadId, '|', '-', [rfReplaceAll])                              // 8
]);
end;
end;
function  TNxLogFormaterDefault.formatMessageBase64(aMessage : TNxLoggerMessage) : String;
begin
if aMessage.LogModule <> '' then
begin
result  := Format('3:s|%1:s.4:s|6:s|8:s|%9:s',
[ encodeBase64(aMessage.ApplicationId),                         // 0
TNxLogFormater.convertLevelToString(aMessage.LogLevel, aMessage.LogException <> nil),   // 1
encodeBase64(aMessage.LogModule),                             // 2
DateTimeToStr(aMessage.LogTimestamp, fFormatSettings),        // 3
encodeBase64(aMessage.LogMessage),                            // 4
encodeBase64(aMessage.InstanceId),                            // 5
encodeBase64(aMessage.LogUser),                               // 6
encodeBase64(aMessage.LogCategory),                           // 7
StringReplace(aMessage.Language, '|', '-', [rfReplaceAll]),   // 8
StringReplace(aMessage.ThreadId, '|', '-', [rfReplaceAll])    // 9
]);
end else
begin
result  := Format('2:s|3:s|5:s|7:s|%8:s',
[ encodeBase64(aMessage.ApplicationId),                        // 0
TNxLogFormater.convertLevelToString(aMessage.LogLevel, aMessage.LogException <> nil),   // 1
DateTimeToStr(aMessage.LogTimestamp, fFormatSettings),                                  // 2
encodeBase64(aMessage.LogMessage),                            // 3
encodeBase64(aMessage.InstanceId),                            // 4
encodeBase64(aMessage.LogUser),                               // 5
encodeBase64(aMessage.LogCategory),                           // 6
StringReplace(aMessage.Language, '|', '-', [rfReplaceAll]),   // 7
StringReplace(aMessage.ThreadId, '|', '-', [rfReplaceAll])    // 8
]);
end;
end;
function  TNxLogFormaterDefault.parseMessage(aMessageText : String) : TNxLoggerMessage;
var sl, sli   : TStrings;
cAppId    : String;
cInstId   : String;
cUser     : String;
cThreadId : String;
cLevel    : TNxLoggerLevel;
cModule,
cMessage  : String;
cLanguage : String;
cCategory : String;
cTime     : TDateTime;
i         : Integer;
begin
cAppId    := '';
cInstId   := '';
cUser     := '';
cThreadId := '';
//cLevel    := nxLogging.NXLL_FATAL;
cModule   := '';
cMessage  := '';
cLanguage := '';
cCategory := '';
cTime     := nan;
result    := nil;
if aMessageText <> '' then
begin
sl  := TStringList.Create;
sli := TStringList.Create;
try
sl.LineBreak  := '|';
sli.LineBreak := '.';
sl.Text := aMessageText;
if sl.Count >= 4 then
begin
// ApplicationId...
cAppId  := sl[0];
// Timestamp...
if not _TryStrToDateTime(sl[1], cTime, fFormatSettings) then
begin
exit;
end;
// Level und Modules...
sli.Text  := sl[2];
if sli.Count > 1 then
begin
cLevel  := TNxLogFormater.convertToLevel(sli[0]);
cModule := sli[1];
for i := 2 to sli.Count - 1 do
begin
cModule := cModule + '.' + sli[i];
end;
end else
begin
if sli.Count > 0 then
begin
cLevel  := TNxLogFormater.convertToLevel(sli[0]);
end else
begin
exit;
end;
end;
// Message...
cMessage  := sl[3];
if sl.Count > 4 then
begin
cInstId := sl[4];
if sl.Count > 5 then
begin
cUser := sl[5];
if sl.Count > 6 then
begin
cCategory := sl[6];
if sl.Count > 7 then
begin
cLanguage := sl[7];
if sl.Count > 8 then
begin
cThreadId := sl[8];
end;
end;
end;
end;
end;
result  := TNxLoggerMessage.Create(cAppId, cInstId, cUser, cLevel, cModule, cMessage, cCategory, cLanguage, cThreadId, nil);
result.fTimestamp := cTime;
end;
finally
FreeAndNil(sl);
FreeAndNil(sli);
end;
end;
end;
function  TNxLogFormaterDefault.parseMessageBase64(aMessageText : String) : TNxLoggerMessage;
var sl, sli   : TStrings;
cAppId    : String;
cInstId   : String;
cUser     : String;
cThreadId : String;
cLevel    : TNxLoggerLevel;
cModule,
cMessage  : String;
cCategory : String;
cLanguage : String;
cTime     : TDateTime;
begin
cAppId    := '';
cInstId   := '';
cUser     := '';
cThreadId := '';
//cLevel    := nxLogging.NXLL_FATAL;
cModule   := '';
cMessage  := '';
cLanguage := '';
cCategory := '';
cTime     := nan;
result    := nil;
if aMessageText <> '' then
begin
sl  := TStringList.Create;
sli := TStringList.Create;
try
sl.LineBreak  := '|';
sli.LineBreak := '.';
sl.Text := aMessageText;
if sl.Count >= 4 then
begin
// ApplicationId...
cAppId  := decodeBase64(sl[0]);
// Timestamp...
if not _TryStrToDateTime(sl[1], cTime, fFormatSettings) then
begin
exit;
end;
// Level und Modules...
sli.Text  := sl[2];
if sli.Count > 1 then
begin
cLevel  := TNxLogFormater.convertToLevel(sli[0]);
cModule := decodeBase64(sli[1]);
{for i := 2 to sli.Count - 1 do
begin
cModule := cModule + '.' + sli[i];
end;}
end else
begin
if sli.Count > 0 then
begin
cLevel  := TNxLogFormater.convertToLevel(sli[0]);
end else
begin
exit;
end;
end;
// Message...
cMessage  := decodeBase64(sl[3]);
if sl.Count > 4 then
begin
cInstId := decodeBase64(sl[4]);
if sl.Count > 5 then
begin
cUser := decodeBase64(sl[5]);
if sl.Count > 6 then
begin
cCategory := decodeBase64(sl[6]);
if sl.Count > 7 then
begin
cLanguage := sl[7];
if sl.Count > 8 then
begin
cThreadId := sl[8];
end;
end;
end;
end;
end;
result  := TNxLoggerMessage.Create(cAppId, cInstId, cUser, cLevel, cModule, cMessage, cCategory, cLanguage, cThreadId, nil);
result.fTimestamp := cTime;
end;
finally
FreeAndNil(sl);
FreeAndNil(sli);
end;
end;
end;
{ **************************************************************************** }
{ ***** TNxLogFormaterTCP **************************************************** }
{ **************************************************************************** }
constructor TNxLogFormaterTCP.Create;
begin
inherited Create;
initLoggerFormatSettings(fFormatSettings);
fMachineIdent := '';
end;
destructor TNxLogFormaterTCP.Destroy;
begin
inherited Destroy;
end;
function  TNxLogFormaterTCP.formatMessage(aMessage : TNxLoggerMessage) : String;
var cClassName  : String;
stt         : String;
begin
if aMessage.fException <> nil then
begin
cClassName  := aMessage.fException.ClassName;
end else
begin
cClassName  := aMessage.fExceptionClassName;
end;
stt := aMessage.StackTrace;
stt := StringReplace(stt, '|', '-', [rfReplaceAll]);
stt := StringReplace(stt, #10, '~#10~', [rfReplaceAll]);
stt := StringReplace(stt, #13, '~#13~', [rfReplaceAll]);
result  := Format('3:s|2:s|5:s|7:s|9:s|11:s|%12:s',
[ StringReplace(aMessage.ApplicationId, '|', '-', [rfReplaceAll]),                          // 0
TNxLogFormater.convertLevelToString(aMessage.LogLevel, aMessage.LogException <> nil),     // 1
StringReplace(aMessage.LogModule, '|', '-', [rfReplaceAll]),                              // 2
DateTimeToStr(aMessage.LogTimestamp, fFormatSettings),                                    // 3
StringReplace(aMessage.LogMessage, '|', '-', [rfReplaceAll]),                             // 4
aMessage.LogCategory,                                                                     // 5
StringReplace(aMessage.Language, '|', '-', [rfReplaceAll]),                               // 6
StringReplace(cClassName, '|', '-', [rfReplaceAll]),                                      // 7
stt,                                                                                      // 8
StringReplace(aMessage.InstanceId, '|', '-', [rfReplaceAll]),                             // 9
StringReplace(aMessage.LogUser, '|', '-', [rfReplaceAll]),                                // 10
StringReplace(aMessage.ThreadId, '|', '-', [rfReplaceAll]),                               // 11
fMachineIdent                                                                             // 12
]);
end;
function  TNxLogFormaterTCP.formatMessageBase64(aMessage : TNxLoggerMessage) : String;
var cClassName  : String;
stt         : String;
begin
if aMessage.fException <> nil then
begin
cClassName  := aMessage.fException.ClassName;
end else
begin
cClassName  := aMessage.fExceptionClassName;
end;
stt := aMessage.StackTrace;
stt := StringReplace(stt, '|', '-', [rfReplaceAll]);
stt := StringReplace(stt, #10, '~#10~', [rfReplaceAll]);
stt := StringReplace(stt, #13, '~#13~', [rfReplaceAll]);
result  := Format('3:s|2:s|5:s|7:s|9:s|11:s|%12:s',
[ encodeBase64(aMessage.ApplicationId),                           // 0
TNxLogFormater.convertLevelToString(aMessage.LogLevel, aMessage.LogException <> nil),  // 1
encodeBase64(aMessage.LogModule),                               // 2
DateTimeToStr(aMessage.LogTimestamp, fFormatSettings),          // 3
encodeBase64(aMessage.LogMessage),                              // 4
encodeBase64(aMessage.LogCategory),                             // 5
aMessage.Language,                                              // 6
encodeBase64(cClassName),                                       // 7
encodeBase64(stt),                                              // 8
encodeBase64(aMessage.InstanceId),                              // 9
encodeBase64(aMessage.LogUser),                                 // 10
encodeBase64(aMessage.ThreadId),                                // 11
encodeBase64(fMachineIdent)                                     // 12
]);
end;
function  TNxLogFormaterTCP.formatMessageExtra(aMessage : TNxLoggerMessage; aExtraDataId : Int64; aExtraData : TBytes) : String;
var zs, cData  : String;
begin
zs  := formatMessage(aMessage);
if length(aExtraData) > 0 then
begin
cData := convertBytesToString(aExtraData);
end else
begin
cData := '';
end;
result  := Format('1:s|%2:s', [IntToStr(aExtraDataId), cData]);
end;
function  TNxLogFormaterTCP.formatMessageExtraBase64(aMessage : TNxLoggerMessage; aExtraDataId : Int64; aExtraData : TBytes) : String;
var zs, cData  : String;
begin
zs  := formatMessage(aMessage);
if length(aExtraData) > 0 then
begin
cData := convertBytesToString(aExtraData);
end else
begin
cData := '';
end;
result  := Format('1:s|%2:s', [IntToStr(aExtraDataId), cData]);
end;
function  TNxLogFormaterTCP.parseMessage(aMessageText : String) : TNxLoggerMessage;
var sl          : TStrings;
cAppId      : String;
cLevel      : TNxLoggerLevel;
cModule,
cMessage,
cLng,
cClassName,
cStackTrace : String;
cThreadId   : String;
cInstId     : String;
cUser       : String;
cCategory   : String;
cTime       : TDateTime;
begin
result  := nil;
if aMessageText <> '' then
begin
sl  := TStringList.Create;
try
sl.LineBreak  := '|';
sl.Text := aMessageText;
if sl.Count >= 9 then
begin
// ApplicationId...
cAppId  := sl[0];
// Timestamp...
if not _TryStrToDateTime(sl[1], cTime, fFormatSettings) then
begin
exit;
end;
// Level...
cLevel  := TNxLogFormater.convertToLevel(sl[2]);
// Modules...
cModule := sl[3];
// Message...
cMessage  := sl[4];
// Category...
cCategory := sl[5];
// Language...
cLng  := sl[6];
// Classname...
cClassName  := sl[7];
// StackTrace...
cStackTrace := sl[8];
cStackTrace := StringReplace(cStackTrace, '~#10~', #10, [rfReplaceAll]);
cStackTrace := StringReplace(cStackTrace, '~#13~', #13, [rfReplaceAll]);
// InstanceId...
if sl.Count > 9 then
begin
cInstId := sl[9];
end;
// LogUser...
if sl.Count > 10 then
begin
cUser   := sl[10];
end;
// ThreadId...
if sl.Count > 11 then
begin
cThreadId := sl[11];
end;
result  := TNxLoggerMessage.Create(cAppId, cInstId, cUser, cLevel, cModule, cMessage, cCategory, cLng, cThreadId, nil);
result.fTimestamp := cTime;
result.fLanguage  := cLng;
result.fExceptionClassName  := cClassName;
result.fStackTrace  := cStackTrace;
end;
finally
FreeAndNil(sl);
end;
end;
end;
function  TNxLogFormaterTCP.parseMessageBase64(aMessageText : String) : TNxLoggerMessage;
var sl          : TStrings;
cAppId      : String;
cInstId     : String;
cUser       : String;
cLevel      : TNxLoggerLevel;
cModule,
cMessage,
cLng,
cClassName,
cStackTrace : String;
cThreadId   : String;
cCategory   : String;
cTime       : TDateTime;
begin
result  := nil;
if aMessageText <> '' then
begin
sl  := TStringList.Create;
try
sl.LineBreak  := '|';
sl.Text := aMessageText;
if sl.Count >= 9 then
begin
// ApplicationId...
cAppId  := decodeBase64(sl[0]);
// Timestamp...
if not _TryStrToDateTime(sl[1], cTime, fFormatSettings) then
begin
exit;
end;
// Level...
cLevel  := TNxLogFormater.convertToLevel(sl[2]);
// Modules...
cModule := decodeBase64(sl[3]);
// Message...
cMessage  := decodeBase64(sl[4]);
// Category...
cCategory := decodeBase64(sl[5]);
// Language...
cLng  := sl[6];
// Classname...
cClassName  := decodeBase64(sl[7]);
// StackTrace...
cStackTrace := decodeBase64(sl[8]);
// InstanceId...
if sl.Count > 9 then
begin
cInstId := decodeBase64(sl[9]);
end;
// LogUser...
if sl.Count > 10 then
begin
cUser   := decodeBase64(sl[10]);
end;
// ThreadId...
if sl.Count > 11 then
begin
cThreadId := decodeBase64(sl[11]);
end;
result  := TNxLoggerMessage.Create(cAppId, cInstId, cUser, cLevel, cModule, cMessage, cCategory, cLng, cThreadId, nil);
result.fTimestamp := cTime;
result.fLanguage  := cLng;
result.fExceptionClassName  := cClassName;
result.fStackTrace  := cStackTrace;
end;
finally
FreeAndNil(sl);
end;
end;
end;
function  TNxLogFormaterTCP.parseMessageMachine(aMessageText : String; var ResMachineIdent : String) : TNxLoggerMessage;
var sl  : TStrings;
begin
ResMachineIdent := '';
result  := parseMessage(aMessageText);
if result <> nil then
begin
if aMessageText <> '' then
begin
sl  := TStringList.Create;
try
sl.LineBreak  := '|';
sl.Text := aMessageText;
if sl.Count > 12 then
begin
ResMachineIdent := sl[12];
end;
finally
FreeAndNil(sl);
end;
end;
end;
end;
function  TNxLogFormaterTCP.parseMessageMachineBase64(aMessageText : String; var ResMachineIdent : String) : TNxLoggerMessage;
var sl  : TStrings;
begin
ResMachineIdent := '';
result  := parseMessageBase64(aMessageText);
if result <> nil then
begin
if aMessageText <> '' then
begin
sl  := TStringList.Create;
try
sl.LineBreak  := '|';
sl.Text := aMessageText;
if sl.Count > 12 then
begin
ResMachineIdent := decodeBase64(sl[12]);
end;
finally
FreeAndNil(sl);
end;
end;
end;
end;
function  TNxLogFormaterTCP.parseMessageMachineExtra(aMessageText : String; var ResMachineIdent : String; var ResExtraID : Int64; var ResExtra : TBytes) : TNxLoggerMessage;
var sl  : TStrings;
begin
result  := parseMessageMachine(aMessageText, ResMachineIdent);
if result <> nil then
begin
if aMessageText <> '' then
begin
sl  := TStringList.Create;
try
sl.LineBreak  := '|';
sl.Text := aMessageText;
if sl.Count > 13 then
begin
ResExtraID := StrToIntDef(sl[13], 0);
end;
if sl.Count > 14 then
begin
ResExtra  := convertStringToBytes(sl[14]);
end;
finally
FreeAndNil(sl);
end;
end;
end;
end;
function  TNxLogFormaterTCP.parseMessageMachineExtraBase64(aMessageText : String; var ResMachineIdent : String; var ResExtraID : Int64; var ResExtra : TBytes) : TNxLoggerMessage;
var sl  : TStrings;
begin
result  := parseMessageMachineBase64(aMessageText, ResMachineIdent);
if result <> nil then
begin
if aMessageText <> '' then
begin
sl  := TStringList.Create;
try
sl.LineBreak  := '|';
sl.Text := aMessageText;
if sl.Count > 13 then
begin
ResExtraID := StrToIntDef(sl[13], 0);
end;
if sl.Count > 14 then
begin
ResExtra  := convertStringToBytes(sl[14]);
end;
finally
FreeAndNil(sl);
end;
end;
end;
end;
{ **************************************************************************** }
{ ***** TNxLogAppenderFile *************************************************** }
{ **************************************************************************** }
constructor TNxLogAppenderFile.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
fRetryCount   := 10;
fFormater     := TNxLogFormaterDefault.Create;
fDirectory    := ExtractFilePath(ParamStr(0));
fFilenameBase := ChangeFileExt(ExtractFileName(ParamStr(0)), '');
initLoggerFormatSettings(fFormatSettings);
fStrategy     := NXLFS_NEWFILES;
fLastDate     := trunc(NowUTC);
end;
destructor TNxLogAppenderFile.Destroy;
begin
FreeAndNil(fFormater);
inherited Destroy;
end;
function  TNxLogAppenderFile.isNextDay : Boolean;
var cd  : TDate;
begin
cd  := trunc(NowUTC);
if cd > fLastDate then
begin
fLastDate := cd;
result  := true;
end else
begin
result  := false;
end;
end;
procedure TNxLogAppenderFile.append(const aEvent : TNxLoggerMessage);
begin
case fStrategy of
NXLFS_SINGLEFILE:
begin
appendSingleFile(aEvent);
end;
NXLFS_NEWFILES:
begin
appendNewFiles(aEvent);
end;
NXLFS_RENAME:
begin
appendRename(aEvent);
end;
else
appendNewFiles(aEvent);
end;
end;
procedure TNxLogAppenderFile.appendSingleFile(const aEvent : TNxLoggerMessage);
var cFilename     : String;
retrycount    : Integer;
logout        : UTF8String;
zs            : UTF8String;
fs            : TFileStream;
label lblretry;
begin
retrycount := fRetryCount;
lblretry:
try
if not DirectoryExists(fDirectory) then ForceDirectories(fDirectory);
cFilename := fDirectory + fFilenameBase + '_' + SC_ALLFILETAIL + '.nxlog';
logout  := UTF8String(fFormater.formatMessage(aEvent));
if FileExists(cFilename) then
begin
fs := TFileStream.Create(cFilename, fmOpenWrite + fmShareDenyWrite);
fs.Position := fs.Size;
end
else
begin
fs := TFileStream.Create(cFilename, fmCreate);
end;
try
zs := logout + #13#10;
fs.Write(zs[1], length(zs));
retrycount := 0;
finally
FreeAndNil(fs);
end;
except
on e : Exception do
begin
zs := zs + UTF8String(#13#10 + '   ###logfail: "' + e.Message + '"');
end;
end;
if retrycount > 0 then
begin
dec(retrycount);
sleep(50);
goto lblretry;
end;
end;
procedure TNxLogAppenderFile.appendNewFiles(const aEvent : TNxLoggerMessage);
var cFilename     : String;
retrycount    : Integer;
logout        : UTF8String;
zs            : UTF8String;
fs            : TFileStream;
label lblretry;
begin
retrycount := fRetryCount;
lblretry:
try
if not DirectoryExists(fDirectory) then ForceDirectories(fDirectory);
cFilename := fDirectory + fFilenameBase + '_' + DateToStr(nowUTC, fFormatSettings) + '.nxlog';
logout  := UTF8String(fFormater.formatMessage(aEvent));
if FileExists(cFilename) then
begin
fs := TFileStream.Create(cFilename, fmOpenWrite + fmShareDenyWrite);
fs.Position := fs.Size;
end
else
begin
fs := TFileStream.Create(cFilename, fmCreate);
end;
try
zs := logout + #13#10;
fs.Write(zs[1], length(zs));
retrycount := 0;
finally
FreeAndNil(fs);
end;
except
on e : Exception do
begin
zs := zs + UTF8String(#13#10 + '   ###logfail: "' + e.Message + '"');
end;
end;
if retrycount > 0 then
begin
dec(retrycount);
sleep(50);
goto lblretry;
end;
end;
procedure TNxLogAppenderFile.appendRename(const aEvent : TNxLoggerMessage);
var cFilename     : String;
cNewFilename  : String;
retrycount    : Integer;
logout        : UTF8String;
zs            : UTF8String;
fs            : TFileStream;
label lblretry;
begin
retrycount := fRetryCount;
lblretry:
try
if not DirectoryExists(fDirectory) then ForceDirectories(fDirectory);
cFilename := fDirectory + fFilenameBase + '_' + SC_CURRENTFILETAIL + '.nxlog';
if isNextDay then
begin
if FileExists(cFilename) then
begin
cNewFilename := fDirectory + fFilenameBase + '_' + SC_FILEFROM + '_'+ DateToStr(nowUTC, fFormatSettings) + '.nxlog';
if not RenameFile(cFilename, cNewFilename) then
begin
raise Exception.Create(Format('could not rename logfile "%0:s" to "%1:s".', [cFilename, cNewFilename]));
end;
end;
end;
logout  := UTF8String(fFormater.formatMessage(aEvent));
if FileExists(cFilename) then
begin
fs := TFileStream.Create(cFilename, fmOpenWrite + fmShareDenyWrite);
fs.Position := fs.Size;
end
else
begin
fs := TFileStream.Create(cFilename, fmCreate);
end;
try
zs := logout + #13#10;
fs.Write(zs[1], length(zs));
retrycount := 0;
finally
FreeAndNil(fs);
end;
except
on e : Exception do
begin
zs := zs + UTF8String(#13#10 + '   ###logfail: "' + e.Message + '"');
end;
end;
if retrycount > 0 then
begin
dec(retrycount);
sleep(50);
goto lblretry;
end;
end;
{ **************************************************************************** }
{ ***** TNxLogAppenderChain ************************************************** }
{ **************************************************************************** }
constructor TNxLogAppenderChain.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
fChainedLogger  := nil;
end;
destructor TNxLogAppenderChain.Destroy;
begin
fChainedLogger  := nil;
inherited Destroy;
end;
procedure TNxLogAppenderChain.append(const aEvent : TNxLoggerMessage);
begin
if fChainedLogger <> nil then
begin
fChainedLogger.log(aEvent);
end;
end;
{ **************************************************************************** }
{ ***** TNxLogAppenderTCPThread ********************************************** }
{ **************************************************************************** }
{$if CompilerVersion > 24}
function getMD5OfString(const aString : string) : string;
var idmd5 : TIdHashMessageDigest5;
begin
idmd5 := TIdHashMessageDigest5.Create;
try
result  := idmd5.HashStringAsHex(aString, IndyTextEncoding_UTF8);
finally
idmd5.Free;
end;
end;
{$else}
function getMD5OfString(const aString : string) : string;
var idmd5 : TIdHashMessageDigest5;
begin
idmd5 := TIdHashMessageDigest5.Create;
try
result  := idmd5.HashStringAsHex(aString, TEncoding.UTF8);
finally
idmd5.Free;
end;
end;
{$ifend}
constructor TNxLogAppenderTCPThread.Create(CreateSuspended: Boolean);
begin
inherited Create(CreateSuspended);
fTCP            := nil;
fMachineIdent   := '';
fHostOrIP       := '';
fPort           := 0;
fRetryCount     := 10;
fAdapter        := nil;
fUsername       := '';
fPassword       := '';
end;
destructor TNxLogAppenderTCPThread.Destroy;
begin
inherited Destroy;
end;
procedure TNxLogAppenderTCPThread.Execute;
var cEntry      : String;
cRes        : String;
cResCode    : Integer;
cCurrentTry : Integer;
_cPWD       : String;
cResCodeS   : String;
cResCodeT   : String;
ind         : Integer;
procedure _connect;
begin
fTCP  := TIdTCPClient.Create(nil);
try
fTCP.Host := fHostOrIP;
fTCP.Port := fPort;
fTCP.Connect;
if (fUsername <> '') then
begin
if fPassword <> '' then
begin
_cPWD  := getMD5OfString(fPassword);
end else
begin
_cPWD := '';
end;
{$if CompilerVersion > 24}
fTCP.IOHandler.WriteLn(fUsername, IndyTextEncoding_UTF8);
fTCP.IOHandler.WriteLn(_cPWD, IndyTextEncoding_UTF8);
{$else}
fTCP.IOHandler.WriteLn(fUsername, TEncoding.UTF8);
fTCP.IOHandler.WriteLn(_cPWD, TEncoding.UTF8);
{$ifend}
end;
except
FreeAndNil(fTCP);
end;
end;
procedure _disconnect;
begin
if fTCP <> nil then
begin
try
fTCP.Disconnect;
except
end;
end;
FreeAndNil(fTCP);
end;
begin
while not Terminated do
begin
if fTCP = nil then
begin
// verbinden...
_connect;
end;
if fTCP <> nil then
begin
// dann sind wir auch verbunden...
cEntry  := fAdapter.consumeEntry;
if cEntry <> '' then
begin
cCurrentTry := 0;
repeat
try
{$if CompilerVersion > 24}
fTCP.IOHandler.WriteLn('log:'+cEntry, IndyTextEncoding_UTF8);
cRes  := fTCP.IOHandler.ReadLn(idglobal.EOL, 5000, -1, IndyTextEncoding_UTF8);
{$else}
fTCP.IOHandler.WriteLn('log:'+cEntry, TEncoding.UTF8);
cRes  := fTCP.IOHandler.ReadLn(idglobal.EOL, 5000, -1, TEncoding.UTF8);
{$ifend}
ind := Pos(':', cRes);
if ind > 0 then
begin
cResCodeS := Copy(cRes, 1, ind);
cResCodeT := Copy(cRes, ind+1, length(cRes)-ind);
if cResCodeS = '' then raise Exception.Create('server result code was empty');
if not TryStrToInt(cResCodeS, cResCode) then raise Exception.Create('server result contained no result code');
case cResCode of
NXLOGPTCP_OK                            :
begin
// Alles gut...
end;
NXLOGPTCP_BADREQUEST                    :
begin
raise Exception.Create('NXLOGPTCP_BADREQUEST'+':'+cResCodeT);
end;
NXLOGPTCP_UNAUTHORIZED                  :
begin
raise Exception.Create('NXLOGPTCP_UNAUTHORIZED'+':'+cResCodeT);
end;
NXLOGPTCP_PAYMENTREQUIRED               :
begin
raise Exception.Create('NXLOGPTCP_PAYMENTREQUIRED'+':'+cResCodeT);
end;
NXLOGPTCP_FORBIDDEN                     :
begin
raise Exception.Create('NXLOGPTCP_FORBIDDEN'+':'+cResCodeT);
end;
NXLOGPTCP_NOTFOUND                      :
begin
raise Exception.Create('NXLOGPTCP_NOTFOUND'+':'+cResCodeT);
end;
NXLOGPTCP_METHODNOTALLOWED              :
begin
raise Exception.Create('NXLOGPTCP_METHODNOTALLOWED'+':'+cResCodeT);
end;
NXLOGPTCP_INTERNALSERVERERROR           :
begin
raise Exception.Create('NXLOGPTCP_INTERNALSERVERERROR'+':'+cResCodeT);
end;
NXLOGPTCP_NOTIMPLEMENTED                :
begin
raise Exception.Create('NXLOGPTCP_NOTIMPLEMENTED'+':'+cResCodeT);
end;
NXLOGPTCP_SERVICETEMPORARYUNAVAILABLE   :
begin
raise Exception.Create('NXLOGPTCP_SERVICETEMPORARYUNAVAILABLE'+':'+cResCodeT);
end;
else
raise Exception.Create('unknown result code in server result');
end;
end else
begin
if cRes = '' then raise Exception.Create('server result was empty');
if not TryStrToInt(cRes, cResCode) then raise Exception.Create('server result contained no result code');
case cResCode of
NXLOGPTCP_OK                            :
begin
// Alles gut...
cCurrentTry := 0;
end;
NXLOGPTCP_BADREQUEST                    :
begin
raise Exception.Create('NXLOGPTCP_BADREQUEST');
end;
NXLOGPTCP_UNAUTHORIZED                  :
begin
raise Exception.Create('NXLOGPTCP_UNAUTHORIZED');
end;
NXLOGPTCP_PAYMENTREQUIRED               :
begin
raise Exception.Create('NXLOGPTCP_PAYMENTREQUIRED');
end;
NXLOGPTCP_FORBIDDEN                     :
begin
raise Exception.Create('NXLOGPTCP_FORBIDDEN');
end;
NXLOGPTCP_NOTFOUND                      :
begin
raise Exception.Create('NXLOGPTCP_NOTFOUND');
end;
NXLOGPTCP_METHODNOTALLOWED              :
begin
raise Exception.Create('NXLOGPTCP_METHODNOTALLOWED');
end;
NXLOGPTCP_INTERNALSERVERERROR           :
begin
raise Exception.Create('NXLOGPTCP_INTERNALSERVERERROR');
end;
NXLOGPTCP_NOTIMPLEMENTED                :
begin
raise Exception.Create('NXLOGPTCP_NOTIMPLEMENTED');
end;
NXLOGPTCP_SERVICETEMPORARYUNAVAILABLE   :
begin
raise Exception.Create('NXLOGPTCP_SERVICETEMPORARYUNAVAILABLE');
end;
else
raise Exception.Create('unknown result code in server result');
end;
end;
except
on e : exception do
begin
inc(cCurrentTry);
sleep(50);
end;
end;
until (cCurrentTry = 0) or (cCurrentTry > fRetryCount);
if cCurrentTry > fRetryCount then
begin
// Das waren also mehrere Fehler hintereinander...
_disconnect;
sleep(1500);
end;
end else
begin
sleep(1000);
end;
end else
begin
// Verbindung steht nicht, was machen wir?
sleep(1500);
end;
end;
FreeAndNil(fTCP);
end;
{ **************************************************************************** }
{ ***** TNxLogAppenderTCP **************************************************** }
{ **************************************************************************** }
constructor TNxLogAppenderTCP.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
initLoggerFormatSettings(fFormatSettings);
fMaxEntries     := TIdThreadSafeInteger.Create;
fMaxEntries.Value := IC_DEFAULTMAXTCPENTRIES;
fHostOrIP       := '';
fPort           := 0;
fRetryCount     := 10;
fBuffer         := TIdThreadSafeStringList.Create;
fWorker         := nil;
fFormater       := TNxLogFormaterTCP.Create;
fLevelFilter    := TNxLoggerMessageFilterLevelSet.Create;
fLevelFilter.unsetLevel(NXLL_TRACE);
fLevelFilter.unsetLevel(NXLL_DEBUG);
fLevelFilter.unsetLevel(NXLL_INFO);
fUserFilter     := nil;
fUsername       := '';
fPassword       := '';
end;
destructor TNxLogAppenderTCP.Destroy;
begin
if isStarted then
begin
stop;
end;
clearBuffer;
FreeAndNil(fBuffer);
FreeAndNil(fFormater);
fUserFilter     := nil;
FreeAndNil(fLevelFilter);
FreeAndNil(fMaxEntries);
inherited Destroy;
end;
function  TNxLogAppenderTCP.consumeEntry : String;
var lst : TStringList;
begin
lst := fBuffer.Lock;
try
if lst.Count > 0 then
begin
result  := lst[0];
lst.Delete(0);
end else
begin
result  := '';
end;
finally
fBuffer.Unlock;
end;
end;
procedure TNxLogAppenderTCP.setMachineIdent(aIdent : String);
begin
if fMachineIdent <> aIdent then
begin
fMachineIdent := aIdent;
if fFormater <> nil then
begin
fFormater.MachineIdent  := fMachineIdent;
end;
end;
end;
procedure TNxLogAppenderTCP.setMaxEntries(aValue : Integer);
begin
fMaxEntries.Value := aValue;
end;
function  TNxLogAppenderTCP.getMaxEntries : Integer;
begin
result  := fMaxEntries.Value;
end;
function  TNxLogAppenderTCP.getCurrentEntries : Integer;
var s   : TStringList;
begin
s := fBuffer.Lock;
try
result  := s.Count;
finally
fBuffer.Unlock;
end;
end;
function  TNxLogAppenderTCP.isStarted : Boolean;
begin
result  := fWorker <> nil;
end;
procedure TNxLogAppenderTCP.start;
begin
if not isStarted then
begin
fWorker := TNxLogAppenderTCPThread.Create(true);
fWorker.FormatSettings  := self.fFormatSettings;
fWorker.MachineIdent    := self.fMachineIdent;
fWorker.HostOrIP        := self.fHostOrIP;
fWorker.Port            := self.fPort;
fWorker.RetryCount      := self.fRetryCount;
fWorker.Username        := self.fUsername;
fWorker.Password        := self.fPassword;
fWorker.Adapter         := self;
fWorker.Start;
end;
end;
procedure TNxLogAppenderTCP.stop;
begin
if isStarted then
begin
fWorker.Terminate;
FreeAndNil(fWorker);
end;
end;
procedure TNxLogAppenderTCP.clearBuffer;
begin
if fBuffer <> nil then fBuffer.Clear;
end;
procedure TNxLogAppenderTCP.append(const aEvent : TNxLoggerMessage);
var zs    : String;
procedure _doAppend;
var _strs   : TStringList;
_maxc   : Integer;
_wasbo  : Boolean;
begin
_maxc := fMaxEntries.Value;
_strs := fBuffer.Lock;
try
if _strs.Count < _maxc then
begin
// Alles OK...
zs  := fFormater.formatMessage(aEvent);
_strs.Add(zs);
_wasbo  := false;
end else
begin
// Pufferüberlauf...
_wasbo  := true;
end;
finally
fBuffer.Unlock;
end;
if _wasbo then
begin
if assigned(fOnOverflow) then
begin
fOnOverflow(_maxc);
end;
end;
end;
begin
if not isStarted then
begin
start;
end;
if fLevelFilter.match(aEvent) then
begin
if fUserFilter <> nil then
begin
if fUserFilter.match(aEvent) then
begin
_doAppend;
end;
end else
begin
_doAppend;
end;
end;
end;
{ **************************************************************************** }
{ ***** TNxLoggerCollectionItem ********************************************** }
{ **************************************************************************** }
constructor TNxLoggerCollectionItem.Create(Collection: TCollection);
begin
inherited Create(Collection);
fAppender := nil;
end;
destructor TNxLoggerCollectionItem.Destroy;
begin
fAppender := nil;
inherited Destroy;
end;
procedure TNxLoggerCollectionItem.append(const aEvent : TNxLoggerMessage);
begin
if fAppender <> nil then
begin
fAppender.append(aEvent);
end;
end;
{ **************************************************************************** }
{ ***** TNxLogger ************************************************************ }
{ **************************************************************************** }
constructor TNxLogger.Create(AOwner : TComponent);
function _GetUserFromWindows: string;
var
UserName    : string;
UserNameLen : Dword;
begin
UserNameLen := 255;
SetLength(userName, UserNameLen);
if GetUserName(PChar(UserName), UserNameLen) then
begin
result := Copy(UserName,1,UserNameLen-1);
end else
begin
result := '';
end;
end;
begin
inherited Create(AOwner);
fAppenders  := TNxLoggerCollection.Create(TNxLoggerCollectionItem);
fCSLog  := TCriticalSection.Create;
fCSCurrentLevel := TCriticalSection.Create;
initLoggerFormatSettings(fLogFormatSettings);
fApplicationID    := ChangeFileExt(ExtractFileName(ParamStr(0)), '');
fInstanceID       := IntToStr(Windows.GetCurrentProcessId);
fUserIdent        := _GetUserFromWindows;
fLanguage         := '';
fCurrentLevel     := NXLL_INFO;
fFilters  := TIdThreadSafeList.Create;
fOnAppend := nil;
fOnLog    := nil;
end;
destructor  TNxLogger.Destroy;
begin
fOnAppend := nil;
fOnLog    := nil;
FreeAndNil(fCSCurrentLevel);
FreeAndNil(fCSLog);
FreeAndNil(fAppenders);
FreeAndNil(fFilters);
inherited Destroy;
end;
class function TNxLogger.isImportantLogLevel(const aRelativeBaseLevel, aLevelToTest : TNxLoggerLevel) : Boolean;
begin
result  := aLevelToTest >= aRelativeBaseLevel;
end;
function  TNxLogger.matchFilters(const aEvent : TNxLoggerMessage) : Boolean;
var lst : TList;
i   : Integer;
flt : TNxLoggerMessageFilter;
begin
result  := true;
lst := fFilters.LockList;
try
for i := 0 to lst.Count - 1 do
begin
flt := TNxLoggerMessageFilter(lst[i]);
result  := result and flt.match(aEvent);
end;
finally
fFilters.UnlockList;
end;
end;
function  TNxLogger.getMachineIdent : String;
begin
result  := GetLocalComputerName;
end;
procedure TNxLogger.initializeFileLogging(const aApplicationId, aLogDirectory, aBaseFilename : String; aRetryCount : Integer = 10; aStrategy : TNxLogAppenderFileStrategy = NXLFS_NEWFILES);
var i     : TCollectionItem;
x     : TNxLoggerCollectionItem;
found : Boolean;
fapp  : TNxLogAppenderFile;
begin
found := false;
fCSLog.Enter;
try
for i in fAppenders do
begin
x := i as TNxLoggerCollectionItem;
if x.fAppender is TNxLogAppenderFile then
begin
fapp  := (x.fAppender as TNxLogAppenderFile);
fapp.fDirectory    := aLogDirectory;
fapp.fFilenameBase := aBaseFilename;
fapp.fRetryCount   := aRetryCount;
fapp.Strategy      := aStrategy;
found := true;
end;
end;
if not found then
begin
fapp  := TNxLogAppenderFile.Create(self);
fapp.fDirectory    := aLogDirectory;
fapp.fFilenameBase := aBaseFilename;
fapp.fRetryCount   := aRetryCount;
fapp.Strategy      := aStrategy;
addAppender(fapp);
end;
fApplicationID := aApplicationId;
finally
fCSLog.Leave;
end;
end;
procedure TNxLogger.initializeServerTCPLogging(const aApplicationId, aHostOrIP : String; aPort : Integer; aMachineIdent : String = ''; aRetryCount : Integer = 10; aUsername : String = ''; aPassword : String = ''; aLevelFilter : TNxLoggerLevelSet = [NXLL_FATAL, NXLL_ERROR, NXLL_WARN]);
var i     : TCollectionItem;
x     : TNxLoggerCollectionItem;
found : Boolean;
fapp  : TNxLogAppenderTCP;
begin
found := false;
fCSLog.Enter;
try
if aMachineIdent = '' then
begin
aMachineIdent := getMachineIdent;
end;
for i in fAppenders do
begin
x := i as TNxLoggerCollectionItem;
if x.fAppender is TNxLogAppenderTCP then
begin
fapp  := (x.fAppender as TNxLogAppenderTCP);
fapp.fMachineIdent  := aMachineIdent;
fapp.fHostOrIP      := aHostOrIP;
fapp.fPort          := aPort;
fapp.fRetryCount    := aRetryCount;
fapp.fUsername      := aUsername;
fapp.fPassword      := aPassword;
fapp.fLevelFilter.setLevelSet(aLevelFilter);
found := true;
end;
end;
if not found then
begin
fapp  := TNxLogAppenderTCP.Create(self);
fapp.setMachineIdent(aMachineIdent);
fapp.fHostOrIP      := aHostOrIP;
fapp.fPort          := aPort;
fapp.fRetryCount    := aRetryCount;
fapp.fUsername      := aUsername;
fapp.fPassword      := aPassword;
fapp.fLevelFilter.setLevelSet(aLevelFilter);
addAppender(fapp);
end;
fApplicationID := aApplicationId;
finally
fCSLog.Leave;
end;
end;
procedure TNxLogger.log(const aEvent : TNxLoggerMessage);
var i : TCollectionItem;
x : TNxLoggerCollectionItem;
begin
if isImportantLogLevel(getCurrentLevel, aEvent.LogLevel) and matchFilters(aEvent) then
begin
fCSLog.Enter;
try
for i in fAppenders do
begin
x := i as TNxLoggerCollectionItem;
x.append(aEvent);
end;
finally
fCSLog.Leave;
end;
if assigned(fOnAppend) then
begin
fOnAppend(self, aEvent);
end;
end;
if assigned(fOnLog) then
begin
fOnLog(self, aEvent);
end;
end;
procedure TNxLogger.log(const aLevel : TNxLoggerLevel; const aMessage : String);
var cMessage  : TNxLoggerMessage;
begin
cMessage  := TNxLoggerMessage.Create(fApplicationID, fInstanceId, fUserIdent, aLevel, aMessage);
log(cMessage);
FreeAndNil(cMessage);
end;
procedure TNxLogger.log(const aLevel : TNxLoggerLevel; const aModule, aMessage : String);
var cMessage  : TNxLoggerMessage;
begin
cMessage  := TNxLoggerMessage.Create(fApplicationID, fInstanceId, fUserIdent, aLevel, aModule, aMessage, TNxLogFormater.convertCategoryToString(NXLCAT_NONE), fLanguage, nil);
log(cMessage);
FreeAndNil(cMessage);
end;
procedure TNxLogger.log(const aLevel : TNxLoggerLevel; const aModule, aMessage : String; const aCategory : TNxLoggerCategory; const aException : exception);
var cMessage  : TNxLoggerMessage;
begin
cMessage  := TNxLoggerMessage.Create(fApplicationID, fInstanceId, fUserIdent, aLevel, aModule, aMessage, TNxLogFormater.convertCategoryToString(aCategory), fLanguage, aException);
log(cMessage);
FreeAndNil(cMessage);
end;
procedure TNxLogger.log(const aLevel : TNxLoggerLevel; const aModule, aMessage : String; const aCategoryAsString : String; const aException : exception);
var cMessage  : TNxLoggerMessage;
begin
cMessage  := TNxLoggerMessage.Create(fApplicationID, fInstanceId, fUserIdent, aLevel, aModule, aMessage, aCategoryAsString, fLanguage, aException);
log(cMessage);
FreeAndNil(cMessage);
end;
procedure TNxLogger.log(const aLevel : TNxLoggerLevel; const aModule, aMessage : String; const aCategoryAsString, aLanguage : String; const aException : exception);
var cMessage  : TNxLoggerMessage;
begin
cMessage  := TNxLoggerMessage.Create(fApplicationID, fInstanceId, fUserIdent, aLevel, aModule, aMessage, aCategoryAsString, aLanguage, aException);
log(cMessage);
FreeAndNil(cMessage);
end;
procedure TNxLogger.fatal(const aMessage : String);
begin
log(NXLL_FATAL, aMessage);
end;
procedure TNxLogger.fatal(const aModule, aMessage : String);
begin
log(NXLL_FATAL, aModule, aMessage, NXLCAT_NONE, nil);
end;
procedure TNxLogger.fatal(const aModule, aMessage : String; const aCategory : TNxLoggerCategory; const aException : exception = nil);
begin
log(NXLL_FATAL, aModule, aMessage, aCategory, aException);
end;
procedure TNxLogger.error(const aMessage : String);
begin
log(NXLL_ERROR, aMessage);
end;
procedure TNxLogger.error(const aModule, aMessage : String);
begin
log(NXLL_ERROR, aModule, aMessage, NXLCAT_NONE, nil);
end;
procedure TNxLogger.error(const aModule, aMessage : String; const aCategory : TNxLoggerCategory; const aException : exception = nil);
begin
log(NXLL_ERROR, aModule, aMessage, aCategory, aException);
end;
procedure TNxLogger.warn(const aMessage : String);
begin
log(NXLL_WARN, aMessage);
end;
procedure TNxLogger.warn(const aModule, aMessage : String);
begin
log(NXLL_WARN, aModule, aMessage, NXLCAT_NONE, nil);
end;
procedure TNxLogger.warn(const aModule, aMessage : String; const aCategory : TNxLoggerCategory; const aException : exception = nil);
begin
log(NXLL_WARN, aModule, aMessage, aCategory, aException);
end;
procedure TNxLogger.info(const aMessage : String);
begin
log(NXLL_INFO, aMessage);
end;
procedure TNxLogger.info(const aModule, aMessage : String);
begin
log(NXLL_INFO, aModule, aMessage, NXLCAT_NONE, nil);
end;
procedure TNxLogger.info(const aModule, aMessage : String; const aCategory : TNxLoggerCategory; const aException : exception = nil);
begin
log(NXLL_INFO, aModule, aMessage, aCategory, aException);
end;
procedure TNxLogger.debug(const aMessage : String);
begin
log(NXLL_DEBUG, aMessage);
end;
procedure TNxLogger.debug(const aModule, aMessage : String);
begin
log(NXLL_DEBUG, aModule, aMessage, NXLCAT_NONE, nil);
end;
procedure TNxLogger.debug(const aModule, aMessage : String; const aCategory : TNxLoggerCategory; const aException : exception = nil);
begin
log(NXLL_DEBUG, aModule, aMessage, aCategory, aException);
end;
procedure TNxLogger.trace(const aMessage : String);
begin
log(NXLL_TRACE, aMessage);
end;
procedure TNxLogger.trace(const aModule, aMessage : String);
begin
log(NXLL_TRACE, aModule, aMessage, NXLCAT_NONE, nil);
end;
procedure TNxLogger.trace(const aModule, aMessage : String; const aCategory : TNxLoggerCategory; const aException : exception = nil);
begin
log(NXLL_TRACE, aModule, aMessage, aCategory, aException);
end;
function  TNxLogger.getAppenderCount : Integer;
begin
result  := fAppenders.Count;
end;
function  TNxLogger.getAppender(aIndex : Integer) : TNxLogAppender;
begin
if (aIndex >= 0) and (aIndex < fAppenders.Count) then
begin
result  := TNxLoggerCollectionItem(fAppenders.Items[aIndex]).Appender;
end else
begin
result  := nil;
end;
end;
procedure TNxLogger.addAppender(aAppender : TNxLogAppender);
begin
TNxLoggerCollectionItem(fAppenders.Add).Appender  := aAppender;
end;
function  TNxLogger.deleteAppender(aIndex : Integer) : TNxLogAppender;
begin
if (aIndex >= 0) and (aIndex < fAppenders.Count) then
begin
result  := TNxLoggerCollectionItem(fAppenders.Items[aIndex]).Appender;
fAppenders.Delete(aIndex);
end else
begin
result  := nil;
end;
end;
procedure TNxLogger.clearAppenders;
begin
fAppenders.Clear;
end;
function  TNxLogger.getCurrentLevel : TNxLoggerLevel;
begin
fCSCurrentLevel.Enter;
try
result  := fCurrentLevel;
finally
fCSCurrentLevel.Leave;
end;
end;
procedure TNxLogger.setCurrentLevel(aLevel : TNxLoggerLevel);
begin
fCSCurrentLevel.Enter;
try
fCurrentLevel := aLevel;
finally
fCSCurrentLevel.Leave;
end;
end;
function  TNxLogger.isTrace : Boolean;
begin
result  := CurrentLevel <= NXLL_TRACE;
end;
function  TNxLogger.isDebug : Boolean;
begin
result  := CurrentLevel <= NXLL_DEBUG;
end;
function  TNxLogger.isInfo  : Boolean;
begin
result  := CurrentLevel <= NXLL_INFO;
end;
function  TNxLogger.isWarn  : Boolean;
begin
result  := CurrentLevel <= NXLL_WARN;
end;
function  TNxLogger.isError : Boolean;
begin
result  := CurrentLevel <= NXLL_ERROR;
end;
function  TNxLogger.isFatal : Boolean;
begin
result  := CurrentLevel <= NXLL_FATAL;
end;
{ **************************************************************************** }
{ ***** TNxLoggerMessage ***************************************************** }
{ **************************************************************************** }
constructor TNxLoggerMessage.Create(const aApplicationId, aInstanceId, aLogUser : String; aLevel : TNxLoggerLevel; const aMessage : String);
begin
self.Create(aApplicationId, aInstanceId, aLogUser, aLevel, '', aMessage, '', '', nil);
end;
constructor TNxLoggerMessage.Create(const aApplicationId, aInstanceId, aLogUser : String; aLevel : TNxLoggerLevel; const aModule, aMessage : String; const aCategory, aLanguage : String; const aException : Exception);
begin
self.Create(aApplicationId, aInstanceId, aLogUser, aLevel, aModule, aMessage, '', '', '', nil);
end;
constructor TNxLoggerMessage.Create(const aApplicationId, aInstanceId, aLogUser : String; aLevel : TNxLoggerLevel; const aModule, aMessage : String; const aCategory, aLanguage, aThreadId : String; const aException : Exception);
begin
inherited Create;
fApplicationId  := aApplicationId;
fInstanceId     := aInstanceId;
fLogUser        := aLogUser;
if aThreadId = '' then
begin
fThreadId     := IntToStr(Windows.GetCurrentThreadId);
end else
begin
fThreadId     := aThreadId;
end;
fLevel          := aLevel;
fCategory       := aCategory;
fModule         := aModule;
fMessage        := aMessage;
fTimestamp      := nowUTC;
fLanguage       := aLanguage;
fException      := aException;
if fException <> nil then
begin
fExceptionClassName := fException.ClassName;
end else
begin
fExceptionClassName := '';
end;
end;
destructor TNxLoggerMessage.Destroy;
begin
inherited Destroy;
end;
procedure TNxLoggerMessage.AssignTo(Dest: TPersistent);
var d : TNxLoggerMessage;
begin
if Dest is TNxLoggerMessage then
begin
d := Dest as TNxLoggerMessage;
d.fApplicationId      := self.fApplicationId;
d.fInstanceId         := self.fInstanceId;
d.fLogUser            := self.fLogUser;
d.fLevel              := self.fLevel;
d.fCategory           := self.fCategory;
d.fModule             := self.fModule;
d.fMessage            := self.fMessage;
d.fTimestamp          := self.fTimestamp;
d.fException          := self.fException;
d.fExceptionClassName := self.fExceptionClassName;
d.fLanguage           := self.fLanguage;
d.fStackTrace         := self.fStackTrace;
d.fThreadId           := self.fThreadId;
end else
begin
inherited Assign(Dest);
end;
end;
function TNxLoggerMessage.getApplicationId : String;
begin
result  := fApplicationId;
end;
function TNxLoggerMessage.getInstanceId : String;
begin
result  := fInstanceId;
end;
function TNxLoggerMessage.getLogUser : String;
begin
result  := fLogUser;
end;
function TNxLoggerMessage.getThreadId : String;
begin
result  := fThreadId;
end;
function TNxLoggerMessage.getLevel : TNxLoggerLevel;
begin
result  := fLevel;
end;
function TNxLoggerMessage.getCategory : String;
begin
result  := fCategory;
end;
function TNxLoggerMessage.getModule : String;
begin
result  := fModule;
end;
function TNxLoggerMessage.getMessage : String;
begin
result  := fMessage;
end;
function TNxLoggerMessage.getTimestamp : TDateTime;
begin
result  := fTimestamp;
end;
function TNxLoggerMessage.getException : Exception;
begin
result  := fException;
end;
function TNxLoggerMessage.getLanguage : String;
begin
result  := fLanguage;
end;
function TNxLoggerMessage.getExceptionClassName : String;
begin
result  := fExceptionClassName;
end;
function TNxLoggerMessage.getStackTrace : String;
begin
result  := fStackTrace;
end;
procedure TNxLoggerMessage.setApplicationId(aValue : String);
begin
fApplicationId  := aValue;
end;
procedure TNxLoggerMessage.setInstanceId(aValue : String);
begin
fInstanceId  := aValue;
end;
procedure TNxLoggerMessage.setLogUser(aValue : String);
begin
fLogUser  := aValue;
end;
procedure TNxLoggerMessage.setThreadId(aValue : String);
begin
fThreadId := aValue;
end;
procedure TNxLoggerMessage.setLevel(aValue  : TNxLoggerLevel);
begin
fLevel  := aValue;
end;
procedure TNxLoggerMessage.setCategory(aValue : String);
begin
fCategory := aValue;
end;
procedure TNxLoggerMessage.setModule(aValue : String);
begin
fModule := aValue;
end;
procedure TNxLoggerMessage.setMessage(aValue  : String);
begin
fMessage  := aValue;
end;
procedure TNxLoggerMessage.setTimestamp(aValue  : TDateTime);
begin
fTimestamp  := aValue;
end;
procedure TNxLoggerMessage.setException(aValue  : Exception);
begin
fException  := aValue;
end;
procedure TNxLoggerMessage.setLanguage(aValue : String);
begin
fLanguage := aValue;
end;
procedure TNxLoggerMessage.setExceptionClassName(aValue : String);
begin
fExceptionClassName := aValue;
end;
procedure TNxLoggerMessage.setStackTrace(aValue : String);
begin
fStackTrace := aValue;
end;
{ **************************************************************************** }
{ ***** TNxLoggerMessageFilterLevelSet *************************************** }
{ **************************************************************************** }
constructor TNxLoggerMessageFilterLevelSet.Create;
begin
inherited Create;
fLevelSet := [NXLL_TRACE, NXLL_DEBUG, NXLL_INFO, NXLL_WARN, NXLL_ERROR, NXLL_FATAL ];
end;
destructor TNxLoggerMessageFilterLevelSet.Destroy;
begin
inherited Destroy;
end;
procedure TNxLoggerMessageFilterLevelSet.AssignTo(Dest: TPersistent);
begin
if Dest is TNxLoggerMessageFilterLevelSet then
begin
(Dest as TNxLoggerMessageFilterLevelSet).fLevelSet := fLevelSet;
end;
end;
function  TNxLoggerMessageFilterLevelSet.match(aMessage : TNxLoggerMessage) : Boolean;
begin
result  := false;
if aMessage <> nil then
begin
if aMessage.LogLevel in fLevelSet then
begin
result  := true;
end;
end;
end;
procedure TNxLoggerMessageFilterLevelSet.saveToStream(aStream : TStream);
var wr  : TWriter;
i   : TNxLoggerLevel;
zs  : String;
begin
wr  := TWriter.Create(aStream, 1024);
try
wr.WriteListBegin;
for i := Low(TNxLoggerLevel) to High(TNxLoggerLevel) do
begin
zs  := TypInfo.GetEnumName(System.TypeInfo(TNxLoggerLevel), Integer(i));
wr.WriteIdent(zs);
if TNxLoggerLevel(i) in fLevelSet then
begin
wr.WriteBoolean(true);
end else
begin
wr.WriteBoolean(false);
end;
end;
wr.WriteListEnd;
wr.FlushBuffer;
finally
FreeAndNil(wr);
end;
end;
procedure TNxLoggerMessageFilterLevelSet.loadFromStream(aStream : TStream);
var rd  : TReader;
i   : TNxLoggerLevel;
zs  : String;
begin
rd  := TReader.Create(aStream, 1024);
try
fLevelSet := [];
rd.ReadListBegin;
for i := Low(TNxLoggerLevel) to High(TNxLoggerLevel) do
begin
zs  := rd.ReadIdent;
if rd.ReadBoolean then
begin
fLevelSet := fLevelSet + [i];
end else
begin
end;
end;
rd.ReadListEnd;
finally
FreeAndNil(rd);
end;
end;
procedure TNxLoggerMessageFilterLevelSet.setLevel(aLevel : TNxLoggerLevel);
begin
fLevelSet := fLevelSet + [aLevel];
end;
procedure TNxLoggerMessageFilterLevelSet.unsetLevel(aLevel : TNxLoggerLevel);
begin
fLevelSet := fLevelSet - [aLevel];
end;
procedure TNxLoggerMessageFilterLevelSet.setLevelAndAbove(aLevel : TNxLoggerLevel);
var cl  : TNxLoggerLevel;
begin
for cl := low(TNxLoggerLevel) to high(TNxLoggerLevel) do
begin
if cl < aLevel then
begin
unsetLevel(cl);
end else
begin
setLevel(cl);
end;
end;
end;
procedure TNxLoggerMessageFilterLevelSet.setLevelSet(aLevelSet : TNxLoggerLevelSet);
begin
fLevelSet := aLevelSet;
end;
function  TNxLoggerMessageFilterLevelSet.isLevelInSet(aLevel : TNxLoggerLevel) : Boolean;
begin
result  := aLevel in fLevelSet;
end;
procedure TNxLoggerMessageFilterLevelSet.reset;
begin
fLevelSet := [NXLL_TRACE, NXLL_DEBUG, NXLL_INFO, NXLL_WARN, NXLL_ERROR, NXLL_FATAL ];
end;
{ **************************************************************************** }
{ ***** TNxLoggerMessageFilterByText ***************************************** }
{ **************************************************************************** }
constructor TNxLoggerMessageFilterByText.Create;
begin
inherited Create;
fText  := '';
end;
destructor TNxLoggerMessageFilterByText.Destroy;
begin
inherited Destroy;
end;
procedure TNxLoggerMessageFilterByText.AssignTo(Dest: TPersistent);
begin
if Dest is TNxLoggerMessageFilterByText then
begin
(Dest as TNxLoggerMessageFilterByText).fText := fText;
end;
end;
procedure TNxLoggerMessageFilterByText.saveToStream(aStream : TStream);
var wr  : TWriter;
begin
wr  := TWriter.Create(aStream, 1024);
try
wr.WriteString('FilterText');
wr.WriteString(fText);
wr.FlushBuffer;
finally
FreeAndNil(wr);
end;
end;
procedure TNxLoggerMessageFilterByText.loadFromStream(aStream : TStream);
var rd  : TReader;
zs  : String;
begin
rd  := TReader.Create(aStream, 1024);
try
zs  := rd.ReadString;
if lowercase(zs) = 'filtertext' then
begin
fText := rd.ReadString;
end else
begin
raise Exception.Create('parse error: "FilterText" expected!');
end;
finally
FreeAndNil(rd);
end;
end;
procedure TNxLoggerMessageFilterByText.setText(aValue : String);
begin
fText  := aValue;
end;
function  TNxLoggerMessageFilterByText.getText : String;
begin
result  := fText;
end;
procedure TNxLoggerMessageFilterByText.reset;
begin
fText  := '';
end;
{ **************************************************************************** }
{ ***** TNxLoggerMessageFilterModuleEquals *********************************** }
{ **************************************************************************** }
function  TNxLoggerMessageFilterModuleEquals.match(aMessage : TNxLoggerMessage) : Boolean;
begin
result  := false;
if aMessage <> nil then
begin
if lowercase(aMessage.LogModule) = lowercase(fText)  then
begin
result  := true;
end;
end;
end;
{ **************************************************************************** }
{ ***** TNxLoggerMessageFilterModuleStarting ********************************* }
{ **************************************************************************** }
function  TNxLoggerMessageFilterModuleStarting.match(aMessage : TNxLoggerMessage) : Boolean;
begin
result  := false;
if aMessage <> nil then
begin
if Pos(lowercase(fText), lowercase(aMessage.LogModule)) = 1 then
begin
result  := true;
end;
end;
end;
{ **************************************************************************** }
{ ***** TNxLoggerMessageFilterModuleContains ********************************* }
{ **************************************************************************** }
function  TNxLoggerMessageFilterModuleContains.match(aMessage : TNxLoggerMessage) : Boolean;
begin
result  := false;
if aMessage <> nil then
begin
if Pos(lowercase(fText), lowercase(aMessage.LogModule)) > 0 then
begin
result  := true;
end;
end;
end;
{ **************************************************************************** }
{ ***** TNxLoggerMessageFilterMessageEquals ********************************** }
{ **************************************************************************** }
function  TNxLoggerMessageFilterMessageEquals.match(aMessage : TNxLoggerMessage) : Boolean;
begin
result  := false;
if aMessage <> nil then
begin
if lowercase(aMessage.LogMessage) = lowercase(fText)  then
begin
result  := true;
end;
end;
end;
{ **************************************************************************** }
{ ***** TNxLoggerMessageFilterMessageStarting ******************************** }
{ **************************************************************************** }
function  TNxLoggerMessageFilterMessageStarting.match(aMessage : TNxLoggerMessage) : Boolean;
begin
result  := false;
if aMessage <> nil then
begin
if Pos(lowercase(fText), lowercase(aMessage.LogMessage)) = 1 then
begin
result  := true;
end;
end;
end;
{ **************************************************************************** }
{ ***** TNxLoggerMessageFilterMessageContains ******************************** }
{ **************************************************************************** }
function  TNxLoggerMessageFilterMessageContains.match(aMessage : TNxLoggerMessage) : Boolean;
begin
result  := false;
if aMessage <> nil then
begin
if Pos(lowercase(fText), lowercase(aMessage.LogMessage)) > 0 then
begin
result  := true;
end;
end;
end;
{ **************************************************************************** }
{ ***** TNxLoggerMessageFilterMachineEquals ********************************** }
{ **************************************************************************** }
function  TNxLoggerMessageFilterMachineEquals.match(aMessage : TNxLoggerMessage) : Boolean;
var cs  : String;
begin
result  := false;
if aMessage <> nil then
begin
if assigned(fOnMachineIdentRequired) then
begin
cs  := '';
fOnMachineIdentRequired(self, aMessage, cs);
if lowercase(fText) = lowercase(cs) then
begin
result  := true;
end;
end;
end;
end;
procedure TNxLoggerMessageFilterMachineEquals.AssignTo(Dest: TPersistent);
begin
if Dest is TNxLoggerMessageFilterMachineEquals then
begin
(Dest as TNxLoggerMessageFilterMachineEquals).fOnMachineIdentRequired := fOnMachineIdentRequired;
end;
end;
{ **************************************************************************** }
{ ***** TNxLoggerMessageFilterApplicationEquals ****************************** }
{ **************************************************************************** }
function  TNxLoggerMessageFilterApplicationEquals.match(aMessage : TNxLoggerMessage) : Boolean;
begin
result  := false;
if aMessage <> nil then
begin
if lowercase(fText) = lowercase(aMessage.ApplicationId) then
begin
result  := true;
end;
end;
end;
initialization
Classes.RegisterClass(TNxLoggerMessageFilterLevelSet);
Classes.RegisterClass(TNxLoggerMessageFilterModuleEquals);
Classes.RegisterClass(TNxLoggerMessageFilterModuleStarting);
Classes.RegisterClass(TNxLoggerMessageFilterModuleContains);
Classes.RegisterClass(TNxLoggerMessageFilterMessageEquals);
Classes.RegisterClass(TNxLoggerMessageFilterMessageStarting);
Classes.RegisterClass(TNxLoggerMessageFilterMessageContains);
Classes.RegisterClass(TNxLoggerMessageFilterMachineEquals);
Classes.RegisterClass(TNxLoggerMessageFilterApplicationEquals);
Classes.RegisterClass(TNxLogFormaterDefault);
Classes.RegisterClass(TNxLogFormaterTCP);
Classes.RegisterClass(TNxLogAppenderFile);
Classes.RegisterClass(TNxLogAppenderTCP);
fDefaultLogger := TNxLogger.Create(nil);
fDefaultLogger.addAppender(TNxLogAppenderFile.Create(fDefaultLogger));
finalization
FreeAndNil(fDefaultLogger);
Classes.UnRegisterClass(TNxLoggerMessageFilterLevelSet);
Classes.UnRegisterClass(TNxLoggerMessageFilterModuleEquals);
Classes.UnRegisterClass(TNxLoggerMessageFilterModuleStarting);
Classes.UnRegisterClass(TNxLoggerMessageFilterModuleContains);
Classes.UnRegisterClass(TNxLoggerMessageFilterMessageEquals);
Classes.UnRegisterClass(TNxLoggerMessageFilterMessageStarting);
Classes.UnRegisterClass(TNxLoggerMessageFilterMessageContains);
Classes.UnRegisterClass(TNxLoggerMessageFilterMachineEquals);
Classes.UnRegisterClass(TNxLoggerMessageFilterApplicationEquals);
Classes.UnRegisterClass(TNxLogFormaterDefault);
Classes.UnRegisterClass(TNxLogFormaterTCP);
Classes.UnRegisterClass(TNxLogAppenderFile);
Classes.UnRegisterClass(TNxLogAppenderTCP);
end.

Ein neues Projekt?

Wir sind gespannt!

Senden Sie uns eine Nachricht und wir informieren Sie näher über unsere individuellen Software-Lösungen!

    Hinweise zum Datenschutz gelesen und akzeptiert.

    css.php
    Kontaktieren Sie uns
    close slider

      Wir freuen uns auf den Kontakt mit Ihnen

      Hinterlassen Sie eine Nachricht für uns und wir treten schnellst möglich mit Ihnen in Verbindung.