Java技术栈

www.javastack.cn

关注阅读更多优质文章

作者:lipengxs

链接:my.oschina.net/lipengxs/blog/3156247

背景

日志内容复杂多样,如何去收集有价值的日志是我们重点关注的。日志的价值其实是取决于业务操作的,不同的业务场景下相同类型的日志的价值会截然不同。

根据以往的业务实践,结合企业级的一些业务需求,我们选定关注以下几类日志。

  • 跟踪日志【trace.log】 Server引擎的调试日志,用于系统维护人员定位系统运行问题使用。

  • 系统日志【system.log】 大粒度的引擎运行的入口、出口的日志,用于调用栈分析,可以进行性能分析使用。

  • 部署日志【deploy.log】 记录系统启动、停止、构件包部署、集群通知等信息的日志。

  • 引擎日志【engine.log】 细粒度的引擎运行日志,可以打印上下文数据,用于定位业务问题。

  • 构件包日志【contribution.log】 构件包记录的业务日志(使用基础构件库的日志输出API写日志)

这里我们专门针对系统日志收集讨论几种收集方案,关注微信公众号Java技术栈,在后台回复:微服务,可以获取我整理的 N 篇 微服务系列教程,都是干货。

方案一:通过日志组件来收集

这里是指通过logback、log4j等日志组件来输出文件,然后再通过文件输出到logstash、kibana等日志组件中,通过这些日志组件来进行可视化统计与分析,这里需要统一关键日志输出格式方便日后统计搜索。

优点

缺点

方案二:使用aop来拦截controller

拦截controller层,通过controller中的方法名是否包含insert、update、delete等关键字来记录业务日志。

优点

缺点

方案三:使用注解来,进行稍微精准的业务日志记录

这个方案粒度可大可小,代码侵入性也比较小,可操作性比较强,如果需要获取参数信息或者返回值信息,可以通过注解配置获取到,可以集合fastjson中的jpath来获取参数值下面有几个伪代码供参考

@Slf4j
@Aspect
public class SysLogAspect {

 @Around("@annotation(sysLog)")
 @SneakyThrows
 public Object around(ProceedingJoinPoint point, SysLog sysLog) {
  // 根据系统上下文获取相关数据
  Operation logVo = SysLogUtils.getOperationModel();
  Object obj=null;
  try{
   // 操作方式
   logVo.setOperationName(sysLog.value());
   // 操作时间
   logVo.setOperationTime(new Date());
   logVo.setObjectType(sysLog.objectType().name());
   logVo.setAppName(StringUtils.defaultString(sysLog.appName(),"TSP"));
   // 发送异步日志事件
   obj = point.proceed();
   if(StringUtils.isNotBlank(sysLog.objectIdKey())&&StringUtils.isNotBlank(sysLog.objectNameKey())){
    Map<String,Object> params=Maps.newHashMap();
    params.put("args",point.getArgs());
    params.put("response",obj);
    logVo.setObjectId(getKeyValue(sysLog.objectIdKey(),params));
    logVo.setObjectName(getKeyValue(sysLog.objectNameKey(),params));
   }
  }catch (BusinessException e){
   logVo.setException(e.getMessage());
   throw new Exception(e);
  }catch (RuntimeException e){
   logVo.setException(e.getMessage());
   throw new Exception(e);
  }catch (Exception e){
   logVo.setException(e.getMessage());
   throw new Exception(e);
  }finally {
   ApplicationContextUtils.publishEvent(new OperationEvent(logVo));
  }
  return obj;
 }

 private String getKeyValue(String key,Map<String,Object> params){
  try{
   Object mm= JSONPath.eval(params,key);
   if(mm!=null){
    return mm.toString();
   }
  }catch (Exception e){
   log.error("JSONPath.eval:",e);
  }
  return null;
 }


}

@SysLog(value = "xxxxxx",objectType = LogObjectType.OFFLINE_THRONG, 
    objectIdKey = "$['args'][0][0]['id']",objectNameKey = "$['response'][0][0]['throngName']")

优点

  • 操作简单

  • 较灵活,粒度可大可小

缺点

  • 有代码侵入

  • 个性化需求不满足

方案四:针对复杂场景或者审计需求手动记录,侵入性强

如果有些业务共用了方法,需要更小的粒度,或者需要记录业务数据变更记录,这时就只能选择侵入式较强的方式来记录日志了,直接在业务代码中记录日志,日志系统新贵 Loki,这个推荐看下。

logClient.logObject(LogObjectType.XXX,id,UserContext.getUserName(),"编辑xxx","xxx变更为xxxxx");

方案五:记录sql日志

则可以使用mybatis拦截器来进行,如果没有使用mybatis,则可以做一个通用的preparestatement以及statement代理。

当然现在已经有很对监控组件可以满足这个需求,比如说jeager、javamelody、druid等。

总结

一般情况下我们会采用多种方式来记录业务日志,这个都是根据具体需求来进行评估用哪几种方式可以更好的达到产品需求。

最近热文:

1、重磅!《Java开发手册(嵩山版)》最新发布

2、打破你的认知!Java空指针居然还能这样玩

3、吊打 Tomcat ,Undertow 性能很炸!!

4、Spring Boot 太狠了,一次发布 3 个版本!

5、Spring Boot 如何快速集成 Redis?

6、盘点 6 个被淘汰的 Java 技术,曾经风光过!

7、Spring Boot Redis 实现分布式锁,真香!

8、国人开源了一款小而全的 Java 工具类库

9、国人开源了一款超好用的 Redis 客户端!!

10、同事写了个隐藏 bug,我排查了 3 天!

扫码关注Java技术栈公众号阅读更多干货。

点击「阅读原文」获取面试题大全~

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐