@1234567890
2018-07-02T09:12:31.000000Z
字数 2889
阅读 1106
日志规范
ERROR
ERROR是最高级别错误,反映系统发生了非常严重的故障,无法自动恢复到正常态工作,需要人工介入处理。系统需要将错误相关痕迹以及错误细节记录ERROR日志中,方便后续人工回溯解决。
WARN
WARN是稍微低级别异常日志,反映系统在业务处理时触发了异常流程,但系统可恢复到正常态,下一次业务可以正常执行。但WARN级别问题需要开发人员给予足够关注,往往表示有参数校验问题或者程序逻辑缺陷,当功能逻辑走入异常逻辑时,应该考虑记录WARN日志。
INFO
INFO日志主要记录系统关键信息,旨在保留系统正常工作期间关键运行指标,可以将初始化系统配置、业务状态变化信息,或者用户业务流程中的核心处理记录到INFO日志中,方便日常运维工作以及错误回溯时上下文场景复现。
DEBUG
DEBUG日志是INFO日志的好帮手,开发人员可以将各类详细信息记录到DEBUG里,起到调试的作用,包括参数信息,调试细节信息,返回值信息等等。其他等级不方便显示的信息都可以通过DEBUG日志来记录。
捕获的异常是系统告知开发人员需要加以关注的,应当适当记录日志,根据实际结合业务的情况使用warn或者error级别
结果与期望不符时也是日志场景之一,简单来说所有流程分支都可以加入考虑。取决于开发人员判断能否容忍情形发生。常见的合适场景包括外部参数不正确
系统中核心角色触发的业务动作是需要多加关注的,是衡量系统正常运行的重要指标,建议记录INFO级别日志,比如电商系统用户从登录到下单的整个流程;微服务各服务节点交互;核心数据表增删改;核心组件运行等等
系统或者服务的启动参数。核心模块或者组件初始化过程中往往依赖一些关键配置,根据参数不同会提供不一样的服务
错误日志。级别比较高,如果发生一些异常,并且任何时候都需要打印时使用。
1. 打开配置文件失败
2. 所有第三方对接的异常(包括第三方返回错误码)
3. 所有影响功能使用的异常,包括:SQLException和除了业务异常之外的所有异常(RuntimeException和Exception)
如果有Throwable信息,需要记录完成的堆栈信息:
log.error("获取用户[{}]的用户信息时出错",userName,e);
如果进行了抛出异常操作,请不要记录error日志,由最终处理方进行处理
//反例(不要这么做)
try{
....
}catch(Exception ex){
String errorMessage=String.format("Error while reading information of user [%s]",userName);
logger.error(errorMessage,ex);
throw new UserServiceException(errorMessage,ex);
}
不应该出现但是不影响程序、当前请求正常运行的异常情况
系统运行信息
时间
包含时区信息和毫秒,这个工作往往日志框架足以支持。核心属性之一。
日志级别
例如 debug、info 以及warn、error
会话标识
能知道是哪个客户端或者是哪个用户触发,登陆账号,seesion信息等
功能标识
功能标识的意义在于方便日志搜索,跟踪指定功能的完整轨迹,是INFO,DEBUG日志的常见技巧。跟logger分类同一道理,更细分功能标识则是方法标识,更多使用在DEBUG做在线调试使用。
精炼的内容
内容永远是日志的核心,结合上述使用场景,简单来说包括场景信息(谁,什么功能等),状态信息(开始,中断,结束)以及重要参数.
其他信息
其他可能的有用信息包括:版本号,线程号等等。
log.debug("[接口名或操作名] [what/how] [params]");
log.info("[接口名或操作名] [what/how] [params]");
log.warn("[接口名或操作名] [Some Error Msg] happens [params]");
log.error("[接口名或操作名] [Some Error Msg] happens [Probably Because] [Probably need to do] [params]");
Logger实例
应用中不可直接使用日志系统(Log4j、Logback)中的API,而应依赖使用日志框架SLF4J中的API,使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger logger = LoggerFactory.getLogger(Abc.class);
占位符的方式
logger.debug("Processing trade with id: " + id + " symbol: " + symbol); 如果日志级别是warn,上述日志不会打印,但是会执行字符串拼接操作,如果symbol是对象,会执行toString()方法,浪费了系统资源,执行了上述操作,最终日志却没有打印。
logger.debug("Processing trade with id: {} symbol : {} ", id, symbol);
避免重复打印日志
additivity默认为true,即通过该logger输出的日志会同时输出到root logger,如果还为该logger指定了独立的appender,就会导致这部分日志重复输出
避免重复打印日志,浪费磁盘空间,务必在配置中设置additivity=false。
案发现场信息和异常堆栈信息
异常信息应该包括两类信息:案发现场信息和异常堆栈信息。如果不处理,那么通过关键字throws往上抛出。
记录异常日志的常见错误:
logger.error(e);
logger.error(e.getMessage());
logger.error("上下文"+e.getMessage());
上面这几种都是错的!请确保使用的是两个入参的API,如error(String s, Throwable t)
logger.error(各类参数或者对象toString + "_" + e.getMessage(), e);
记录日志又抛异常
不允许记录日志后又抛出异常,因为这样会多次记录日志,只允许记录一次日志。