如何使用ELMAH手动记录错误


259

是否可以使用ELMAH执行以下操作?

logger.Log(" something");

我正在做这样的事情:

try 
{
    // Code that might throw an exception 
}
catch(Exception ex)
{
    // I need to log error here...
}

因为已处理此异常,所以ELMAH不会自动记录该异常。


1
为了将来参考,我写了一篇关于以下内容的文章:以编程方式记录错误。我的ELMAH教程也提供了有关此信息。
ThomasArdal'9

Answers:


412

直接日志写入方法,自ELMAH 1.0开始有效:

try 
{
    some code 
}
catch(Exception ex)
{
    Elmah.ErrorLog.GetDefault(HttpContext.Current).Log(new Elmah.Error(ex));
}

ELMAH 1.2引入了更灵活的API:

try 
{
    some code 
}
catch(Exception ex)
{
    Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
}

两种解决方案之间有区别:

  • Raise方法将ELMAH过滤规则应用于异常。Log方法没有。
  • Raise 基于订阅,并且能够将一个异常记录到多个记录器中。

1
您的方法与其他方法有什么区别?
Omu

3
这些日志将错误记录在Elmah中,而不会导致应用程序停止工作。它允许您捕获常见的异常,正确地处理它们,但仍然能够记录它们。
PCasagrande

7
我发现当回发包含Mvc4 .Net 4.5的不安全Html时,Elmah.ErrorSignal没有记录,在我的示例中是从Windows Access Control Services回发带有SignInResponseMessage的POST。Elmah.ErrorLog.GetDefault确实在这种情况下起作用
Adam

1
我在使用不安全的HTML时遇到了同样的问题。ErrorLog.GetDefault可以解决问题
hgirish 2013年

4
使用时的一个重大警告Elmah.ErrorLog.Log():如果log调用本身失败,则抛出该异常,有可能使整个Web应用程序崩溃。Raise()默默地失败。例如:如果服务器端存在配置错误的问题(例如,Elmah配置为将错误保存到磁盘,但没有对logs文件夹的正确访问权限),则该.Log()方法将抛出。(尽管这对于调试很有用,例如为什么不.Raise()记录任何内容?)
Cristian Diaconescu

91

我建议将对Elmah的调用包装在您自己的一个简单包装器类中。

using Elmah;

public static class ErrorLog
{
    /// <summary>
    /// Log error to Elmah
    /// </summary>
    public static void LogError(Exception ex, string contextualMessage=null)
    {
        try
        {
            // log error to Elmah
            if (contextualMessage != null) 
            {
                // log exception with contextual information that's visible when 
                // clicking on the error in the Elmah log
                var annotatedException = new Exception(contextualMessage, ex); 
                ErrorSignal.FromCurrentContext().Raise(annotatedException, HttpContext.Current);
            }
            else 
            {
                ErrorSignal.FromCurrentContext().Raise(ex, HttpContext.Current);
            }

            // send errors to ErrorWS (my own legacy service)
            // using (ErrorWSSoapClient client = new ErrorWSSoapClient())
            // {
            //    client.LogErrors(...);
            // }
        }
        catch (Exception)
        {
            // uh oh! just keep going
        }
    }
}

然后只要需要记录错误就调用它。

try {
   ...
} 
catch (Exception ex) 
{
    // log this and continue
    ErrorLog.LogError(ex, "Error sending email for order " + orderID);
}

这具有以下好处:

  • 您无需记住Elmah调用的这种有点过时的语法
  • 如果您有很多DLL,则不需要从每个引用DLL到Elmah Core,只需将其放入您自己的“系统” DLL中即可。
  • 如果您需要进行任何特殊处理,或者只是想在断点中调试错误,则将其全都放在一处。
  • 如果您离开Elmah,则只能更改一个地方。
  • 如果您有旧的错误日志记录,则要保留(我碰巧有一个简单的错误日志记录机制,该机制已绑定到某些UI中,但我没有时间立即删除)。

注意:我添加了一个“ contextualMessage”属性来获取上下文信息。如果愿意,可以省略此选项,但我认为它非常有用。Elmah自动解包异常,因此基础异常仍将在日志中报告,但单击上下文上下文消息将可见。


1
好答案。也许ELMAH应该开箱即用地实现类似的功能。有时在没有上下文的情况下很难调试错误。
13年

2
我喜欢所有内容,但可以吞下任何次要错误// uh oh! just keep going。如果我的错误处理失败,我想知道。我希望它发出一些声音。
杰里米·库克

3
@JeremyCook我同意,但需要注意的是,如果您不小心,错误处理例程将失败,最终导致自己调用然后崩溃(哦,我实际上也在这里调用第三方API来记录错误)。我可能不应该留这个答案,但是之前在发生这种事情之前我有糟糕的经历
Simon_Weaver 2014年

1
作为扩展方法,恕我直言会更好。
斯蒂芬·肯尼迪

1
您可能在想:不,我可以尝试记录多少手动错误?我以为大约一年前。长话短说:使用这个包装器!
nmit026'1

29

您可以使用Elmah.ErrorSignal()方法记录问题,而不会引发异常。

try
{
    // Some code
}
catch(Exception ex)
{
    // Log error
    Elmah.ErrorSignal.FromCurrentContext().Raise(ex);

    // Continue
}


14

是的,有可能。ELMAH旨在拦截未处理的异常。但是,您可以通过ErrorSignal类向ELMAH发出异常信号。这些异常不会抛出(不会冒泡),而只会发送给ELMAH(以及ErrorSignal类的Raise事件的订阅者)。

一个小例子:

protected void ThrowExceptionAndSignalElmah()
{
    ErrorSignal.FromCurrentContext().Raise(new NotSupportedException());
}

13

我一直在寻找从MVC4应用程序中开始对邮件进行排队的线程中做同样的事情,因此引发异常时,我没有HttpContext可用。为此,我根据此问题和在此处找到的另一个答案得出以下结论:elmah:没有HttpContext的异常?

在配置文件中,我指定了一个应用程序名称:

<elmah>
    <security allowRemoteAccess="false" />
    <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="ELMAH" applicationName="myApplication"/>   
</elmah>

然后在代码中(如上面提供的答案,但没有HttpContext),您可以传递null而不是HttpContext:

ThreadPool.QueueUserWorkItem(t => {
     try {
         ...
         mySmtpClient.Send(message);
     } catch (SomeException e) {
         Elmah.ErrorLog.GetDefault(null).Log(new Elmah.Error(e));
     }
 });

我喜欢您的解决方案;但是,我无法解决“ Elmah”。在我的项目中。我尝试添加“使用Elmah”;在我的代码中,但在当前上下文中不存在。
2013年

@Taersious你packages.config长什么样?你看到类似的东西<package id="elmah" version="1.2.2" targetFramework="net45" /> <package id="elmah.corelibrary" version="1.2.2" targetFramework="net45" /> <package id="elmah.sqlserver" version="1.2" targetFramework="net45" />'吗?您安装了NuGET吗?
马修

我想说是,但是我的项目当前被锁定在源代码管理中。我从项目中的示例配置文件手动实现了elmah。
Taersious

@Taersious如果手动完成,在调用使用之前您是否将Elmah引用添加到了项目...我希望它能以任何一种方式工作,但是我知道当nuget添加它时,上面的行会添加到packages.config
Matthew

3

有时CurrentHttpContext可能不可用。

定义

public class ElmahLogger : ILogger
{
    public void LogError(Exception ex, string contextualMessage = null, bool withinHttpContext = true)
    {
        try
        {
            var exc = contextualMessage == null 
                      ? ex 
                      : new ContextualElmahException(contextualMessage, ex);
            if (withinHttpContext)
                ErrorSignal.FromCurrentContext().Raise(exc);
            else
                ErrorLog.GetDefault(null).Log(new Error(exc));
        }
        catch { }
    }
}

public class MyClass
{
    readonly ILogger _logger;

    public MyClass(ILogger logger)
    {
        _logger = logger;
    }

    public void MethodOne()
    {
        try
        {

        }
        catch (Exception ex)
        {
            _logger.LogError(ex, withinHttpContext: false);
        }
    }
}

2

我在ASP.NET core上,并且使用ElmahCore

使用HttpContext(在控制器中)手动记录错误只需编写:

using ElmahCore;
...
HttpContext.RiseError(new Exception("Your Exception"));

没有HttpContext的应用程序的另一部分中:

using ElmahCore;
...
ElmahExtensions.RiseError(new Exception("Your Exception"));

0

我试图使用Signal.FromCurrentContext()。Raise(ex);将自定义消息写入Elmah日志。并发现这些异常已冒出,例如:

try
{
    ...
}
catch (Exception ex)
{
    Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
    // this will write to the log AND throw the exception
}

此外,我看不到elmah如何支持不同级别的日志记录-是否可以通过web.config设置关闭详细日志记录?


1
如果您捕获到异常并且不再抛出异常,则异常不会冒出来。也许我误会了?ELMAH不支持不同级别的日志记录。它仅用于错误。
ThomasArdal'3

谢谢,托马斯。这正是我试图确认
瓦列里·加夫里洛夫

0

用了这条线,它工作得很好。

 try{
            //Code which may throw an error
    }
    catch(Exception ex){
            ErrorLog.GetDefault(HttpContext.Current).Log(new Elmah.Error(ex));
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.