在没有与Eurekalog对话的情况下纠正线程内的日志记录

时间:2017-10-06 23:01:55

标签: multithreading delphi eurekalog

我有一个使用最新版EurekaLog的Delphi 10项目。我目前正在使用EurekaLog来帮助我调试生产客户端中的问题。

我注意到EurekaLog没有注册线程中发生的错误。在我开始阅读之后,我发现我需要从TThread更改为TThreadEx,并在Execute覆盖方法的开头添加以下代码。

SetEurekaLogStateInThread(ThreadID, true);

尽管如此,当发生错误时,它不会在EL文件中生成事件。

如果我在ExceptionManager.StandardEurekaError('TThrdSincArquivos.Execute => ' + ex.Message);上添加try..except,则会记录。但是堆栈跟踪显示为在我调用StandardEurekaLog()的行上发生错误,而不是在实际发生错误的行上。这违背了整个事情的目的。

另一个问题是它显示了一个我不想要的对话框,因为错误发生在后台线程中。我只是想记录下来。我应该只在主线程上出现错误的对话框。

如何在线程中实现这些结果?

  • 实际使用正确的堆栈记录错误。

  • 在主线程上,显示对话框,但在一个线程中,只记录没有对话框。

修改

以下是我的EurekaLog多线程配置

Call Stack option Multi-threading option

这是我的主题声明:

unit ThrdSincArquivos;

interface

uses
  System.Classes, System.SysUtils, System.Generics.Collections, REST.Client, REST.Types,
  System.JSON, Data.DB, Datasnap.DBClient, FireDAC.Comp.Client, FireDAC.Stan.Param, System.SyncObjs, EBase, EExceptionManager, EClasses;

type
  TThrdSincArquivos = class(TThreadEx)
  private

我的主题是创建

constructor TThrdSincArquivos.Create(pPrimeiraExec: boolean; tipoSincParam: TTipoSinc);
begin
  inherited Create(true);

  NameThreadForDebugging('TThrdSincArquivos');
  primeiraExec := pPrimeiraExec;
  tipoSinc := tipoSincParam;
  executadoThreadSinc := false;
  FreeOnTerminate := true
end;

我的执行开始

procedure TThrdSincArquivos.Execute;
var
  contador: Integer;
begin
  inherited;

  try

和执行结束

  except
    on ex: Exception do
    begin
      oLog.GravarLog(ex, 'TThrdSincArquivos.Execute => FIM');
    end;
  end;
end;

它拒绝记录Elf文件的任何异常。我尝试在我自己的日志例程后添加一个加注,但它仍然没有帮助。它应该记录,但事实并非如此,除非我明确地调用StandardEurekaError,但我得到的堆栈错误,我得到了对话框。

1 个答案:

答案 0 :(得分:0)

使用TThread类时-将线程异常保存到you are supposed to handle in some way.FatalException属性中。要么来自线程事件,要么来自其他(调用者)线程。 EurekaLog不会破坏此行为。例如。启用EurekaLog时,以前编写的代码将不会更改其行为。这样,您正确编写的代码在下都可以在没有EurekaLog的情况下正常工作。

您的代码当前如何处理线程异常?您是否正在执行类似ShowMessage或自定义日志记录的操作?这显然不适用于EurekaLog,它不知道您正在使用ShowMessage或您自己的自定义日志记录代码来处理异常。您可能希望在调用者线程中使用类似Application.ShowException或re-raise之类的东西。

如果由于某种原因您不能使用默认的RTL / VCL处理(由EurekaLog挂接)-那么您需要告诉EurekaLog您想处理这个特殊异常。例如,来自docs:例如,您可以使用HandleException(E);单位中的EBase

Thread.WaitFor;
if Assigned(Thread.FatalException) then
begin
  // Your old code is here
  // Do your own thing: show message, log, etc.

  // Tell EurekaLog to do its thing:
  HandleException(Thread.FatalException);
end;

您可能想要设置异常过滤器或使用事件来禁用线程异常对话框,因为大概您已经自己处理了异常(例如已经显示的消息)。

还有更多的方法来处理线程中的异常,EurekaLog's docs说明了每种线程的情况(例如BeginThreadTThread,线程池等) 。)和几种可能的选择。将所有这些信息打包成一个答案是不合理的。

如果由于某种原因,您没有用于处理.FatalException的{​​{1}}属性的代码-那么您可以使用TThread类及其TThreadEx属性来处理异常自动退出线程,如here所述:

.AutoHandleException

但是,请注意,如果您以后决定禁用EurekaLog,则您的代码将无法正常工作(例如,将忽略异常)。因为如果您从项目中删除EurekaLog,则您的项目将没有代码来处理线程异常!

P.S。

  

我需要从type TMyThread = class(TThreadEx) protected procedure Execute; override; end; procedure TMyThread.Execute; begin // ... your code ... end; procedure TForm1.Button1Click(Sender: TObject); var Thread: TMyThread; begin Thread := TMyThread.Create(True, 'My thread'); Thread.AutoHandleException := True; // <- added Thread.FreeOnTerminate := True; Thread.Start; Thread := nil; // never access thread var with FreeOnTerminate after Start end; 更改为TThread,并添加以下内容   代码在我的TThreadEx覆盖方法的开头。

Execute

这有点不正确:您可以做一个或另一个,但不能两者都做。还有其他方法可以告诉EurekaLog它应该在此线程中挂钩异常。

基本上,异常生命有两个阶段:引发和处理。当用默认的RTL / VCL代码实现时,EurekaLog会钩住这两个阶段。您需要明确指出要挂接的线程,因为您可能想忽略无法控制的系统/第三方线程。因此,在RTL / VCL中不存在对SetEurekaLogStateInThread(ThreadID, true); 的默认处理。这就是为什么没有什么可钩的。