How to get a stack trace from a processed / caught exception and upload it to the trace log

We created the Datasnap service (with Delphi XE), using Bob Swart's white paper as a guide. It works great, and we deployed it to our test server.

Now the problem arises, when we performed a large number of requests (via JMeter), some memory corruption occurs. Some requests succeed, some with access violations. In the end, it became so corrupt that each request to our OWN methods (and not DSAdmin) responds with an access violation.

However, I cannot access stacktrace to get additional information because the exception has already been caught in request processing.

If I heavily test the VCL version of this application, it will work correctly.

Does anyone know what this might be, or is experiencing the same problem, or can you help me get the stack trace from the caught exception (in someone else's code that I cannot edit)?

Thanks in advance.

+4
source share
2 answers

To log both caught and uncaught exceptions using the JEDI JCL, you must install the JEDI JCL .

Then try code similar to this code taken from jcl\examples\windows\debug\framestrack\FramesTrackDemoMain.pas :

You must compile the full debugging information in the compiler and linker options in the delphi project options for this to work.

Note that you do not need to throw a LogException, it is automatically called when you add an exception notification callback (JclAddExceptNotifier). remember to also call JclRemoveExceptNotifier when the form or data module from which you added it is destroyed, as shown below:

 procedure TForm1.LogException(ExceptObj: TObject; ExceptAddr: Pointer; IsOS: Boolean); var TmpS: string; ModInfo: TJclLocationInfo; I: Integer; ExceptionHandled: Boolean; HandlerLocation: Pointer; ExceptFrame: TJclExceptFrame; begin TmpS := 'Exception ' + ExceptObj.ClassName; if ExceptObj is Exception then TmpS := TmpS + ': ' + Exception(ExceptObj).Message; if IsOS then TmpS := TmpS + ' (OS Exception)'; mmLog.Lines.Add(TmpS); ModInfo := GetLocationInfo(ExceptAddr); mmLog.Lines.Add(Format( ' Exception occured at $%p (Module "%s", Procedure "%s", Unit "%s", Line %d)', [ModInfo.Address, ModInfo.UnitName, ModInfo.ProcedureName, ModInfo.SourceName, ModInfo.LineNumber])); if stExceptFrame in JclStackTrackingOptions then begin mmLog.Lines.Add(' Except frame-dump:'); I := 0; ExceptionHandled := False; while (chkShowAllFrames.Checked or not ExceptionHandled) and (I < JclLastExceptFrameList.Count) do begin ExceptFrame := JclLastExceptFrameList.Items[I]; ExceptionHandled := ExceptFrame.HandlerInfo(ExceptObj, HandlerLocation); if (ExceptFrame.FrameKind = efkFinally) or (ExceptFrame.FrameKind = efkUnknown) or not ExceptionHandled then HandlerLocation := ExceptFrame.CodeLocation; ModInfo := GetLocationInfo(HandlerLocation); TmpS := Format( ' Frame at $%p (type: %s', [ExceptFrame.ExcFrame, GetEnumName(TypeInfo(TExceptFrameKind), Ord(ExceptFrame.FrameKind))]); if ExceptionHandled then TmpS := TmpS + ', handles exception)' else TmpS := TmpS + ')'; mmLog.Lines.Add(TmpS); if ExceptionHandled then mmLog.Lines.Add(Format( ' Handler at $%p', [HandlerLocation])) else mmLog.Lines.Add(Format( ' Code at $%p', [HandlerLocation])); mmLog.Lines.Add(Format( ' Module "%s", Procedure "%s", Unit "%s", Line %d', [ModInfo.UnitName, ModInfo.ProcedureName, ModInfo.SourceName, ModInfo.LineNumber])); Inc(I); end; end; mmLog.Lines.Add(''); end; procedure TForm1.FormCreate(Sender: TObject); begin JclAddExceptNotifier(Form1.LogException); end; procedure TForm1.FormDestroy(Sender: TObject); begin JclRemoveExceptNotifier(Form1.LogException); end; 

This is the usual initialization code:

 initialization JclStackTrackingOptions := JclStackTrackingOptions + [stExceptFrame]; JclStartExceptionTracking; 

Here's a demonstration of the JCL FramesTrackExample.dproj:

enter image description here

For your purposes, change the code that adds the line to TMemo.Lines, instead a log file is written to disk instead. If you already have a logging system, that's great, but if not, consider Log4D .

+7
source

Each new web service call represents a new thread. Some resources may be allocated by the previous thread at the next next service call, and the new thread is trying to access them. Or some resources may be released by one thread when another thread tries to use them. You must use TCriticalSection to ensure that all resources are available for only one thread. Also make sure that TCriticalSection is a global variable and is accessible to all instances.

-1
source

Source: https://habr.com/ru/post/1386556/


All Articles