#1 2015-04-28 14:18:29

ASiwon
Member
From: Poland
Registered: 2015-01-30
Posts: 82

Some logging related questions

Hello,

I have some problem with using TSynLog.Family.EchoCustom event. For following simple code:

var
  log: ISynLog;
  echoObject: TSomeObjectWichSupportsEvent;


log := TSynLog.Add;
log.Instance.Family.EchoCustom := echoObject.Write;
log.Log(sllInfo, 'Info logging');
log.Instance.Family.EchoCustom := nil;
echoObject.Free;

After executing this sequence all log calls trying to call event in freed object instance. It is because fWriter is still storing and using for event reference to freed objects. If I call

log.Instance.Writer.EchoRemove(echoObject.Write);

then everything works correctly. Is it correct way or just calling log.Instance.Family.EchoCustom := nil; should be enough? I have similar problem while adding event. Before first log operation EchoCustom should be assigned to the Familly.EchoCustom event and after first log operation it should be added to the writer using Writer.EchoAdd method. Is it possible to add one way to set and remove EchoCustom event?

I have one question yet. Is it possible to change ISynLog base interface to IInvokable? In some cases I want to check in unit tests my code is logging properly. With mocking possibility it would be very easy.


best regards
Adam Siwon

Offline

#2 2015-04-29 06:21:55

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,150
Website

Re: Some logging related questions

ASiwon wrote:

Is it possible to change ISynLog base interface to IInvokable? In some cases I want to check in unit tests my code is logging properly. With mocking possibility it would be very easy.

IMHO this is not possible, due to how the methods are defined.
Just try it: the compiler complains about 'array of const' parameters.
And there are overloaded methods, so mocking/stubbing may be impossible (at least with mORMot.pas, which expect unique method names AFAIR).

But we may mock the Writer class, or something in-between ISynLog methods and the Writer instance.

Offline

#3 2015-04-29 09:34:09

ASiwon
Member
From: Poland
Registered: 2015-01-30
Posts: 82

Re: Some logging related questions

ab wrote:

IMHO this is not possible, due to how the methods are defined.
Just try it: the compiler complains about 'array of const' parameters.

But we may mock the Writer class, or something in-between ISynLog methods and the Writer instance.

Thank you for your answer. This is better idea than creating mock or stub possibility for ISynLog interface! This allow me to test log messages even if ISynLog instance is created inside of the procedure (using TSynLog.Enter method)

For now I'm trying to use EchoCustom event to test messages which are saved in log. I have some problem with this. I wrote small example to explain the problem:

function TForm1.MemoLog(Sender: TTextWriter; Level: TSynLogInfo; const Text: RawUTF8): boolean;
begin
  Memo1.Lines.Add('MemoLog call: ' + IntToStr(Integer(Level)));
  Memo1.Lines.Add(Text);
  Result := True;
end;

procedure TForm1.btn1Click(Sender: TObject);
var
  log: ISynLog;
begin
  log := TSynLog.Add;
  log.Instance.Family.EchoCustom := MemoLog;
  if log.Instance.Writer <> nil then
    log.Instance.Writer.EchoAdd(MemoLog);
  log.Instance.Family.Level := LOG_VERBOSE;
  log.Log(sllWarning, 'Some warning');
  log.Instance.Writer.EchoRemove(MemoLog);
  log := nil;

  log := TSynLog.Add;
  log.Instance.Family.EchoCustom := MemoLog;
  log.Instance.Writer.EchoAdd(MemoLog);
  log.Instance.Family.Level := LOG_VERBOSE - [sllWarning];
  log.Log(sllWarning, 'Some warning');
  log.Instance.Writer.EchoRemove(MemoLog);
  log := nil;

  raise EORMException.Create('Error Message');
end;

This shows how from view of logging mechanism works my test procedure. I hope this is correct code which should works correctly. If I call btn1Click once then everything is Ok. In memo are added lines:

MemoLog call: 4
20150429 11190807 warn  Some warning

But when I call btn1Click second and next times then in memo are added lines:

MemoLog call: 4

in Text param of function MemoLog is empty string. After some times of debugging I have changed procedure TTextWriter.EchoAdd to:

procedure TTextWriter.EchoAdd(const aEcho: TOnTextWriterEcho);
begin
  if self<>nil then
    if MultiEventAdd(fEchos,TMethod(aEcho)) then
      if fEchos<>nil then
        fEchoStart := B-fTempBuf+1; // ignore any previous buffer
end;

in original source condition is: if fEchos=nil then. After this correction proper warning message is added to memo every time I call procedure: btn1Click. Could you help me and check where exactly exists a problem? I'm using DXE4 and mORMot from 27 April 2015 18:57:25

And there are overloaded methods, so mocking/stubbing may be impossible (at least with mORMot.pas, which expect unique method names AFAIR).

Is it any chance to change it? Sometimes I'm writing unit test for class which use interfaces with overloaded procedures. Possibility of creating stub or mock for such interfaces would be very usefull.


best regards
Adam Siwon

Offline

#4 2015-04-29 12:25:20

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,150
Website

Re: Some logging related questions

I've fixed the TTextWriter.EchoAdd() issue with http://synopse.info/fossil/info/52573ec04a
Thanks for the feedback.

Sadly, support of overloaded methods would need to add the parameters types to the method name, so that overloaded functions would be identified...
But we currently identify methods via interfacename.methodname, e.g. at REST level, or within JSON process, or when defining the methods (including stubs and mocks).
So adding this feature may add a lot of code modifications... with the risk of introducing regressions...

Offline

#5 2015-04-30 16:08:48

ASiwon
Member
From: Poland
Registered: 2015-01-30
Posts: 82

Re: Some logging related questions

ab wrote:

I've fixed the TTextWriter.EchoAdd() issue with http://synopse.info/fossil/info/52573ec04a
Thanks for the feedback.

Thank you very much. Now it works as expected. :-)


best regards
Adam Siwon

Offline

Board footer

Powered by FluxBB