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.
