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

Multithreading 在没有与Eurekalog对话的情况下,在线程内正确记录日志,multithreading,delphi,eurekalog,Multithreading,Delphi,Eurekalog,我有一个Delphi10项目,使用最新版本的EurekaLog。我目前正在使用EurekaLog来帮助我调试生产客户机中的问题 我注意到EurekaLog没有记录线程中发生的错误。开始阅读之后,我发现我需要从TThread更改为TThreadEx,并在Execute重写方法的开头添加以下代码 SetEurekaLogStateInThread(ThreadID, true); SetEurekaLogStateInThread(ThreadID, true); 尽管如此,当发生错误时,它不会

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

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

SetEurekaLogStateInThread(ThreadID, true);
SetEurekaLogStateInThread(ThreadID, true);
尽管如此,当发生错误时,它不会在
EL
文件中生成事件

如果我添加
ExceptionManager.standareurekaerror('tthrdss.Execute=>'+ex.Message)
try。但是堆栈跟踪显示为错误发生在我调用
StandardEurekaLog()
的行上,而不是实际发生错误的行上。这违背了整件事的目的

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

如何在线程内实现这些结果

  • 用正确的堆栈记录错误

  • 当在主线程上时,显示对话框,但在线程内,只需记录而不显示对话框

编辑

下面是我的EurekaLog多线程配置

以下是我的线程声明:

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
,但是我得到了错误的堆栈,并且得到了对话框。

当您使用
TThread
类时,它将线程异常保存到
.FatalException
属性,该属性。来自线程事件或其他(调用方)线程。尤里卡洛并没有破坏这种行为。例如,当您启用EurekaLog时,您以前编写的代码不会改变其行为。这样,正确编写的代码在使用和不使用EurekaLog的情况下都能正常工作

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

如果由于某种原因不能使用默认的RTL/VCL处理(由EurekaLog钩住),那么您需要告诉EurekaLog您想要处理这个特殊的异常。例如,from:您可以使用(例如)
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;
您可能希望设置异常过滤器或使用事件来禁用线程异常的对话框,因为您可能已经自己处理了异常(例如,已显示消息)

处理线程中异常的方法有很多,并用几个可能的选项说明每个线程的情况(如
BeginThread
TThread
、线程池等)。将所有这些信息打包成一个答案是不合理的

如果由于某种原因,您没有处理
TThread
.FatalException
属性的代码,则可以使用
TThreadEx
类及其
.AutoHandleException
属性在线程退出时自动处理异常,如下所述:

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


基本上,异常生命有两个阶段:提升和处理。在默认RTL/VCL代码中实现时,EurekaLog钩住这两个阶段。您需要明确指出要挂接哪些线程,因为您可能希望忽略无法控制的系统/第三方线程。RTL/VCL中不存在
TThread
的默认处理。这就是为什么没有什么好挂的。

顺便说一句,没有像XE10这样的东西会让尤里卡洛非常失望。我个人使用MadExcept,并强烈推荐它。@Pascal您可以使用。该组件提供[OneExceptionAction]()事件,允许在Eureka处理异常时跳过不必要的步骤。事件具有AEurekaAction参数,用于定义要执行的步骤。ShowingExceptionInfo的参数值表示Eureka希望显示错误对话框。如果不想显示对话框,只需将AExecute参数设置为False即可。@Pascal还有AEExceptionInfo参数-它是一个具有两个有用属性的类。您可以检查ThreadID、ThreadException和SynchronizeException,以了解后台线程中是否出现异常。
SetEurekaLogStateInThread(ThreadID, true);