xxl-job日志篇 - 骚操作

·  阅读 8747
xxl-job日志篇 - 骚操作

“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第n篇文章,点击查看活动详情

前言


在上一篇讲了xxl-job二次开发后,我又将目光放到了它的日志实现上,假设让你去设计一个调度系统的日志打印你会怎么设计?

如果是我,我会把上下文一起响应到返回值,然后对响应值进行解码,拿到业务打印的日志,这是常规做法对吧,但是xxl就不是这样做,所以我就蛮好奇它是咋实现的。

让我们进去探个究竟吧~

image.png

xxl-job日志打印方式


在旧版本采用XxlJobLogger.log,新版采用XxlJobHelper.log,然后我们管理后台任务详情就能看到我们打印的日志了

XxlJobHelper

com.xxl.job.core.context.XxlJobHelper#log(java.lang.String, java.lang.Object...)

/**
 * append log with pattern
 *
 * @param appendLogPattern  like "aaa {} bbb {} ccc"
 * @param appendLogArguments    like "111, true"
 */
public static boolean log(String appendLogPattern, Object ... appendLogArguments) {

    FormattingTuple ft = MessageFormatter.arrayFormat(appendLogPattern, appendLogArguments);
    String appendLog = ft.getMessage();

    /*appendLog = appendLogPattern;
    if (appendLogArguments!=null && appendLogArguments.length>0) {
        appendLog = MessageFormat.format(appendLogPattern, appendLogArguments);
    }*/

    StackTraceElement callInfo = new Throwable().getStackTrace()[1];
    return logDetail(callInfo, appendLog);
}
复制代码

FormattingTuple是组装下打印的数据,将{}代替为后面参数,跟log.info一毛一样。

new Throwable().getStackTrace()[1]这个是拿到当前执行方法的堆栈,如果有异常方便打印到具体的方法

com.xxl.job.core.context.XxlJobHelper#logDetail

image.png

好家伙,他往日志里头塞数据,也就是当你任务执行完的时候,XxlJobHelper打印的日志会塞到特定的文件里头,那么他怎么展示出来呢?

寻找xxl-job捞日志的方法


好奇引发我百度了一下,发现它调了/logDetailCat这个方法去消费端取日志,哈哈,常规操作,坐下~

image.png

捞日志具体实现

@RequestMapping("/logDetailCat")
@ResponseBody
public ReturnT<LogResult> logDetailCat(String executorAddress, long triggerTime, long logId, int fromLineNum){
   try {
      ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(executorAddress);
      ReturnT<LogResult> logResult = executorBiz.log(new LogParam(triggerTime, logId, fromLineNum));

      // is end
           if (logResult.getContent()!=null && logResult.getContent().getFromLineNum() > logResult.getContent().getToLineNum()) {
               XxlJobLog jobLog = xxlJobLogDao.load(logId);
               if (jobLog.getHandleCode() > 0) {
                   logResult.getContent().setEnd(true);
               }
           }

      return logResult;
   } catch (Exception e) {
      logger.error(e.getMessage(), e);
      return new ReturnT<LogResult>(ReturnT.FAIL_CODE, e.getMessage());
   }
}
复制代码

com.xxl.job.admin.core.scheduler.XxlJobScheduler#getExecutorBiz

image.png

首先会去拿到当然执行地址的执行器,里头封装了几个方法:心跳、日志、kill任务、执行任务

image.png

我们重点看下拉取日志的实现方法:

com.xxl.job.core.biz.impl.ExecutorBizImpl#log

@Override
public ReturnT<LogResult> log(LogParam logParam) {
    // log filename: logPath/yyyy-MM-dd/9999.log
    String logFileName = XxlJobFileAppender.makeLogFileName(new Date(logParam.getLogDateTim()), logParam.getLogId());

    LogResult logResult = XxlJobFileAppender.readLog(logFileName, logParam.getFromLineNum());
    return new ReturnT<LogResult>(logResult);
}
复制代码

image.png

它会去拿我们刚刚存起来的日志文件,然后读取出数据丢到xxl-job远程接口,然后admin将jobid还有日志记录起来,到此就把定时任务的日志收集起来~

思考环节


不得不说,操作有点骚,虽然可以实现日志的异步收集,也有一些弊端,比如说缓存这些日志是否有必要,让我们一起来思考下:作者这么做目的是什么?

1、长定时任务打印一堆日志?

A:我认为长任务就不应该出现,在我们上篇讲xxl-job的任务调度实现用的是线程池,如果一些占着也浪费资源。解决方案:采用异步任务,机器后台开个线程慢慢跑,这样不会导致调度线程池爆满,也不会说打印很多日志需要采用这种方式来暂存。

那么有人会反驳了,如果任务有问题怎么中断,所以我们需要另外实现任务中断的方法,这也是很多小伙伴会遗忘的地方,导致有问题的时候,只能重启去终止任务的执行

这样也有好处,就是采用log.info,我们本身的日志系统去收集日志,统一在apm上查看,不过这个有个坑是什么呢,就是有些自研的apm在异步的情况会丢失traceid,所以我们需要手动set进去!

image.png

好了,博主准备下班过国庆了~

分类:
后端
标签:
收藏成功!
已添加到「」, 点击更改