学习笔记-日志
日志规约
1应中不可直接使日志系统(Log4、Logback)中的API,应依赖使日志框架SLF4J中的AP
使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一。使用SLF4J:
private static final Logger logger = LoggerFactory-getLogger(Test.class)
这里主要的一个目的就是依赖抽象而非依赖具体。如果用Log4j的话,那么1.0到2.0需要改Logger的获取方式,由这个Logger点getLogger改为LoggerManager点getLogger。如果是用SLF4J的话,那么我的代写代码编写方式完全不变,无论是底层的Log4j还是Log2.0,或者是Logback。
SLF4J + Logback
2根据志的不同重要程度使用不同级别的志记录方法DEBUG级别:记录调试信息
INFO级别:记录程序运行过程中的关键信息WARN级别:用于提示存在潜在风险的情况ERROR级别:记录错误信息,会触发邮件报警。TRACE:记录链路信息一般需要整合第三方链路追踪框架???什么是链路信息?
有兴趣的话可以用以下两个问题问豆包trace级别的日志一般咋打多线程情况下怎么打
trace级别的日志一般咋打多线程情况下怎么打
父子线程怎样传逸链路信息 然后怎样整合skywalking框架给出具体方式与代码
百度云盘:
第一期bytebuddy实操详解.mp415G
第三期看skywalkinaagent部分源码.mp414G
第二期-agent定制与sk使用与初步读源码.11G
3 在日志输出时,字符串变量之间的拼接使用占位符的方式。logger.info("Processing trade with id: and symbol: 0". id, symbol)
4 对于trace/debug/info级别的日志输出,必须进行日志级别的开关判断。
#4对于trace/debug/info级别的志输出,如果在你的志打印有法调用或者比较耗时的操作那么必须进志级别的开关判断。
/如果判断为真,那么可以输出 trace 和 debug 级别的日志
虽然在debug(参数)的方法体内第一行代码isDisabled(LevelDEBUG_INT)为真时(Si4j的常见实现Log4和Logback),就直接retum,但是参数可能会进行字符串拼接运算。此外,如果debug(geName)种参数内有getName0方法调用,无谓浪费方法调用的开销
if(logger.isDebugEnabled0){ loggerebugCurent D is: andname is: , id, getName()
if (log.isDebugEnabled()) {
log.debug("{}", obj.getExpensiveData());
}
在乎性能只能这样做,
像传统的 SLF4J 那种,没有懒求值能力。
5避免重复打印日志,浪费磁盘空间务必在日志配置文件中设置additivity=false。
6生产环境禁止直接使用 System.out 或 System.err 输出日志或使用e.printStackTrace(打印异常堆
7 异常信息应该包括两类信息:案发现场信息和异常堆栈信息。如果不处理,那么通过关键字throWs往上抛出。
logger.error(inputParams:and erorMessage:f,各类参数或者对象toString0.e.getMessage().e) 具体业务信息
8 如果对象某些 get 法被覆写,存在拋出异常的情况,则可能会因为打印志而影响正常业务流程的执行。
9异常日志记录
记录异常时应包含足够的上下文信息,如发生异常的时间、地点、操作,以及堆栈跟踪信息。敏感信息处理,不要在日志中打印出敏感信息,如密码、个人信息等,以避免安全风险。
开发日志规范培训笔记(第二波)
内容摘要
- 字符串拼接 vs 占位符:打印日志时应使用占位符方式(如
log.info("{}", var))而非字符串拼接,性能更优,避免不必要的字符串对象创建。 - 日志级别开关判断:当日志语句中包含方法调用或耗时操作时,必须在外层加
if (log.isDebugEnabled())判断,防止生产环境因日志级别配置失误而执行无效的耗时操作,引发性能故障。 - 避免重复打印日志:Log4j/Logback 的 Logger 存在父子继承关系,日志事件会向上传递给父 Logger 的 Appender 再次处理,导致同一条日志被多次输出。解决方式是将子 Logger 的
additivity属性设置为false,阻断向上传递。 - 异常日志应包含两类信息:一是案发现场信息(业务上下文、入参、触发原因等);二是异常堆栈信息(调用链、方法名、行号)。两者缺一不可,否则排查问题无从入手。
- 日志打印不应影响业务流程:若在日志语句中调用对象的 getter 方法,一旦对象为
null,会触发NullPointerException,中断正常业务流程。应提前做判空处理(如 Java 8 的Optional),避免日志辅助代码反过来破坏主流程。
核心亮点 / 金句
- "日志打印的本质是辅助监控行为,不应该影响核心业务流程。" 日志是工具,不能反客为主。
- "防止因日志级别配置错误导致生产故障" :一个忘记关掉的 debug 日志 + 一个耗时方法调用,就可能变成线上事故的根源。
System.out.println是同步阻塞操作,无缓冲、性能差、无法追踪,且散落代码各处难以管理——生产代码中禁止使用。- 敏感信息(如密码)禁止打印到日志:日志文件对开发人员可见,明文密码入日志是严重的安全漏洞。
结论与行动建议
- 建立日志打印 Checklist:每次写 error/warn 级别日志时,自查是否包含业务上下文(入参、操作描述)和堆栈信息;日志语句中是否存在可能为 null 的 getter 调用;是否有耗时方法需要加级别开关判断。
- 检查项目日志配置:确认各子模块 Logger 的
additivity是否已设为false,生产环境的日志级别是否为info或以上,避免 debug 日志在生产环境意外输出。 - 多线程场景下传递 Trace ID:使用 MDC(如 SLF4J 的
MDCAdapter)或链路追踪框架,确保异步/子线程的日志能关联到同一请求的主线程,方便问题定位。
长视频转录笔记:Java 日志规范与 JVM 调优培训
内容摘要
- 操作前要评估后果:每次做技术操作前,需要想清楚可能带来的风险,轻则产生 bug,重则造成生产事故(如司机无法支付被解雇案例),甚至影响产品口碑、股价和公司存亡。
- 日志框架应依赖抽象而非具体实现:不要在应用代码中直接使用 Log4j、Logback 等底层框架,而应通过 SLF4J 等日志门面(Facade)解耦。底层实现升级时,业务代码无需修改,只需更换依赖。类比:老板不直接管每个工人,而是通过包工头/项目经理统一调度。
- 根据重要程度选用不同日志级别:
TRACE:最细粒度,记录代码执行轨迹,生产环境通常关闭DEBUG:调试信息INFO:运行时关键信息WARN:潜在风险提醒(如某 IP 频繁访问达到阈值)ERROR:已发生错误
- 多线程场景下的链路追踪:父子线程间需要传递链路 ID(Trace ID),可借助 SkyWalking + MDC(
TraceContext)实现,子线程通过context自动关联父线程的 Trace ID,从而在日志中还原完整调用链路。 - SkyWalking Agent 的无侵入增强原理:通过字节码增强(类似 ByteBuddy)在编译期/加载期向目标类注入拦截逻辑,无需修改业务代码即可采集链路数据。这也是简历中可包装的技术亮点。
核心亮点 / 金句
"依赖于抽象,而不要依赖于具体。" —— SLF4J 的设计哲学,同样适用于接口设计和架构思维。
"你不是怕被裁才去学习,而是为了提升自己。现在提前开始,相当于提前布局。"
"你业务代码可以不写,但异常处理和日志是频繁需要整的,它类似于基础设施。"
"日志搞得越细,出问题时越能快速定位;一个方法可以拆成链路的多个节点。"
结论与行动建议
- 立即落地两个自学任务:① 研究多线程场景下如何通过
MDC+ SkyWalking 传递 Trace ID;② 了解 SkyWalking Agent 的字节码增强原理。可用 AI 工具(豆包、ChatGPT)辅助生成代码 demo,再自己理解消化,用于面试包装。 - 面试时必须能回答两类问题:① 你们公司如何打日志、日志规范是什么;② 有没有生产故障经历,如何排查解决。结合本次 JVM 调优案例与日志体系,整理出一套完整的"故障排查 → 链路追踪 → 日志定位"叙述脉络。
- 实习/试用期心态建议:不要催活,主动学习,提升技术才是根本。被裁或跳槽时,提前积累的技术深度是最大的底气。
