基本要素
一行日志的基本要素必须包含时间戳, 日志等级,traceId,线程名称,日志所在类(logger名称),日志内容 等要素。
特别的,对于接口层日志,还应该包含 请求URL。
对于 日志内容, 必须包含:
- “中文问题或操作描述”,(强烈建议中文,一是一眼看明白,二是中文很容易在一堆框架日志中凸显出来)。
- 中文描述前使用 ’[]’用一两个词表示这一组日志是在做什么功能的(或本次调用是做什么功能的)。
- 所有需要登录的请求,必须打印用户id(RequestInfoUtils)。
- 文档id(课程id),空间id,以及其他所有正在操作的实体id。 若有,则必须打印(不用特别只为日志调接口获取)。
- 远程调用时的日志,必须打印参数。
对于对象打印:
建议直接使用log格式, 直接把对象传给logger即可,不需要手动toJSON。
普通日志格式和json格式,都能被常见的日志框架直接解析。
常见日志场景
- controller层参数和返回值(强制): “请求进入”和“请求返回”必须打印日志(common实现)。
- service层参数和返回值(建议):如无必要,不需要打印“请求进入”和“请求返回”。
- rpc调用前后的日志(优先):rpc调用前后打印调用参数和返回值,但对于下方有异常校验,返回值校验的请求可以不打印。
well case:
1 2 3 4 5 6 7 8 9
| InnerRequest<DocParam> request = new InnerRequest<>(); log.info("[点赞]请求doc-server获取文档内容-request:{}", request.getData()); DocResult result = InnerResponseUtils.get(docClient.queryDoc(request));
if (result == null || StringUtils.isBlank(result.getContentJson()) { log.error("[点赞]请求doc-server获取文档内容失败,返回值为空或者内容为空-result:{}", result) throw new GlobalException("xxx"); }
|
- 参数校验和结果校验(强制):所有校验不通过提前结束流程的分支,必须打印日志,且需要包含问题描述和具体参数或返回值。
badcase:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| private class DocParam { @NotNull private Long docId; }
...... if (param.getCreateTime() < someDate) { return null; } Doc doc = doSomething(param.getCreateTime()); if (doc == null) { return new Doc(); } if (StringUtils.isBlank(doc.getDocContentJson()) { log.error("[发布评论]查询文档内容为空"); log.error("[发布评论]查询文档报错了-param:{}", param); throw new GlobalException("xxx"); }
|
- mq消息的发送与接收(强制):mq的发送必须打印完整的消息体。 mq的consume必须打印完整的消息体。
- 异常捕获(强制):异常捕获必须打印日志,必须有错误描述,必须打印当前方法的入参。除非是checked的异常,否则都应该打印异常栈。
badcase:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| try { doSomething(); } catchException e) { }
try { doSomething(); } catch (Exception e) { doSomethingOthers(); }
try { doSomething(); } catch (Exception e) { doSomethingOthers(); log.error("[some]出错了"); log.error("[some]doSomething出错了"); log.error("[some]doSomething出错了-param:{}", param); log.error("[some]doSomething出错了-param:{}, exception:{}", param, e); }
|
- 循环体(强制):循环体不要打印info级别的日志,其他规则遵循1-6。
badcase:
1 2 3 4 5 6
| for (Doc doc : list) { log.info("[文档列表]开始处理-id:{}", doc.getId()); boolean result = doSomething(); log.info("[文档列表]处理结束-id:{}, result:{}", doc.getId(), result); ...... }
|
well case:
1 2 3 4 5 6 7 8
| log.info("[文档列表]开始处理文档列表"); for (Doc doc : list) { boolean result = doSomething(); if (!result) { log.info("[文档列表]处理文档失败-文档id:{}", doc.getId()); } ...... }
|