I have just written my own logging framework (very lightweight, no need for a big logging framework). It consists of an interface ILogger and a number of classes implementing that interface. The one I have a question about is TGUILogger which takes a TStrings as the logging target and synchronizes the logging with the main thread so that the Items member of a listbox can be used as the target.
type
ILogger = Interface (IInterface)
procedure Log (const LogString : String; LogLevel : TLogLevel);
procedure SetLoggingLevel (LogLevel : TLogLevel);
end;
type
TGUILogger = class (TInterfacedObject, ILogger)
public
constructor Create (Target : TStrings);
procedure Log (const LogString : String; LogLevel : TLogLevel);
procedure SetLoggingLevel (LogLevel : TLogLevel);
private
procedure PerformLogging;
end;
procedure TGUILogger.Log (const LogString : String; LogLevel : TLogLevel);
begin
TMonitor.Enter (Self);
try
FLogString := GetDateTimeString + ' ' + LogString;
TThread.Synchronize (TThread.CurrentThread, PerformLogging);
finally
TMonitor.Exit (Self);
end;
end;
procedure TGUILogger.PerformLogging;
begin
FTarget.Add (FLogString);
end;
The logging works, but the application does not close properly. It seems to hang in the Classes unit. The stack trace:
System.Halt0, System.FinalizeUnits, Classes.Finalization, Classes.FreeExternalThreads, System.TObject.Free, Classes.TThread.Destroy, Classes.TThread.RemoveQueuedEvents
What am I doing wrong here?
EDIT: I just found the following hint in the Delphi help for TThread.StaticSynchronize
Warning: Do not call StaticSynchronize from within the main thread. This can cause
an infinite loop.
This could be exactly my problem since some logging request come from the main thread. How can I solve this?