我的代码库中有很多地方,我希望在出现问题时得到通知 - 这是我想象的很常见。查看以下代码,我如何重新考虑此方法以抽象出电子邮件/日志记录详细信息?目前,这分散在大约100个地方,我真的需要做点什么!
public bool MethodOne() {
string message;
bool success = new Task().Execute();
message = string.Format( "MethodOne was {0} successful.",
success ? "" : "not");
if( !success )
SMTP.send( to, from, message );
System.Diagnostic.EventLog.WriteEntry( executingAssembly, message);
return success;
};
我目前的想法是做类似以下的事情:
public class Log
{
string to = "me@me.com",
from = "system@me.com",
subject = "Error occured";
public void Write( string executingAssembly, string message, bool sendEmail )
{
System.Diagnostic.EventLog.WriteEntry( executingAssembly, message);
if( sendEmail )
SendEmail( to, from, subject, message );
}
private void SendEmail( to, from, subject, message )
{
// Details to send email.
}
}
问题: 如何在应用程序中提高日志记录错误和发送通知的可维护性?
答案 0 :(得分:6)
考虑使用Logging and Log Manager程序,例如NLog。然后,您可以编写一组业务规则来登录nlog.config(或application.config)文件,该文件指定要记录到的不同位置(目标),您可以指定要为每个位置记录的内容(取决于严重性和类) 。
取自NLog网站
一些NLog支持的目标
使用NLog的一些主要功能
答案 1 :(得分:0)
Microsoft Enterprise Library有两个非常好的块,Logging Application Block和Exception Handling Application Block
这是一个基于策略的系统,允许您在.config文件中定义不同的策略。有了适当的策略和一些异常处理程序,您可以编写诸如以下的catch块:
catch(Exception ex)
{
if(HandleException("My Datalayer Policy", ex)) throw;
}
可以将异常策略配置为使事件冒泡。非常好的图书馆。
Logging块也使用.config中的“策略”,这些策略称为类别。例如,如果我想记录一些消息,但我想要发送电子邮件,我会使用两个类别和两个监听器,一个用于记录事件,另一个用于通过电子邮件发送事件的详细信息。如果未指定电子邮件类别,例如,当Sucess为true时,则仅发生日志记录事件。当成功为假时,将应用“电子邮件”类别,并且两个侦听器都会触发。
答案 2 :(得分:0)
一些评论:
您的日志类应该是静态类
您应该尝试/捕获所有错误处理代码,因为错误管理应该做的最后一件事......是导致错误!
您可以使用枚举列出主要错误类型和/或另一个严重性/ ...
我更喜欢将日志错误放入与App相同的文件夹中的小文本文件中。更容易处理,客户可以通过邮件发送(我不喜欢应用程序通过邮件发送数据的想法,你应该检查你的客户/用户是否正常。)。
您可以从Reflection获取执行程序集或其他信息
您可能还会从StackTrace中获取其他有价值的信息(我会在错误日志中编写Stacktrace,保存了很长时间)。
您还应该在应用程序级别捕获未处理的异常。
请描述更多错误以获得更具体的答案。
答案 3 :(得分:0)
我认为没有成功的任务执行是特殊的(否则你会发送很多电子邮件给某人)。因此,在任务失败时抛出异常(您还可以提供有关任务失败原因的其他详细信息)。以下是一些使用NLog的代码:
private static Logger _logger = LogManager.GetCurrentClassLogger();
public bool MethodFoo()
{
try
{
new Task().Execute();
_logger.Info("Task executed successfully");
return true;
}
catch(YourCustomException ex)
{
_logger.ErrorException("Cannot execute task", ex);
return false;
}
}
唯一剩下的就是NLog配置:
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<target name="eventLog" xsi:type="EventLog"
log="Application" source="Your Source" machineName="."
layout="${longdate}|${level}|${callsite:methodName=true}${message}" />
<target name="email" xsi:type="Mail"
subject="Error occured"
to="me@me.com"
from="system@me.com"
smtpServer="127.0.0.1"
smtpPort="25"
body="${longdate}|${message}" />
</targets>
<rules>
<logger name="*" minlevel="Info" writeTo="eventLog" />
<logger name="*" minlevel="Error" writeTo="email" />
</rules>
</nlog>
您需要两个目标 - 一个用于将信息和错误消息写入事件日志,另一个用于通过电子邮件发送错误通知。此外,我创建了两个规则 - 所有级别信息及以上的消息都将发送到事件日志,但错误和致命消息将通过电子邮件发送。
BTW与呼叫站点布局渲染器${callsite:methodName=true}
方法名称将插入到日志消息中。因此,您无需在代码中指定它。
答案 4 :(得分:0)
如果要抽象其他人建议的日志记录抽象,可以使用Commons Logging。是的,这是两层间接,但有些情况可能会有用。
您可以安装NuGet包,然后在您的代码中使用它:
// obtain logger instance
ILog log = LogManager.GetCurrentClassLogger();
// log something
log.Info("Some Debug Log Output");
然后将commons日志库配置为使用NLog,如下所示:
<common>
<logging>
<factoryAdapter type="Common.Logging.NLog.NLogLoggerFactoryAdapter, Common.Logging.NLog20">
<arg key="configType" value="INLINE" />
</factoryAdapter>
</logging>
</common>
然后您可以配置NLog。 @Sergey Berezovskiy的回答就是一个例子。
关键是,Commons Logging库不允许您在NLog或log4net或Logging Application Block之间进行选择。您可以将后端切换到您想要的任何内容。如果您正在编写可能托管在各种项目类型中的dll或其他内容,这将非常有用。当然,它也可能是一个无用的额外间接层。这取决于你正在做什么。