我正在做生产支持,很大程度上依靠日志来排除故障。我发现现在的日志信息相当混乱。
你能提供写日志信息的最佳实践或指南吗?
顺便说一下:我们使用的是log4Net。你对替代图书馆有什么建议吗?
谢谢。
发布于 2010-11-07 19:05:23
理想情况下,您的日志消息应该包括时间、内容、地点、人员的详细信息,以及触发消息的事件的严重程度的一些指示。
我赞同@Oded在保持信息整洁方面的建议。对于例程内容,日期和时间,日志级别,错误代码,我会尝试将它们格式化为固定的宽度,并将它们放在开头。它使扫描日志变得更容易。
关于日志消息格式化的好指南,我唯一遇到的是“Release It!”一书的第17章:http://www.pragprog.com/titles/mnee/release-it上面的很多建议都是基于这一点的。
发布于 2010-11-07 18:30:44
ELMAH是一个非常好的日志库,也是log4net的一个不错的替代品。
关于日志的格式化(你说信息“凌乱”,但你没有确切解释这是什么意思)--确保每个条目与其他条目清楚地分开,并以可读的方式格式化(空格、换行符等)。
发布于 2010-11-08 23:32:02
@corriganjc有很多好的建议。
我想补充一些细节:如果可能的话,考虑使用UTC记录消息。一方面,查看在“你的”时区中生成的消息,然后必须记住正确的量来偏移它们以“正确”地解释它们,这可能是令人恼火的。另一方面,您的所有日志消息都可以按时间/日期排序,而无需进一步解释。(如果您记录了来自两个时区的消息,并且您使用“本地”时间记录了这些消息,则无法对它们进行排序,除非您将它们带到一个通用时区)。
使用GlobalContext、ThreadContext和LogicalThreadContext对象向消息中注入额外的上下文。建议记录诸如"session id“或"transaction id”之类的内容是一个很好的建议,并且可能可以使用"context“对象最有效地实现,而不是通过显式地将这些值添加到实际的日志记录调用点。您可以设置上下文一次,并通过添加格式化选项,使用ever message记录该上下文。
如果您使用context对象,请考虑创建“标准”值名称,甚至定义可供开发人员引用的字符串常量,这样他们在尝试添加上下文时就不会出现make输入错误:
//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的一个好处是它是一个仅限配置的依赖项。您不必接受源或引用依赖项即可使用它。
https://stackoverflow.com/questions/4117322
复制相似问题