Title: A simple yet useful Logger component (replaces TComponent)
Question: Ever wonderd how to easily incorporate logging functionality into your delphi programs, without the hassle of copying the same code over and over again to every unit ?
Answer:
The TLogger component explained here is a simple and very useful tool for programmers when they want to incorporate LOGGING capabilities into their programs.
The TLogger presented here is thread-safe and is extreamly easy to use.
It also detects if the parent is of the same base type and inherits
the Syncronization (thread safe behaviour) from the parent.
Usage:
1 Create your TComponent based component with the TLogger
as the inherited class instead
Ex: TMyCompo = class(TLogger)
private
protected
public
published
end;
2 Initialize the LogPath property. It defaults to the windows
TEMP dir
3 Call the Log(''); method to log something !
The .log file is named YYYYMMDD.LOG where the Y,M and D are
the year,month and date.
-----------CUT-------------CUT--------------
unit Logger;
interface
uses
Windows, Messages, SysUtils, Classes, SyncObjs;
type
TLogger = class(TComponent)
private
{ Private declarations }
protected
{ Protected declarations }
Sync : TCriticalSection;
FreeSync : Boolean;
public
{ Public declarations }
LogPath : String;
LogFileName : String;
Constructor Create(AOwner:TComponent); Override;
Destructor Destroy; Override;
{ LOG procedure }
Procedure Log( Str:String ); Virtual;
published
{ Published declarations }
end;
implementation
{ TLogger }
constructor TLogger.Create(AOwner:TComponent);
Var
B : Array[0..1024] of Char;
P : PChar;
begin
Inherited Create(AOwner);
{ LogPath = Windows Temp directory }
P := @B;
GetTempPath( Sizeof(B),P);
LogPath := StrPas(P);
{ If the owner is a TLogger get the parameters from it ! }
If (AOwner IS TLogger) then
Begin
LogPath := TLogger(AOwner).LogPath;
LogFileName := TLogger(AOwner).LogFileName;
Sync := TLogger(AOwner).Sync;
FreeSync := False;
End Else
Begin
{ Create the logger component and make sure we free it later }
Sync := TCriticalSection.Create;
FreeSync := True;
End;
end;
destructor TLogger.Destroy;
begin
{ Free the Sync object }
If Assigned(Sync) AND (FreeSync) then
Begin
{ Make sure nobody else is using the Sync object }
Sync.Enter;
Sync.Leave;
{ Free it }
Sync.Free;
Sync := NIL;
End;
{ Call inherited method }
Inherited Destroy;
end;
Procedure TLogger.Log( Str: String );
Var
F : TFileStream;
S : String;
FN : String;
OK : Boolean;
Times : Integer;
begin
Try
{ Enter Sync state }
Sync.Enter;
{ Build Log-String }
S := FormatDateTime('HH:NN:SS',Now)+' '+Str+#13#10
{ Build Filename }
If LogFileName='' then
FN := IncludeTrailingPathDelimiter( LogPath )+
FormatDateTime('YYYYMMDD',Date)+'.log';
Else
FN := IncludeTrailingPathDelimiter( LogPath )+LogFileName;
{ Set timer }
Times := 10; // Maximum 10 tries
Repeat
OK := True;
Try
F := NIL;
Try
{ Open / Create file }
If FileExists( FN ) then
F := TFileStream.Create( FN, fmOpenWrite OR fmShareDenyWrite )
Else
F := TFileStream.Create( FN, fmCreate OR fmShareDenyWrite );
{ Go to end }
F.Seek( 0, soFromEnd);
{ Append data }
F.Write( S[1], Length(S));
Finally
F.Free;
End;
Except
On E:Exception do
Begin
OK := False;
{ Decrement try counter }
Dec( Times );
{ Terinate looping or sleep 10 ms and try again }
If Times=0 then OK := True
Else SleepEx(10,True);
End;
End;
Until OK;
Finally
{ Leave sync }
Sync.Leave;
End;
end;
end.