You are not logged in.
Pages: 1
Hi Arnaud,
Is it possible to have a callback event for SynLog that returns a custom filename? Either that, or move the filename generation routine into another procedure/function that is virtual and may be overridden by a descendant class?
This is useful if I want to only have a daily log, so if the programme gets restarted, logging may resume in the same file. Also, if the file already exists, perhaps logHeaderWritten should be set in fInternalFlags, to prevent writing of header again.
Thank you!
Offline
Hi Arnaud,
What do you think of this? (SynCommons.pas)
SynCommons.pas | 95 +++++++++++++++++++++++++++++++++++-----------------------
1 file changed, 57 insertions(+), 38 deletions(-)
diff --git a/SynCommons.pas b/SynCommons.pas
index d673641..3fec809 100644
--- a/SynCommons.pas
+++ b/SynCommons.pas
@@ -10705,6 +10705,7 @@ type
/// how stack trace shall be computed
TSynLogStackTraceUse = (stManualAndAPI,stOnlyAPI,stOnlyManual);
+ TSynLogExistsAction = (acOverwrite, acAppend, acAppendWithHeader);
{/ regroup several logs under an unique family name
- you should usualy use one family per application or per architectural
@@ -10762,6 +10763,7 @@ type
fRotateFileCount: cardinal;
fRotateFileSize: cardinal;
fRotateFileAtHour: integer;
+ fLogExistsAction: TSynLogExistsAction;
function CreateSynLog: TSynLog;
{$ifdef MSWINDOWS}
procedure SetAutoFlush(TimeOut: cardinal);
@@ -10945,6 +10947,8 @@ type
// be appended instead
// - TSynLogFile class and our LogView tool will handle both patterns
property EndOfLineCRLF: boolean read fEndOfLineCRLF write fEndOfLineCRLF;
+ // action to take if log file already exists. Defaults to append with header
+ property LogExistsAction: TSynLogExistsAction read fLogExistsAction write fLogExistsAction;
end;
/// thread-specific internal context used during logging
@@ -11025,12 +11029,12 @@ type
procedure CreateLogWriter; virtual;
{$ifndef DELPHI5OROLDER}
procedure LogInternal(Level: TSynLogInfo; TextFmt: PWinAnsiChar;
- const TextArgs: array of const; Instance: TObject); overload;
+ const TextArgs: array of const; Instance: TObject); overload;
{$endif}
procedure LogInternal(Level: TSynLogInfo; const Text: RawUTF8;
Instance: TObject; TextTruncateAtLength: integer); overload;
procedure LogInternal(Level: TSynLogInfo; aName: PWinAnsiChar;
- aTypeInfo: pointer; var aValue; Instance: TObject=nil); overload;
+ aTypeInfo: pointer; var aValue; Instance: TObject=nil); overload;
// any call to this method MUST call UnLock
function LogHeaderLock(Level: TSynLogInfo): boolean;
procedure LogTrailerUnLock(Level: TSynLogInfo); {$ifdef HASINLINE}inline;{$endif}
@@ -11048,6 +11052,7 @@ type
function Instance: TSynLog;
function ConsoleEcho(Sender: TTextWriter; Level: TSynLogInfo;
const Text: RawUTF8): boolean; virtual;
+ procedure GenerateFileName; virtual;
public
/// intialize for a TSynLog class instance
// - WARNING: not to be called directly! Use Enter or Add class function instead
@@ -41663,6 +41668,7 @@ begin
fExceptionIgnore := TList.Create;
fLevelStackTrace :=
[sllError,sllException,sllExceptionOS,sllFail,sllLastError,sllStackTrace];
+ fLogExistsAction := acAppendWithHeader;
end;
function TSynLogFamily.CreateSynLog: TSynLog;
@@ -42644,48 +42650,61 @@ begin
end;
end;
-procedure TSynLog.CreateLogWriter;
+procedure TSynLog.GenerateFileName;
{$ifndef MSWINDOWS}
var i: integer;
{$endif}
-var timeNow,hourRotate,timeBeforeRotate: TDateTime;
+var timeNow, hourRotate, timeBeforeRotate: TDateTime;
+begin
+ {$ifdef MSWINDOWS}
+ ExeVersionRetrieve;
+ fFileName := Ansi7ToString(ExeVersion.ProgramName);
+ if fFamily.IncludeComputerNameInFileName then
+ fFileName := fFileName+' ('+Ansi7ToString(ExeVersion.Host)+')';
+ {$else}
+ fFileName := ExtractFileName(ParamStr(0));
+ i := Pos('.',fFileName);
+ if i>0 then
+ SetLength(fFileName,i-1);
+ {$endif}
+ fFileRotationSize := 0;
+ if fFamily.fRotateFileCount>0 then begin
+ if fFamily.fRotateFileSize>0 then
+ fFileRotationSize := fFamily.fRotateFileSize shl 10; // size KB -> B
+ if fFamily.fRotateFileAtHour in [0..23] then begin
+ hourRotate := EncodeTime(fFamily.fRotateFileAtHour,0,0,0);
+ timeNow := Time;
+ if hourRotate<timeNow then
+ hourRotate := hourRotate+1; // trigger will be tomorrow
+ timeBeforeRotate := hourRotate-timeNow;
+ fFileRotationNextHour := GetTickCount64+trunc(timeBeforeRotate*MSecsPerDay);
+ end;
+ end;
+ if (fFileRotationSize=0) and (fFileRotationNextHour=0) then
+ fFileName := fFileName+' '+Ansi7ToString(NowToString(false));
+ {$ifdef MSWINDOWS}
+ if IsLibrary then
+ fFileName := fFileName+' '+ExtractFileName(GetModuleName(HInstance));
+ {$endif}
+ if fFamily.fPerThreadLog=ptOneFilePerThread then
+ fFileName := fFileName+' '+IntToString(GetCurrentThreadId);
+ fFileName := fFamily.fDestinationPath+fFileName+fFamily.fDefaultExtension;
+end;
+
+procedure TSynLog.CreateLogWriter;
begin
if fWriterStream=nil then begin
- {$ifdef MSWINDOWS}
- ExeVersionRetrieve;
- fFileName := Ansi7ToString(ExeVersion.ProgramName);
- if fFamily.IncludeComputerNameInFileName then
- fFileName := fFileName+' ('+Ansi7ToString(ExeVersion.Host)+')';
- {$else}
- fFileName := ExtractFileName(ParamStr(0));
- i := Pos('.',fFileName);
- if i>0 then
- SetLength(fFileName,i-1);
- {$endif}
- fFileRotationSize := 0;
- if fFamily.fRotateFileCount>0 then begin
- if fFamily.fRotateFileSize>0 then
- fFileRotationSize := fFamily.fRotateFileSize shl 10; // size KB -> B
- if fFamily.fRotateFileAtHour in [0..23] then begin
- hourRotate := EncodeTime(fFamily.fRotateFileAtHour,0,0,0);
- timeNow := Time;
- if hourRotate<timeNow then
- hourRotate := hourRotate+1; // trigger will be tomorrow
- timeBeforeRotate := hourRotate-timeNow;
- fFileRotationNextHour := GetTickCount64+trunc(timeBeforeRotate*MSecsPerDay);
- end;
- end;
- if (fFileRotationSize=0) and (fFileRotationNextHour=0) then
- fFileName := fFileName+' '+Ansi7ToString(NowToString(false));
- {$ifdef MSWINDOWS}
- if IsLibrary then
- fFileName := fFileName+' '+ExtractFileName(GetModuleName(HInstance));
- {$endif}
- if fFamily.fPerThreadLog=ptOneFilePerThread then
- fFileName := fFileName+' '+IntToString(GetCurrentThreadId);
- fFileName := fFamily.fDestinationPath+fFileName+fFamily.fDefaultExtension;
+ GenerateFileName;
if fFamily.NoFile then
- fWriterStream := TFakeWriterStream.Create else begin
+ fWriterStream := TFakeWriterStream.Create else
+ begin
+ if FileExists(fFileName) then
+ begin
+ if fFamily.fLogExistsAction = acOverwrite then
+ DeleteFile(fFileName)
+ else if fFamily.fLogExistsAction = acAppend then
+ Include(fInternalFlags,logHeaderWritten);
+ end;
if (fFileRotationSize=0) or not FileExists(fFileName) then
TFileStream.Create(fFileName,fmCreate).Free; // create a void file
fWriterStream := TFileStream.Create(fFileName, // open with read sharing
Alternatively, if this is not possible, then I will subclass TSynLog. Thank you!
Last edited by cheemeng (2014-09-19 12:35:49)
Offline
Additional updates (my previous patch was buggy and incomplete)...
procedure TSynLog.CreateLogWriter;
begin
if fWriterStream=nil then begin
GenerateFileName;
if fFamily.NoFile then
fWriterStream := TFakeWriterStream.Create else
begin
if FileExists(fFileName) and (fFamily.fLogExistsAction <> acOverwrite) then
begin
if fFamily.fLogExistsAction = acAppend then
Include(fInternalFlags,logHeaderWritten);
end else
if (fFileRotationSize=0) or not FileExists(fFileName) then
TFileStream.Create(fFileName,fmCreate).Free; // create a void file
fWriterStream := TFileStream.Create(fFileName, // open with read sharing
fmOpenReadWrite or fmShareDenyWrite);
end;
if (fFileRotationSize>0) or (fFamily.fLogExistsAction <> acOverwrite) then
fWriterStream.Seek(0,soFromEnd); // in rotation mode, append at the end
end;
if fWriterClass=nil then
fWriterClass := TTextWriter;
if fWriter=nil then
fWriter := fWriterClass.Create(fWriterStream,fFamily.BufferSize);
fWriter.EndOfLineCRLF := fFamily.EndOfLineCRLF;
if integer(fFamily.EchoToConsole)<>0 then
fWriter.EchoAdd(ConsoleEcho);
if Assigned(fFamily.EchoCustom) then
fWriter.EchoAdd(fFamily.EchoCustom);
if Assigned(fFamily.fEchoRemoteClient) then
fWriter.EchoAdd(fFamily.fEchoRemoteEvent);
end;
Offline
Hi Arnaud,
Would just like to know what do you think of the proposed changes.
If it should not go to the main code, then let me know and I'll subclass it myself. Thanks!
Offline
Online
Thanks Arnaud!
Offline
There is a bug that prevents log file appends from working correctly... it ends up overwriting the log file nevertheless if RotationSize is not set (Line 42753), which is why I proposed by code above.
To cater for your updated log file access retry code, the code can be updated to be as follows:
for retry := 0 to 2 do begin
for i := 1 to 10 do
try
if FileExists(fFileName) and (fFamily.FileExistsAction <> acOverwrite) then
begin
if fFamily.FileExistsAction = acAppend then
Include(fInternalFlags,logHeaderWritten);
end else if (fFileRotationSize=0) or not FileExists(fFileName) then
TFileStream.Create(fFileName,fmCreate).Free; // create a void file
fWriterStream := TFileStream.Create(fFileName,
fmOpenReadWrite or fmShareDenyWrite); // open with read sharing
break;
except
on Exception do
Sleep(100);
end;
if fWriterStream<>nil then
break;
fFileName := ChangeFileExt(fFileName,'-'+fFamily.fDefaultExtension);
end;
Lines 42742 to 42748 are unnecessary.
Offline
Line 42774 also needs amendment to
if (fFileRotationSize>0) or (fFamily.FileExistsAction <> acOverwrite) then
Last edited by cheemeng (2014-09-28 18:52:00)
Offline
Pages: 1