如何使用 ELMAH 手动记录错误
Posted
技术标签:
【中文标题】如何使用 ELMAH 手动记录错误【英文标题】:How to use ELMAH to manually log errors 【发布时间】:2011-11-18 10:57:04 【问题描述】:是否可以使用 ELMAH 执行以下操作?
logger.Log(" something");
我正在做这样的事情:
try
// Code that might throw an exception
catch(Exception ex)
// I need to log error here...
ELMAH 不会自动记录此异常,因为它已被处理。
【问题讨论】:
为了将来参考,我写了一篇关于这个的帖子:Logging errors programmatically。我的ELMAH Tutorial 也有这方面的一些信息。 【参考方案1】:直接日志写入方法,从 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
是基于订阅的,能够将一个异常记录到多个记录器中。
【讨论】:
你的方法和其他方法有什么区别? 这些在 Elmah 中记录错误,而不会导致应用程序停止工作。它允许您捕获常见异常,正确处理它们,但仍然能够记录它们。 我发现当 POST 返回包含 Mvc4 .Net 4.5 的不安全 html 时,Elmah.ErrorSignal 没有记录,在我的示例中,是从 Windows 访问控制服务返回的带有 SignInResponseMessage 的 POST。 Elmah.ErrorLog.GetDefault 在那种情况下确实有效 我对不安全的 Html 有同样的问题。 ErrorLog.GetDefault 成功了 使用Elmah.ErrorLog.Log()
时的一个重要警告:它会在日志调用本身失败的情况下抛出,可能会导致整个网络应用程序崩溃。 Raise()
静默失败。例如:如果服务器端存在错误配置问题(例如 Elmah 配置为将错误保存到磁盘,但没有正确访问日志文件夹),.Log()
方法将抛出。 (不过这对调试很有用,例如为什么 .Raise()
不记录任何内容?)【参考方案2】:
我建议将对 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 会自动解包异常,因此底层异常仍会在日志中报告,但当您单击它时,上下文消息将可见。
【讨论】:
很好的答案。也许 ELMAH 应该开箱即用地实现类似的东西。有时在没有上下文的情况下很难调试错误。 我喜欢// uh oh! just keep going
的任何次要错误,但几乎没有。如果我的错误处理失败,我想知道。我想让它发出一些声音。
@JeremyCook 我同意,但需要注意的是,如果你不小心失败的错误处理例程往往最终会调用自己然后爆炸(哦,我实际上也在调用第三方 API在这里记录错误)。我可能不应该把这个留在这个答案中,但我之前曾有过这样的事情发生的不好的经历
作为扩展方法会更好。
您可能会想:不,我可以尝试记录多少手动错误?我是这么想的,大约一年前。长话短说:使用这个包装器!【参考方案3】:
您可以使用 Elmah.ErrorSignal() 方法记录问题而不会引发异常。
try
// Some code
catch(Exception ex)
// Log error
Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
// Continue
【讨论】:
【参考方案4】:catch(Exception ex)
Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
【讨论】:
【参考方案5】:是的,这是可能的。 ELMAH 旨在拦截未处理的异常。但是,您可以通过 ErrorSignal 类向 ELMAH 发出异常信号。这些异常不会被抛出(不要冒泡),而只会发送给 ELMAH(以及 ErrorSignal 类的 Raise 事件的订阅者)。
一个小例子:
protected void ThrowExceptionAndSignalElmah()
ErrorSignal.FromCurrentContext().Raise(new NotSupportedException());
【讨论】:
【参考方案6】:我希望在我已经开始从我的 MVC4 应用程序中排队邮件的线程中做同样的事情,因此当引发异常时我没有可用的 HttpContext。为此,我根据这个问题和在此处找到的另一个答案得出了以下结论:elmah: exceptions without 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;”在我的代码中,但在我当前的上下文中不存在。 @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 如果手动执行,您是否在调用 using 之前将 Elmah 引用添加到项目中...我希望它能够以任何一种方式工作,但我知道当 nuget 添加它时以上添加到packages.config
【参考方案7】:
我在 ASP.NET core 上使用 ElmahCore。
要手动记录错误使用 HttpContext(在控制器中)只需编写:
using ElmahCore;
...
HttpContext.RiseError(new Exception("Your Exception"));
在您的应用程序的另一部分没有 HttpContext:
using ElmahCore;
...
ElmahExtensions.RiseError(new Exception("Your Exception"));
【讨论】:
【参考方案8】:有时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);
【讨论】:
【参考方案9】:我试图使用 Signal.FromCurrentContext().Raise(ex); 将自定义消息写入 elmah 日志;发现这些异常都是冒泡的,eg:
try
...
catch (Exception ex)
Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
// this will write to the log AND throw the exception
此外,我看不到 elmah 如何支持不同级别的日志记录 - 是否可以通过 web.config 设置关闭详细日志记录?
【讨论】:
如果你捕捉到一个异常并且不再抛出它,异常就不会冒泡。也许我误解了? ELMAH 不支持不同级别的日志记录。仅用于错误。 谢谢,托马斯。这正是我想要确认的【参考方案10】:用过这条线,效果很好。
try
//Code which may throw an error
catch(Exception ex)
ErrorLog.GetDefault(HttpContext.Current).Log(new Elmah.Error(ex));
【讨论】:
以上是关于如何使用 ELMAH 手动记录错误的主要内容,如果未能解决你的问题,请参考以下文章