当前位置: 首页 > news >正文

Alibaba开发规范_异常日志之日志规约:最佳实践与常见陷阱

文章目录

    • 引言
    • 1. 使用SLF4J日志门面
      • 规则
      • 解释
      • 代码示例
        • 正例
        • 反例
    • 2. 日志文件的保存时间
      • 规则
      • 解释
    • 3. 日志文件的命名规范
      • 规则
      • 解释
      • 代码示例
        • 正例
        • 反例
    • 4. 使用占位符进行日志拼接
      • 规则
      • 解释
      • 代码示例
        • 正例
        • 反例
    • 5. 日志级别的开关判断
      • 规则
      • 解释
      • 代码示例
        • 正例
        • 反例
    • 6. 避免重复打印日志
      • 规则
      • 解释
      • 代码示例
        • 正例
        • 反例
    • 7. 记录异常信息
      • 规则
      • 解释
      • 代码示例
        • 正例
        • 反例
    • 8. 谨慎记录日志
      • 规则
      • 解释
    • 9. 使用`warn`记录用户输入错误
      • 规则
      • 解释
      • 代码示例
        • 正例
        • 反例
    • 10. 使用英文描述日志错误信息
      • 规则
      • 解释
      • 代码示例
        • 正例
        • 反例
    • 总结

在这里插入图片描述

引言

日志是软件开发中不可或缺的一部分,合理的日志记录可以帮助开发者快速定位问题、监控系统运行状态。本文将深入探讨Java日志规约的最佳实践,并通过反例和正例代码来更好地理解和应用这些规则。


1. 使用SLF4J日志门面

规则

  • 应用中不可直接使用日志系统(Log4j、Logback)中的API,而应依赖使用日志框架SLF4J中的API

解释

SLF4J(Simple Logging Facade for Java)是一个日志门面框架,它提供了统一的API,允许应用程序在不修改代码的情况下切换底层日志实现(如Log4j、Logback)。使用SLF4J可以提高代码的可维护性和灵活性。

代码示例

正例
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class Test {private static final Logger logger = LoggerFactory.getLogger(Test.class);public void doSomething() {logger.info("This is an info message.");}
}
反例
import org.apache.log4j.Logger;public class Test {private static final Logger logger = Logger.getLogger(Test.class);public void doSomething() {logger.info("This is an info message.");}
}

在反例中,直接使用Log4j的API,导致代码与具体日志实现耦合,难以切换日志框架。


2. 日志文件的保存时间

规则

  • 所有日志文件至少保存15天,因为有些异常具备以“周”为频次发生的特点。网络运行状态、安全相关信息、系统监测、管理后台操作、用户敏感操作需要留存相关的网络日志不少于6个月

解释

日志文件的保存时间应根据业务需求和法律要求来确定。通常,日志文件至少保存15天,而涉及安全和敏感操作的日志需要保存更长时间(如6个月)。


3. 日志文件的命名规范

规则

  • 应用中的扩展日志(如打点、临时监控、访问日志等)命名方式:appName_logType_logName.log

解释

通过规范的日志文件名,可以快速识别日志的来源、类型和用途,便于日志的管理和查找。

代码示例

正例
force_web_timeZoneConvert.log
反例
log.txt

在反例中,日志文件名过于简单,无法快速识别日志的来源和用途。


4. 使用占位符进行日志拼接

规则

  • 在日志输出时,字符串变量之间的拼接使用占位符的方式

解释

使用占位符(如{})进行日志拼接可以避免不必要的字符串拼接操作,提高性能。

代码示例

正例
logger.debug("Processing trade with id: {} and symbol: {}", id, symbol);
反例
logger.debug("Processing trade with id: " + id + " and symbol: " + symbol);

在反例中,使用字符串拼接会导致性能损耗,尤其是在日志级别较高时(如INFOWARN)。


5. 日志级别的开关判断

规则

  • 对于trace/debug/info级别的日志输出,必须进行日志级别的开关判断

解释

在输出日志之前进行级别判断,可以避免不必要的字符串拼接和方法调用,提高性能。

代码示例

正例
if (logger.isDebugEnabled()) {logger.debug("Current ID is: {} and name is: {}", id, getName());
}
反例
logger.debug("Current ID is: " + id + " and name is: " + getName());

在反例中,即使日志级别高于DEBUG,仍然会执行字符串拼接和方法调用,造成性能浪费。


6. 避免重复打印日志

规则

  • 避免重复打印日志,浪费磁盘空间,务必在log4j.xml中设置additivity=false

解释

additivity属性控制子Logger是否继承父Logger的输出源。设置为false可以避免日志重复输出。

代码示例

正例
<logger name="com.taobao.dubbo.config" additivity="false"><appender-ref ref="FILE"/>
</logger>
反例
<logger name="com.taobao.dubbo.config"><appender-ref ref="FILE"/>
</logger>

在反例中,未设置additivity=false,可能导致日志重复输出。


7. 记录异常信息

规则

  • 异常信息应该包括两类信息:案发现场信息和异常堆栈信息

解释

记录异常时,应包含案发现场信息(如参数值、状态等)和异常堆栈信息,以便快速定位问题。

代码示例

正例
try {// 业务逻辑
} catch (Exception e) {logger.error("Error processing trade with id: " + tradeId, e);
}
反例
try {// 业务逻辑
} catch (Exception e) {logger.error("Error occurred");
}

在反例中,未记录异常堆栈信息,难以定位问题。


8. 谨慎记录日志

规则

  • 生产环境禁止输出debug日志;有选择地输出info日志;使用warn记录业务行为信息时,注意日志输出量

解释

过多的日志输出会影响系统性能,并增加日志管理的难度。应根据实际需求谨慎记录日志。


9. 使用warn记录用户输入错误

规则

  • 可以使用warn日志级别来记录用户输入参数错误的情况,避免用户投诉时无所适从

解释

使用warn级别记录用户输入错误,可以在不频繁报警的情况下,提供足够的信息用于问题排查。

代码示例

正例
if (userInput == null) {logger.warn("User input is null");
}
反例
if (userInput == null) {logger.error("User input is null");
}

在反例中,使用error级别记录用户输入错误,可能导致频繁报警。


10. 使用英文描述日志错误信息

规则

  • 尽量用英文来描述日志错误信息,如果日志中的错误信息用英文描述不清楚的话使用中文描述即可

解释

使用英文描述日志错误信息可以提高日志的通用性,特别是在国际化团队或海外部署的场景中。

代码示例

正例
logger.error("Failed to process trade: tradeId={}", tradeId);
反例
logger.error("处理交易失败:tradeId={}", tradeId);

在反例中,使用中文描述日志错误信息,可能导致国际化团队难以理解。


总结

通过遵循日志规约的最佳实践,开发者可以编写出高效、易维护的日志代码。

在这里插入图片描述

http://www.lryc.cn/news/531257.html

相关文章:

  • 使用istio实现权重路由
  • M. Triangle Construction
  • 每天学点小知识之设计模式的艺术-策略模式
  • 机试题——到邻国目标城市的最短距离
  • Python + Tkinter + pyttsx3实现的桌面版英语学习工具
  • 【Vite + Vue + Ts 项目三个 tsconfig 文件】
  • AI时代IT行业职业方向规划大纲
  • Mac M1 Comfyui 使用MMAudio遇到的问题解决?
  • 大语言模型深度研究功能:人类认知与创新的新范式
  • [SAP ABAP] 性能优化
  • 并行计算、分布式计算与云计算:概念剖析与对比研究(表格对比)
  • ASP.NET Core Filter
  • doris:删除操作概述
  • 【思维导图】redis
  • 申博经验贴
  • .Net Core笔记知识点(跨域、缓存)
  • YOLOV11-1:YoloV11-安装和CLI方式训练模型
  • 自学习记录-编程语言的特点(持续记录)
  • TypeScript (TS) 和 JavaScript (JS)
  • 【HarmonyOS之旅】基于ArkTS开发(二) -> UI开发三
  • 如何选择Spring AOP的动态代理?JDK与CGLIB的适用场景?
  • 手机连接WIFI可以上网,笔记本电脑连接WIFI却不能上网? 解决方法?
  • MySQL不适合创建索引的11种情况
  • 树莓派pico入坑笔记,故障解决:请求 USB 设备描述符失败,故障码(43)
  • GRE阅读双线阅读 --青山学堂GRE全程班 包括 阅读、数学、写作、填空、背单词
  • 98,【6】 buuctf web [ISITDTU 2019]EasyPHP
  • Kamailio、MySQL、Redis、Gin后端、Vue.js前端等基于容器化部署
  • 知识管理系统助力企业信息共享与创新思维的全面提升研究
  • Leetcode 131 分割回文串(纯DFS)
  • 结构体DMA串口接收比特错位