前言
首先, 这篇文章没有进行任何的日志功能的详细介绍, 而是对日志提出了几种最佳实践适合对日志记录有所了解的同学阅读
下面是正文:
JAVA 日志管理既是一门科学, 又是一门艺术科学的部分是指了解写日志的工具以及其 API, 而选择日志的格式, 消息的格式, 日志记录的内容, 哪种消息对应于哪一种日志级别, 则完全是基于经验从过去的实践证明, JAVA 的日志记录会严重的影响性能我也曾多次亲眼见到在 DEBUG 模式下运行的在线股票交易程序, 比在 WARN 或是其它更高层次模式下运行时延时要严重的多延时和速度是任何电子交易平台或是股票交易平台的一个重大关注点, 所以我们必须了解并掌握 JAVA 日志及其最佳实践这不仅仅只是为了用在金融或是投资银行领域, 它适用于所有既追求速度又需要日志功能的应用
为何需要日志
这是一个很基本的争议, 人们会争辩说, 我们可以使用
System.out.println()
来打印消息, 为何还需要日志呢? 每个人刚开始接触 JAVA 时, 都使用
System.out.println()
在控制台打印消息但是它的功能远远没有日志记录 API 如 log4j 或是 java.util.logging 强大如果你正在写一个 java 服务器应用, 那么你只有通过日志文件才能知道你的服务器在做什么如果你没有记录任何日志, 那么没有人知道你的服务器在干啥而如果你的服务器作为一个中间件连接到应用中时, 比如从股票交易系统或是电子交易系统获得输入流, 将其转换并标准化后发送到输出流, 这时日志就更为重要没有日志你根本不知道究竟哪里出了问题因此, 日志在 JAVA 中是必不可少的
JAVA 中有哪些不同的日志级别
使用过 JAVA 日志的童鞋一定知道这些基础的日志级别比如
DEBUG, INFO, WARN 和 ERROR
DEBUG 是最低的限制级别这个级别只能用于开发和测试环境中, 不可以用于生产环境
INFO 略高于 DEBUG 的限制级别, 我们应该用这个级别记录一些信息型消息比如服务器启动成功, 输入的数据, 输出的数据等等
WARN 的限制级别高于 INFO , 它用来记录警告信息比如客户端和服务器之间的连接中断, 数据库连接丢失, Socket 达到上限这些信息是最为重要的, 因为你可以在这些信息出现时发出警告, 从而让运维团队管理应用程序的运行, 并及时处理这些报错
ERROR 比 WARN 的限制级别还高, 用于记录 ERROR 和 Exception 你可以在该日志级别上设置警报装置, 并且提醒运维团队对之做出处理 ERROR 非常重要, 你必须将其记录下来
FATAL 是指可能导致程序终止的非常严重的时间在这种事件之后你的应用很可能会崩溃
OFF 具有最高的级别, 旨在关闭 JAVA 中的日志功能
这些日志级别是根据 slf4j 整理的, 和 java.util.logging API 中定义的级别不太一样 java.util.logging 还提供了其它的基于问题严重性进行划分的日志级别如
SEVERE, FINER, FINEST, FATAL
等
使用 log4j 还是 java.util.logging
我会推荐使用 log4j, 你可能会对此持有异议我也同意 java.util.logging 的功能很强大, 但是我发现 log4j 更易于使用你已经了解了 log4j 的各个日志级别, 这里每个级别都非常恰当的描述了其功能 log4j 还提供了额外的灵活性, 你无需重新启动应用来改变日志的级别当然, 你也可以在 java.util.logging 中通过 JMX 实现这个功能
log4j 还允许我们在配置文件 log4j.xml 中设置每个类的日志级别你既可以使用 XML 文件也可以使用 properties 文件进行配置而且 log4j 是线程安全的它被设计用于高并发的系统中在另一方面, 我发现 java.util.logging 中的 Formatter 和 Appender 功能非常棒
为何在 JAVA 中使用日志会影响性能
通常来说, 记录日志越频繁, 所需的 IO 操作就越多, 从而影响了应用的性能因此为每一个消息选择一个合适的日志级别是非常重要的既然我们不能不使用 JAVA 日志, 那么我们只能控制日志的级别以及在那个级别上记录的日志内容所以, 一定要在 isDebugEnabled() 代码块中记录 DEBUG 消息, 如下所示:
- if(logger.isDebugEnabled()){
- logger.debug("java logging level is DEBUG Enabled")
- }
在生产环境中一定要使用 WARN 或是更高级别的日志记录等级, 一定不要使用 DEBUG 它很可能成为性能下降的罪魁祸首
JAVA 日志的 10 个小建议
1. 将 DEBUG 日志访日 isDebugEnabled 代码块
它能显著的减少因为字符串拼接而带来的性能的影响
2. 谨慎的消息的等级
当你在编写服务器端应用时, 这一点显得格外的重要, 因为它是你观察服务器运行情况的唯一途径如果你记录了太多的日志, 则会影响服务器的性能, 但是如果你不记录重要的信息如输入数据和输出数据, 那么就很难识别究竟发生了什么问题
3. 使用 slf4j 或是 java.util.loggin
我推荐 slf4j 因为它的灵活性非常高它允许在不重启应用的前提下更改日志级别你可以通过 log4j 的看门狗来不停的寻找目录中的 log4j.xml 配置文件, 并且在找到后重置日志配置
4.log4j 可以为不同的类配置不同的日志级别
你可以将一些类设置为 INFO 级别, 再将另一些类设置为 WARN 级别或是 ERROR 级别
5. 日志的格式化
不要忘了记录线程的名称和完整的 JAVA 类名, 因为如果有多个线程同时在执行这段代码, 你可能根本找不出事件序列在我看来, 这一条建议最为重要
6. 从日志中生成报告
在记录日志时要保证一致性和信息性, 从而可以分析日志
7. 使用前缀来说明哪一部分代码在打印日志
前缀是指如客户端, 数据库或是 Session 等等之后你可以使用 grep 或是 find 来找到和这些关键字相关的日志我在进行了这种实践后发现它非常有助于 debug 或是调查事件, 尤其是当日志文件很庞大的时候你可以将所有数据库级别的日志加上前缀 DB_LOG , 再将所有 SESSION 级别的日志加上前缀 SESSION_LOG
8. 如果某个日志没有分配等级, 则将其继承最近级别的等级
这也是为什么我们总是将日志等级分配到根日志上
log4j.rootLogger=DEBUG.
9. 没有日志和过度日志都是不好的
原因前面已经说明
10. 自检日志并调整日志
最好用英文记录日志, 而且要有良好的可读性, 从而在查阅时能够快速理解日志
11. 使用标准化格式而不要自行拼接
- logger.debug("No of Orders" + noOfOrder + "for client:" + client);// 不好
- logger.debug("No of Orders {} for client: {}", noOfOrder, client);
补充: 记录哪些信息以及各个信息对应什么级别的日志
1. 不要记录敏感信息
不要记录敏感信息如密码, 身份证号, 信用卡号或账户号
2. 尽量记录决策性信息
比如, 一个 JAVA 应用需要从偏好文件或是环境中加载配置, 如果没有找到就使用默认的配置如果你在使用默认配置, 那么你应当记录如下信息:
logger.info("Not able to load personal settings, default Setting selected for user : {}", user);
这个日志丢失了一个关键性信息, 为什么无法加载到个人配置? 因此如果出现异常的话, 还应当记录异常当然, 这条日志也提供了有用的信息, 比如究竟是哪个用户遇到了这个问题
3. 一致性
一致性在日志和编码中都很重要无论你采用哪种格式, 你都应当坚持一致性你应当花些时间仔细考虑日志的格式, 从而用它来捕获有用的信息
4. 记录一切出现问题时辅助 debug 的信息
举个例子, 我们经常在应用中将 String 转化为 Date, 如果 String 的格式不正确的话, 我们通常会抛出 ParseException 但是我经常看到有的代码里捕获了这个异常之后, 将 Date 赋值为 null 并打印如下日志:
logger.info("failed to convert String to date")
看到这行日志的时候, 你根本不知道那个 date 传入了不合法的值它也没有打印出不合法的 String 的内容究竟是什么你需要这些信息来解决这个问题一个更好的日志信息如下:
logger.info("invalid startDate: {}", startDate);
来源: http://www.tuicool.com/articles/Ff6jUvA