exceptiondelphiloggingpascalassertion

How to get (current code line, current unit, current function) without using assertions?


I am trying to create a log system in my program that will log debugging messages on text files, and I want to save the exact place in the code where the log message routine was called, but I don’t want to use the Assert function because it creates exceptions and this system is not for logging exceptions only. Also I have to write some debugging info.

Example using assert:

procedure AnyProcedure();
begin
  try
    Assert(1=0);
  except
    on E: Exception do
      Log.AddLine('Log occurred is '+E.Message+' : Start');//Log occurred is "c:\progr~..jkdj.pas" at line [29]
  end;

  //....some code
  try
    Assert(1=0);
  except
    on E: Exception do
      Log.AddLine('Log occurred is '+E.Message+' : Step1 done');//Log occurred is "c:\progr~..jkdj.pas" at line [37]
  end;
   
  //....some code
  try
    Assert(1=0);
  except
    on E: Exception do
      Log.AddLine('Log occurred is '+E.Message+' : Step2 done');//Log occurred is "c:\progr~..jkdj.pas" at line [45]
  end;

  //....some code
  try
    Assert(1=0);
  except
    on E: Exception do
      Log.AddLine('Log occurred is '+E.Message+' : Step3 done');//Log occurred is  "c:\progr~..jkdj.pas" at line [53]
  end;

  //....some code
  try
    Assert(1=0);
  except
    on E: Exception do
      Log.AddLine('Log '+E.Message+' : End');//Log occurred is "c:\progr~..jkdj.pas" at line [61]
  end;
end;

This works fine. The only thing is that it raises an exception and the code becomes too big, so I can’t use a function – see next example function LogMessage – and call it in another place because the line will always be the same. Also the file name will be where the LogMessage function is implemented:

Not working example:

procedure LogMessage(AMessage: String);
var AFile, ALine: String;
begin
  try
    Assert(1=0);             //line 29
  except
    on E: Exception do
    begin
      AFile:= Copy(E.Message, Pos(' (', E.Message)+2, Pos(', line ', E.Message)-Pos(' (', E.Message)-2);
      ALine:= Copy(E.Message, Pos(', line ', E.Message)+7, Pos(')', E.Message)-Pos(', line ', E.Message)-7);
      ShowMessage('Log occurred in file "'+AFile+'" at line ['+ALine+'] : '+AMessage);
    end;
  end;
end;

procedure AnyProcedure();
begin
  LogMessage('Start'); //Log occurred in file "c:\progr~....jkashdj.pas" at line [29]
//....
  LogMessage('step1'); //Log occurred in file "c:\progr~....jkashdj.pas" at line [29]
//....
  LogMessage('step2'); //Log occurred in file "c:\progr~....jkashdj.pas" at line [29]
//....
  LogMessage('step3'); //Log occurred in file "c:\progr~....jkashdj.pas" at line [29]
//....
  LogMessage('end');
end

Solution

  • You can bind your own TAssertErrorProc procedure to the AssertErrorProc variable. You might write something like this:

    procedure OnAssert(const Message, Filename: string; LineNumber: Integer;
      ErrorAddr: Pointer);
    begin
      ShowMessage(Format('Assert in file "%s" at line %d.', [Filename, LineNumber]));
    end;
    
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      AssertErrorProc := OnAssert;
    end;