编写好的日志记录语句时,您遵循什么准则?

时间:2008-11-06 22:50:54

标签: logging

我最近在我的项目代码库中发现了一条日志声明 “我在这里搜索参数==> =========== 11/30/2008 === 1 ==== 00:00 AM”

您在应用程序中编写好的日志消息时遵循了哪些指导原则?

7 个答案:

答案 0 :(得分:14)

日志语句中最有用的部分(当然可能是日期和时间除外)是唯一的ID。我们所有的日志条目都以MSG-xxxxx开头,其中xxxxx是一个唯一的整数。此MSG-xxxxx标记始终在源中进行硬编码,从不在资源文件中,因此很容易找回它。它也是文档中非常简单的搜索键。

另外有用的是始终将变量字符串内容括在双引号中以便轻松区分消息本身:

MSG-12345试图打开“myfile.txt”,返回错误代码“123 - 找不到文件”。

当您尝试使用某些正则表达式从日志中提取信息时,这也会有所帮助。

答案 1 :(得分:14)

`log'语句看起来更像是跟踪语句。

记录:显示正常事件和错误

跟踪:显示执行路径以及所有日志记录事件

就个人而言,我希望日志记录能够找出我的程序已完成的工作,并且我希望跟踪语句来验证执行路径并找出问题所在。我将跟踪语句路由到一个单独的文件,其中包含两种类型的上下文日志消息。

因此,您至少应该有2个日志级别,并且能够关闭跟踪性能。您应该能够将这些事件流路由到不同的位置。这使您可以轻松地保存日志以获取历史记录,同时不会使用您只想跟踪问题的调试信息混乱。

这里的很多答案都集中在日志消息中包含的字段中,但我认为日志调用的放置和日志记录级别更重要。如果您使用log4net,您可以通过配置文件随意包含/排除日期戳,但是如果不重新编译,您将无法放置或删除日志语句,因此有必要仔细考虑它们的去向。除了标准字段(例如时间戳和线程ID等)之外,您还想知道进行调用的类和方法名称。如果你按照你所关注的类型命名你的记录器的最佳做法,Log4net等已经处理了类名。除此之外,我通常包括方法名称。这对于跟踪尤为必要,但我将其包含在我的所有日​​志消息中。

记录

您希望了解有关将要执行的操作的足够信息,以便在出现问题时回过头来查看。好的候选人是消息ID,电子邮件地址,以及唯一标识工作项的东西。这种消息应该在这种数据可用时立即出现,这样当你通过日志文件阅读时,你会看到类似“尝试用y做x”的事情,然后如果我们看到异常,我们知道我们需要查看哪个工作项目,以了解我们失败的原因。

记录异常应与“尝试”日志消息配对,以便在读取日志时上下文中的异常消息有意义。这意味着要考虑异常处理的结构。如果您使用.net并且只想记录异常,而不是处理异常,则需要重新抛出相同的异常,而不是新异常,所以只需要'throw'而不是'throw e'其中'e'是您的异常实例。如果它没有意义,请查看这个。

<强>跟踪

这实际上更简单,通常我会在感兴趣的方法的开头和结尾留言,比如书挡。在条目中,您可以打印影响程序流的关键方法参数。在方法结束时记录消息是一种可选的,通常你会有兴趣查看类似于堆栈跟踪的跟踪类型。你可以在没有它们的情况下找出执行路径。

<强>性能

对于字符串性能,如果使用log4net或类似方法,请使用'* Format'方法。这内部将使用StringBuilder,因此您不会一直支付不可变的字符串惩罚。一般来说,关键是能够关闭跟踪以获得性能,并且即使日志消息很昂贵,也要使日志记录足够简洁以便继续使用。正确完成后,应该没有足够的问题。

答案 2 :(得分:6)

不要在日志记录语句中进行字符串连接,至少是调试语句。

我前一段时间工作的一个Java应用程序性能惨淡。所以我们破解了分析器,看看瓶颈在哪里。事实证明,这主要是由于在嵌套的内部循环等中组装的DEBUG级别日志记录语句所产生的字符串连接操作(哈哈,并认为它们首先被添加以找出性能如此糟糕的原因) !)

不要这样做

LOGGER.debug("The variable was " + myVariable + " and we are doing " + foo);

而是执行此操作

if (LOGGER.isDebugEnabled()) {
  LOGGER.debug("put your debug statement here " + foo + " and " + bar);
}

答案 3 :(得分:5)

有5个方面对我很重要(从较不重要的方面开始):

  1. 在日志条目中包含时间戳
  2. 提供筛选不太重要的“垃圾邮件”条目的可能性。好的,旧的方括号标签应该足够grep。如果它们中的一些会自动生成会很好 - 取决于日志类型(消息,警告,断言等)和可选的消息重要性级别(垃圾邮件,正常,高,严重)。 IMO也建议手动添加额外的上下文缩小标签。
  3. 使日志功能/宏尽可能易于使用。
  4. 立即冲洗输出缓冲区。
  5. 提供即时和明确确定日志条目生成位置(源文件名+行号)的可能性。在某些语言中可能很难,但通常确切地知道哪个断言失败意味着立即修复错误。此外,您不会浪费时间手动添加日志位置标识符(例如“SomeClass :: SomeMethod:Message”)

答案 4 :(得分:4)

在我的日志中,我需要日期和时间,创建日志的过程以及PID。没有什么比查看日志并想知道它们是否在五分钟前出现,或者它们是否在5年前在您的更改之前被遗忘的情况更糟糕。日期和时间很重要。

当我报告错误时,我简明扼要地说明了所调用的内容,发生的情况以及返回的错误代码。如果它是错误的,我也会报告回到strerror(错误)。我正在读这个以找到问题,而且通常我会尖叫着急着找到问题。我不想看东西。我希望它告诉我发生了什么,我更喜欢冗长无用。如果我正在调试,而且即使我不调试,我也会记录所有数据,如SQL语句或低级记录,密钥,以及任何可以帮助我尽快找到问题的内容。

有时我们会疯狂登录,这会让系统稍微减慢速度。但是当狗屎下降并且我们收到传票并且有关于松散的指控以及婴儿杀手的指责被抛出时,我们喜欢我们有足够的日志来显示究竟发生了什么以及为什么以及由谁造成的。这是责备管理。

答案 5 :(得分:2)

代码变量级别的日志记录,因此您可以在任何内容之间切换,程序流程的基本信息和内部工作方式的疯狂详细信息。然后通过调整控制日志记录级别的变量,您可以控制要接收的输出量。

在您希望能够从遇到问题的客户接收日志记录的大型项目中,如果您可以控制应用程序的哪些部分将记录,也会有所帮助;例如,如果读取AD用户信息时出现问题,您可以添加“AD_LOGGING = EVERYTHING”并接收详细的日志信息,而无需查看该程序其他每个部分的日志信息。

答案 6 :(得分:2)

我们使用“二维”记录,即按单个模块记录并按级别记录。在尝试调试客户问题时,这为我们提供了真正的控制。

每个日志条目都有唯一的ID加上日期加上时间加模块加调试级别。在向用户显示的异常/错误消息中反映id(如果需要)。因此,如果用户记录事件,我们可以快速提取日志的该部分,并查看该点周围发生的事情。

调试级别消息不使用诸如“无效输入”之类的通用性,我们记录导致问题的实际值。如果该字段与其他字段有关系,我们也会记录它们。