首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在Java和一般情况下的日志:最佳实践?

在Java和一般情况下的日志:最佳实践?
EN

Stack Overflow用户
提问于 2009-05-25 10:45:40
回答 8查看 64.9K关注 0票数 79

有时,当我看到我的日志代码时,我想知道我做得是否正确。这个问题可能没有明确的答案,但我有以下顾虑:

库类

我有几个库类,它们可能记录一些INFO消息。致命错误被报告为异常。目前,我的类中有一个静态记录器实例,使用类名作为日志记录名称。(Log4j's:Logger.getLogger(MyClass.class))

这条路对吗?也许这个库类的用户不想要来自我的实现的任何消息,或者想要将它们重定向到应用程序特定的日志。我应该允许用户从“外部世界”设置一个记录器吗?你是如何处理这类情况的?

常规日志

在某些应用程序中,我的类可能希望将日志消息写入到未由类的名称标识的特定日志中。(例如:HTTP Request log)做这样的事情最好的方法是什么?脑海中浮现出查找服务...

EN

回答 8

Stack Overflow用户

回答已采纳

发布于 2009-05-25 10:48:51

您的约定非常标准,非常好(imho)。

需要注意的一件事是过多的不必要调试调用造成的内存碎片,因此,对于Log4J (和大多数其他Java日志框架),您最终会得到如下结果:

代码语言:javascript
复制
if (log.isDebugEnabled()) {
  log.debug("...");
}

因为构造日志消息(您可能不会使用它)的成本可能很高,特别是在执行数千次或数百万次日志消息时。

你的信息级日志不应该太“闲聊”(从你说的来看,它听起来并不是)。信息消息通常应该是有意义和重要的,就像应用程序被启动和停止一样。如果你遇到问题,你可能想知道的事情。Debug/fine级别的日志记录更多地用于当您实际遇到要诊断的问题时。调试/精细日志记录通常仅在需要时打开。Info通常是一直开着的。

如果有人不想要来自你的类的特定INFO消息,他们当然可以自由地更改你的log4j配置以不获取它们。在这方面,Log4j非常简单(与Java1.4日志记录相反)。

至于HTTP,我一般不认为这是Java日志记录的问题,因为通常只有一个类负责您感兴趣的内容,所以您只需要将它放在一个位置。在这种情况下(在我的经验中很少见),当您想要跨看似不相关的类的公共日志消息时,只需放入一些易于获取的标记即可。

票数 45
EN

Stack Overflow用户

发布于 2018-01-21 13:22:13

以下是我在所有项目中遵循的一组指导原则,以确保良好的性能。我是根据互联网上各种来源的输入来形成这套指南的。

就像今天一样,我相信Java2是迄今为止登录Log4j的最佳选择。

基准测试可以在here上找到。为了获得最佳性能,我遵循的实践如下:

  1. 我现在避免使用SLF4J,原因如下:
    • 它的标记存在一些并发问题,我想用这些标记来管理SQL语句的日志记录(Markers not as powerful as slf4j -请参阅Ralph Goers的第一条评论)
    • 它不支持Java8Lambda,同样,我想使用它来获得更好的性能

为了在一个单独的文件中使用同步记录器更好地记录performance

  • Log错误消息,
  1. 使用异步记录器执行所有常规日志记录,因为我们希望在错误消息发生时立即看到错误消息
  2. 在常规日志记录中不使用位置信息,例如文件名、类名、方法名、行号,因为为了派生这些信息,框架会获取堆栈的快照并遍历它。这会影响性能。因此,只使用错误日志中的位置信息,而不使用常规日志中的位置信息,以便跟踪由单独线程处理的单个请求,请考虑使用线程上下文和随机UUID,因为我们将错误记录在一个单独的文件中,这是非常重要的,我们也将上下文信息记录在错误日志中。例如,如果应用程序在处理文件时遇到错误,则打印错误日志文件中的文件名和正在处理的文件记录以及stacktrace
  3. Log文件应该是可grep且易于理解的。例如,如果应用程序在多个文件中处理客户记录,则每个日志消息应如下所示:

12:01:00,127信息FILE_NAME=file1.txt - Processing开始12:01:00,127 DEBUG FILE_NAME=file1.txt,CUSTOMER_ID=756 12:01:00,129信息FILE_NAME=file1.txt - Processing ends

  1. 使用SQL标记记录所有SQL语句,如下所示,并使用过滤器启用或禁用它:

私有静态最终标记sqlMarker = MarkerManager.getMarker("SQL");私有空method1() { logger.debug(sqlMarker,"SELECT * FROM EMPLOYEE");}

  1. 使用Java8 Lambdas记录所有参数。这将在禁用给定日志级别时从格式化消息中保存应用程序:

样本输出,j=10;logger.info(“

i=5 {},{}",()->i,()->j);

  1. 不使用字符串连接。使用如上所示的参数化消息
  2. 使用日志记录配置的动态重新加载,以便应用程序自动重新加载日志记录配置中的更改,而无需重新启动应用程序
  3. 不使用printStackTrace()

应用程序应在退出前关闭记录器:

LogManager.shutdown();

最后,为了供大家参考,我使用了以下configuration:

  1. 所需的Maven依赖项在此处:

org.apache.logging.log4j log4j-api 2.8.1 org.apache.logging.log4j log4j-核心2.8.1 com.lmax disruptor 3.3.6 org.apache.logging.log4j log4j-1.2-api 2.8.1

票数 22
EN

Stack Overflow用户

发布于 2015-10-18 04:13:29

@cletus' answer中,他写到了

代码语言:javascript
复制
if (log.isDebugEnabled()) {
  log.debug("val is " + value);
}

这可以通过使用SLF4J来克服。它提供了格式化帮助

代码语言:javascript
复制
log.debug("val is {}", value);

其中,仅当级别为debug时才构造消息。

因此,出于性能和稳定性的原因,现在使用SL4J和它的伙伴日志记录器Logback是advised

票数 14
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/906233

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档