Search code examples
delphithread-safetydelphi-xe

How to handle Log in a Threaded manner


I have a form with a TMemo that I want to show what is going on in several services started by the application.

What I have running:

  • idHTTPServer running with idContext responding to requests
  • a Thread downloading updates from Dropbox
  • idUDPServer responding to UDP requests
  • another thread taking care of some database stuff.
  • the main application thread also needed to add log

Basically, I need to know how to create a standard, unified, thread safe way to channel the log messages to my TMemo and keep the user updated of what is going on.


Solution

  • Since you are already using Indy anyway, you can use Indy's TIdSync (synchronous) or TIdNotify (asynchronous) class to access the TMemo safely. For simple logging purposes, I would use TIdNotify, eg:

    type
      TLog = class(TIdNotify)
      protected
        FMsg: string;
        procedure DoNotify; override;
      public
        class procedure LogMsg(const AMsg; string);
      end;
    
    procedure TLog.DoNotify;
    begin
      Form1.Memo1.Lines.Add(FMsg);
    end;
    
    class procedure TLog.LogMsg(const AMsg: string);
    begin
      with TLog.Create do
      try
        FMsg := AMsg;
        Notify;
      except
        Free;
        raise;
      end;
    end;
    

    Then you can directly call it in any thread like this:

    TLog.LogMsg('some text message here');
    

    UPDATE: in Delphi 2009 and later, you can use anonymous procedures with the static versions of TThread.Synchronize() and TThread.Queue(), thus making Indy's TIdSync and TIdNotify classes obsolete, eg:

    type
      TLog = class
      public
        class procedure LogMsg(const AMsg; string);
      end;
    
    class procedure TLog.LogMsg(const AMsg: string);
    begin
      TThread.Queue(nil,
        procedure
        begin
          Form1.Memo1.Lines.Add(AMsg);
        end
      );
    end;