#1 2020-06-08 16:12:52

jaclas
Member
Registered: 2014-09-12
Posts: 215

Call stack - how to get?

I use OnBeforeException event:

  TSynLog.Family.OnBeforeException := mormotLogOnBeforeException;

How to get call stack in this event method? Is possible?

Offline

#2 2020-06-08 16:41:41

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

Re: Call stack - how to get?

You have the TSynLogExceptionContext.EStack/EStackCount fields with the raw stack trace.

Then you would need to convert it into string, as SynLogException() does.

Offline

#3 2020-06-08 18:19:34

jaclas
Member
Registered: 2014-09-12
Posts: 215

Re: Call stack - how to get?

This is a very complex code, and also uses non-public methods and values such as TSynMapFile:

unit SynLog;
[...]

implementation

[...]

var
  ExeInstanceMapFile: TSynMapFile;

function GetInstanceMapFile: TSynMapFile;
begin
 [...]
end;

Should I duplicate this code and these objects?


I would have to use the only available class method that forces a TSynMapFile instance in the background:

class procedure TSynMapFile.Log(W: TTextWriter; aAddressAbsolute: PtrUInt; AllowNotCodeAddr: boolean);

...but this method requires TTextWriter, which I don't want to use in this case.


Wouldn't it be possible to make new, public method converting the callstack into text form in mORMot itself?
Please consider this solution.

Last edited by jaclas (2020-06-08 18:48:56)

Offline

#4 2020-06-09 09:05:09

pvn0
Member
From: Slovenia
Registered: 2018-02-12
Posts: 211

Re: Call stack - how to get?

How else are you going to get readable stack trace? There's no avoiding TSynMapFile.

Offline

#5 2020-06-09 09:46:43

jaclas
Member
Registered: 2014-09-12
Posts: 215

Re: Call stack - how to get?

I don't want to avoid TSynMapFile, I want to avoid having to duplicate code with SynLog (and problems with two TSynMapFile instances!). I just want the SynLog module to have a public function to read the callstack. This function could be used by TSynLog and external code (as I need it now).

Besides, TSynMapFile class should have one global instance (it is currently private).

A good solution would be to add a static class function to the TSynMapFile class, eg.:

class function TSynMapFile.GetCallStackAsStr(const CallStack: PPtrUInt) : TStrings;

or global function in a module, like this:

function GetCallStackAsStr(const CallStack: PPtrUInt) : TStrings;

This functionality would GREATLY extend the usability of SynLog! Even without a rest of mORMot!

Last edited by jaclas (2020-06-09 09:51:10)

Offline

#6 2020-06-09 13:39:15

EMartin
Member
From: Buenos Aires - Argentina
Registered: 2013-01-09
Posts: 337

Re: Call stack - how to get?

I use TSynLog.Add.Log(all StackTrace, ...) and was very helpful.


Esteban

Offline

#7 2020-06-10 06:51:59

jaclas
Member
Registered: 2014-09-12
Posts: 215

Re: Call stack - how to get?

@EMartin

Once again... I need to get and pass a call stack to my code as a text/string, how does your example solve my problem?

Offline

#8 2020-06-10 08:36:18

franfj
Member
Registered: 2018-03-28
Posts: 12

Re: Call stack - how to get?

The simplest solution is using the TSynLogFamiliy.EchoCustom:

    /// can be set to a callback which will be called for each log line
    // - could be used with a third-party logging system
    // - EchoToConsole or EchoCustom can be activated separately
    // - you may even disable the integrated file output, via NoFile := true
    property EchoCustom: TOnTextWriterEcho read fEchoCustom write SetEchoCustom;

The EchoCustom receives the Level and the formated text, so you could use that text to do whatever you want.

Offline

#9 2020-06-10 09:57:55

jaclas
Member
Registered: 2014-09-12
Posts: 215

Re: Call stack - how to get?

Are you suggesting that I should read and parse the whole log to get a potential exception? Really?

I need to catch an exception, decode the call stack and send it somewhere... what you're recommending is a lot of over-the-top ideas.
I want SynLog (or other part of mormot) to let me convert the callstack (from OnBeforeException level) to thong with its internal tricks.
So, I just want Arnaud to refactor the code a bit and give external access to callstack conversion (using a private TSynMapFile instance)

Last edited by jaclas (2020-06-10 09:58:49)

Offline

#10 2020-06-10 14:10:41

franfj
Member
Registered: 2018-03-28
Posts: 12

Re: Call stack - how to get?

jaclas wrote:

Are you suggesting that I should read and parse the whole log to get a potential exception? Really?

I need to catch an exception, decode the call stack and send it somewhere... what you're recommending is a lot of over-the-top ideas.
I want SynLog (or other part of mormot) to let me convert the callstack (from OnBeforeException level) to thong with its internal tricks.
So, I just want Arnaud to refactor the code a bit and give external access to callstack conversion (using a private TSynMapFile instance)

You don't need to parse the whole log, just handle the levels that report exceptions (sllExceptionOS and sllException).

If you need another implementation, is not hard to extract all internal exception stack processing from

// this is the main entry point for all intercepted exceptions
procedure SynLogException(const Ctxt: TSynLogExceptionContext);

Anyway, since SynLog does not get callstack for delphi win64 I used JCLDebug (give it a look, although it has another disadvantages).

Offline

#11 2020-06-16 18:37:24

jaclas
Member
Registered: 2014-09-12
Posts: 215

Re: Call stack - how to get?

Arnaud, I know you have been very busy lately with changes in SQLite, but please read my above posts and think about making available in the interface section (public) of the methods to get/convert call stack... please :-)

Offline

#12 2020-06-16 22:29:09

mpv
Member
From: Ukraine
Registered: 2012-03-24
Posts: 1,571
Website

Re: Call stack - how to get?

@jaclas - if you really need this feature you can try to do a poll request on github. At last this is an Open Source project. And don't forgett to verify your changes for both Delphy and FPC wink

Offline

#13 2020-06-17 09:21:13

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

Re: Call stack - how to get?

Offline

#14 2020-06-17 16:22:02

jaclas
Member
Registered: 2014-09-12
Posts: 215

Re: Call stack - how to get?

Thanks Arnaud!

I still have a problem with the callstack, with the OnBeforeException event (from TSynLogFamily), it is almost empty, there is only a line calling the exception. The problem is probably not in the callstack extraction itself, because the EStackCount value of the aExceptionContext object is zero.

See:

0RUekXOkk0sYC1JaoYYo6FtfOM9NsI3R1QwFJgquFdoI8XInRC3piPUx6uFP6BCy.png

Offline

#15 2020-06-17 17:22:57

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

Re: Call stack - how to get?

Perhaps you don't have stack frames activated...

Offline

#16 2020-06-17 18:35:09

jaclas
Member
Registered: 2014-09-12
Posts: 215

Re: Call stack - how to get?

Stack frames are active of course.

When I set result to True in OnBeforeException (so, SynLog catches and log an exception) then I get in log all data from call stack:

20200617 18310722 EXC   EPathNotFoundException ("some example exception") [] at 
6629ca Main.TfrmMain.btnMakeExceptionClick (96)  stack trace API 
6629ca Main.TfrmMain.btnMakeExceptionClick (96) 
544d65 Vcl.Controls.TControl.Click (7537) 
5492c0 Vcl.Controls.TWinControl.WndProc (10280) 
55dec5 Vcl.StdCtrls.TButtonControl.WndProc (5308) 
[...]

Offline

#17 2020-06-23 16:31:12

jaclas
Member
Registered: 2014-09-12
Posts: 215

Re: Call stack - how to get?

Arnaud, I prepare very simple example (dpr with 65 lines), please check this code and callstack readed from OnBeforeException event level:

https://pastebin.com/8CXhiSgS

I get this result (first part is result od event, second part is standard SynLog catching exsception log):

--- mormotLogOnBeforeException -------- begin --------
Exception class: Exception
line #0:  onBeforeExceptionTest.InsideProc (38)
--- mormotLogOnBeforeException --------- end ----------
20200623 16272444 EXC   Exception ("test exception from inside procedure") [] at
 54cc89 onBeforeExceptionTest.InsideProc (38)  stack trace API 54cc89 onBeforeEx
ceptionTest.InsideProc (38) 54ccec onBeforeExceptionTest.OutsideProc (43) 54ccf8
 onBeforeExceptionTest.VeryOutsideProc (48) 54ce24 onBeforeExceptionTest.Main (5
8)

Why in OnBeforeException (where I use new introduced TSynMapFile.FindStackTrace() method) I can't get full stack?

Offline

#18 2020-06-23 19:50:22

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

Re: Call stack - how to get?

Because the log version is browsing the call stack by hand, whereas the Delphi Exception handler didn't populate the call stack.

Offline

Board footer

Powered by FluxBB