我正在做生产支持,很依赖日志进行故障排除。我发现日志信息现在非常混乱。
您能提供编写日志信息的最佳做法或指南吗?
BTW:我们正在使用log4Net。你对替代图书馆有什么建议吗?
感谢。
答案 0 :(得分:7)
理想情况下,您的日志消息应包含“何时”,“内容”,“何处”,“谁”以及触发消息的事件的严重程度的详细信息。
我的第二个建议是@Oded保持信息整洁。对于常规的东西,日期和时间时间,日志级别,错误代码,我会尝试将它们格式化为固定宽度,并将它们放在开头。它使扫描日志变得更加容易。
关于日志消息格式的良好指南,我唯一遇到的是“发布它!”一书的第17章:http://www.pragprog.com/titles/mnee/release-it上述许多建议都基于此。
答案 1 :(得分:2)
ELMAH是一个非常好的日志记录库,并不是log4net的替代品。
关于日志的格式化(你说信息是“凌乱的”,虽然你没有准确解释这意味着什么) - 确保每个条目与其他条目明确分开,并且格式化为可读方式(间距,换行等......)。
答案 2 :(得分:2)
@corriganjc有很多好建议。
我会添加一些细节: 如果可能,请考虑使用UTC记录消息。一方面,查看“你的”时区中生成的消息,然后必须记住正确的数量来抵消它们以“正确地”解释它们可能会很烦人。另一方面,所有日志消息都可按时间/日期排序,无需进一步解释。 (如果您从两个时区记录了消息并且已使用“本地”时间记录它们,则在将它们带到公共时区之前无法对它们进行排序。)
使用GlobalContext,ThreadContext和LogicalThreadContext对象在邮件中注入其他上下文。记录诸如“会话ID”或“事务ID”之类的建议是一个很好的建议,并且可以使用“上下文”对象最有效地完成,而不是通过将这些值显式添加到实际的日志记录调用站点。您可以设置一次上下文,并通过添加格式化选项,使用ever message记录该上下文。
如果您使用上下文对象,请考虑制作“标准”值名称,甚至可以定义开发人员可以引用的字符串常量,以便在尝试添加其上下文时不会产生拼写错误:
//Context value names
public static class DiagnosticContextValueNames
{
public static string TransactionId = "transactionid";
public static string SessionId = "sessionid";
}
//In your code
log4net.ThreadContext.Properties[DiagnosticContextValueNames.TransactionId] = GetTransactionId();
log4net.ThreadContext.Properties[DiagnosticContextValueNames.SessionId] = GetSessionId();
//Somewhere later on...
logger.Info("hello"); // this message can be tagged with the transaction id and session id if you use the appropriate formatting options
您甚至可以考虑GlobalContext.Properties,ThreadContext.Properties等上的扩展方法,以帮助指导开发人员正确设置上下文值:
public static class LoggingExtensions
{
public static void SetTransactionId(this ThreadContextProperties props, string trans)
{
props["TransactionId"] = trans;
// Or, using constants as defined above...
props[ThreadContextValueNames.TransactionId] = trans;
}
}
// In your code...
log4net.ThreadContext.Properties.SetTransactionId(GetTransactionId());
// As compared to this:
log4net.ThreadContext.Properties["transactionid"] = GetTransactionId();
如果您从log4net记录器中包装或继承,您可以自动添加一些上下文信息,从而减轻开发人员的负担。有一种正确的方法来包装或继承log4net记录器,但它不是火箭科学。关键是将log4net传递给包装记录器的类型。 cfeduke在this post中的回答提供了一种包装log4net记录器的方法。
您可以按照他的示例,但根据“ILogger.Log”方法实现所有日志记录调用。在“Log”中,您可以为所有日志消息添加所需的属性:
// This approach requires more effort than simply populating the context properties "normally", and
// is probably overkill for most situations. However, it can prove useful if you are able
// to have access to the context information that you want to log from within the Log method
// of the logger.
public void Log(type loggerBoundaryDeclaringType, LogLevel level, object message, object exception)
{
log4net.ThreadContext.Properties["transactionid"] = GetTransactionId();
log4net.ThreadContext.Properties["sessionid"] = GetSessionId();
_logger.Log(loggerBoundaryDeclaringType, level, message, exception);
}
就其他日志记录平台而言,您可以查看NLog。新版本最近已作为Beta版本发布。它有许多与log4net类似的功能。
您可能还会考虑使用旧的System.Diagnostics.TraceSource。如果你走这条路,请在codeplex上查看Ukadc.Diagnostics。这是System.Diagnostics的插件库,提供丰富的消息格式化功能(类似于您可以使用log4net和NLog执行的操作)。关于Ukadc.Diagnostics的一个好处是它只是一个配置依赖。您不必使用源或引用依赖项来使用它。
答案 3 :(得分:1)
> ... we're using log4Net. Do you have any suggestion on alternative library?
您可以使用common.logging(http://netcommon.sourceforge.net),这是一个与
一起使用的微小日志包装器由于您必须配置要使用的日志记录引擎,并且还必须配置日志记录引擎,因此它使日志记录配置更加复杂。
它的log api受到log4net-api
的启发