java日志信息和格式_业务日志内容与格式探讨

本文探讨了Java日志的各个级别,如ERROR、WARN、INFO和DEBUG的使用场景和重要性,强调了WARN频繁时应触发报警,ERROR日志的警报需直接和紧急。建议使用日志模板,并指出日志应包含时间、线程、级别、异常信息等。推荐使用Log4j 2.x及其配置,以及SLF4J作为日志门面。遵循阿里Java编程规范,确保日志的有效性和资源效率。
摘要由CSDN通过智能技术生成

在开发日志系统,简单的日志系统用ELK即可,代码量很少。在分析日志时,发现大量日志格式存在问题,真正的工作在于日志内容的分类、日志格式的梳理。

日志级别概述

ERROR

ERROR是最高级别错误,反映系统发生了非常严重的故障,无法自动恢复到正常态工作,需要人工介入处理。系统需要将错误相关痕迹以及错误细节记录ERROR日志中,方便后续人工回溯解决。

WARN

WARN是低级别异常日志,反映系统在业务处理时触发了异常流程,但系统可恢复到正常态,下一次业务可以正常执行。但WARN级别问题需要开发人员给予足够关注,往往表示有参数校验问题或者程序逻辑缺陷,当功能逻辑走入异常逻辑时,应该考虑记录WARN日志。

INFO

INFO日志主要记录系统关键信息,旨在保留系统正常工作期间关键运行指标,开发人员可以将初始化系统配置、业务状态变化信息,或者用户业务流程中的核心处理记录到INFO日志中,方便日常运维工作以及错误回溯时上下文场景复现。

DEBUG

开发人员可以将各类详细信息记录到DEBUG里,起到调试的作用,包括参数信息,调试细节信息,返回值信息等等。其他等级不方便显示的信息都可以通过DEBUG日志来记录

使用WARN和统计报警

由于WARN是低级别异常日志,不需要马上处理。但是如果频次过于频繁,达到一定阈值,就发出报警,进行处理。

强调ERROR报警

ERROR的报出应该伴随着业务功能受损,即上面提到的系统中发生了非常严重的问题,必须有人马上处理。

ERROR日志目标

给处理者直接准确的信息:error信息形成自身闭环。

问题定位:发生了什么问题,哪些功能受到影响

获取帮助信息:直接帮助信息或帮助信息的存储位置

通过报警知道解决方案或者找何人解决

实用模板

日志模板2选1:

log.error(“[接口名或操作名] [Some Error Msg] happens. [Probably Because]. [Probably need to do] [params] .”);

log.error(“[接口名或操作名] [Some Error Msg] happens. [Probably Because]. [please contact xxx@xxx] [params] .”);

尽量按上述模板完成,如果实施起来有难度,至少ERROR 日志打印时需要在做一个自我问答,能非常有效的帮助评估这条报警是否有意义:这条报警看到之后我能处理吗? 应该怎么处理? 如果是同事看到能处理或者及时通知联系人呢吗? 因为你不可能保证随时都处在工作状态,但报警时随时有可能出现的。

日志输出内容

日志输出的注意点

我不确定大家是否遇到过下面的情况:*排查问题时,发现那块出现错误的地方有日志输出,但是输出的日志对于排查问题一点用都没有**,每当出现这种情况的时候我都想骂人。

好的日志需要有哪些内容呢?

发生时间

出现问题的线程

日志级别

出现问题的类文件,类的哪一行,异常栈

程序入参

相应的程序员的注释等

(可选项)

会话标识,能知道是哪个客户端或者是哪个用户触发,登陆账号,seesion信息等

通过RequestID来对请求进行唯一的标记,目的是可以通过RequestID将一个请求在系统中的执行过程串联起来。根据不同的目的生成RequestID,必要时在RequestID中尽量编码更多的信息

日志框架选型

新的Log4j 2.x版本有了大幅的性能提升、新的插件系统,以及配置设置方面的很多改善。Log4j 1.x 在高并发情况下出现死锁导致cpu使用率异常飙升,而Log4j2.x基于LMAX Disruptor的异步日志在多线程环境下性能会远远优于Log4j 1.x和logback。

log4j2-spring.xml配置

springboot 推荐***-spring.xml的命名规范。

日志配置主要涉及2点:

who? 就是谁输出日志,可指定根目录、或者具体的包路径

输出的目录与格式

日志包含基本内容:

发生时间

出现问题的线程

日志级别

出现问题的类文件,类的哪一行,异常栈

循环日志文件:日志文件大于阀值的时候,就开始写一个新的日志文件

配置格式扩展

自定义格式:

%t:线程名称

%p:日志级别

%c:日志消息所在类名

%m:消息内容

%M:输出执行方法

%d:发生时间,%d{yyyy-MM-dd HH:mm:ss,SSS},输出类似:2011-10-18 22:10:28,921

%x: 输出和当前线程相关联的NDC(嵌套诊断环境),尤其用到像java servlets这样的多客户多线程的应用中。

%L:代码中的行数

%n:换行

Logger Names

package org.apache.test;

public class MyTest {

private static final Logger logger = LogManager.getLogger();

}

代码日志打印

With Java 8 you can achieve the same effect with a lambda expression. You no longer need to explicitly check the log level:

Java-8 style optimization: no need to explicitly check the log level:

the lambda expression is not evaluated if the TRACE level is not enabled

logger.trace("Some long-running operation returned {}", () -> expensiveOperation());

在java8中不用显示判断日志级别,如果未启用该日志级别,则不会执行lambda表达式。

自定义过滤器类

log4j2中用ThreadContext代替MD

public class ThreadContextFilter implements Filter {

@Override

public void init(FilterConfig filterConfig) throws ServletException {

}

@Override

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

try {

ThreadContext.put("UUID", StaticUUID.ID); //StaticUUID是自己写的类,用于生成UUID常量。

ThreadContext.put("ip", request.getLocalAddr());

chain.doFilter(request, response);

} finally {

//清除ThreadContext,避免内存泄露

ThreadContext.clearAll();

}

}

@Override

public void destroy() {

}

}

这样可以在日志中动态输出一些信息,如ip,用户名等。

阿里java编程规范-日志部分:

日志规约

【强制】应用中不可直接使用日志系统(Log4j、Logback)中的API,而应依赖使用日志框架SLF4J中的API,使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一。

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

private static final Logger logger = LoggerFactory.getLogger(Abc.class);

slf4j是日志门面框架,其仅提供日志记录的API,而不实现日志记录的功能,slf4j需要通过适配库适配到log4j或logback等日志系统来实现日志的记录。使用slf4j api能够提升代码和应用的可移植性,在使用不同日志系统的应用之间能够做到无缝的适配。同时,使用slf4j api的应用,在切换日志系统时(比如从logback切换到log4j2,不需要代码改造)

【强制】日志文件推荐至少保存15天,因为有些异常具备以“周”为频次发生的特点。

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

logType:日志类型,推荐分类有stats/desc/monitor/visit等;

logName:日志描述。这种命名的好处:通过文件名就可知道日志文件属于什么应用,什么类型,什么目的,也有利于归类查找。

正例:mppserver应用中单独监控时区转换异常,如: mppserver_monitor_timeZoneConvert.log

说明:推荐对日志进行分类,如将错误日志和业务日志分开存放,便于开发人员查看,也便于通过日志对系统进行及时监控。

【强制】对trace/debug/info级别的日志输出,必须使用条件输出形式或者使用占位符的方式。

说明:logger.debug("Processing trade with id: " + id + " symbol: " + symbol); 如果日志级别是warn,上述日志不会打印,但是会执行字符串拼接操作,如果symbol是对象,会执行toString()方法,浪费了系统资源,执行了上述操作,最终日志却没有打印。

正例:(条件)

if (logger.isDebugEnabled()) {

logger.debug("Processing trade with id: " + id + " symbol: " + symbol);

}

正例:(占位符)

logger.debug("Processing trade with id: {} symbol : {} ", id, symbol);

占位符方式,log4j2/logback支持,log4j1.x是不直接支持的,只能通过slf4j库适配

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

正例:

additivity默认为true,即通过该logger输出的日志会同时输出到root logger,如果还为该logger指定了独立的appender,就会导致这部分日志重复输出

【强制】异常信息应该包括两类信息:案发现场信息和异常堆栈信息。如果不处理,那么通过关键字throws往上抛出。

正例:

logger.error(各类参数或者对象toString + "_" + e.getMessage(), e);

记录异常日志的常见错误:

logger.error(e);

logger.error(e.getMessage());

logger.error("上下文"+e.getMessage());

上面这几种都是错的!请确保使用的是两个入参的API,如error(String s, Throwable t)

【推荐】谨慎地记录日志。生产环境禁止输出debug日志;有选择地输出info日志;如果使用warn来记录刚上线时的业务行为信息,一定要注意日志输出量的问题,避免把服务器磁盘撑爆,并记得及时删除这些观察日志。

说明:大量地输出无效日志,不利于系统性能提升,也不利于快速定位错误点。记录日志时请思考:这些日志真的有人看吗?看到这条日志你能做什么?能不能给问题排查带来好处?不要认为日志记录不怎么消耗性能,我见过不少事无巨细式的日志把系统性能严重拖慢的案例

【参考】可以使用warn日志级别来记录用户输入参数错误的情况,避免用户投诉时,无所适从。注意日志输出的级别,error级别只记录系统逻辑出错、异常等重要的错误

参考

tips:本文属于自己学习和实践过程的记录,很多图和文字都粘贴自网上文章,没有注明引用请包涵!如有任何问题请留言或邮件通知,我会及时回复。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值