xxl-job中 关于所有日志系统的源码的解读(一行一行源码解读)

2022-08-03 17:33:29 浏览数 (1)

目录

  • 1 寻找日志相关文件
  • 2 保存日志相关代码文件
  • 3 服务端实时调用日志信息

1 寻找日志相关文件

xxl-job 中,什么地方会使用日志,就是在各个执行过程中,会记录日志,在服务端执行错误会保存日志,还有我们打开页面,查看日志的时候,会调用接口,从后台查看日志信息

  • 首先是记录日志的相关代码文件

我们在使用xxl-job记录日志时只需要在任务执行过程中使用XxlJobHelper.log()即可,方法和log4j/slf4j一样简单。

你写代码,想记录日志,那么直接写

代码语言:javascript复制
XxlJobHelper.log("hello world");

以上这个代码背后就会 先进行日志内容的格式化,也就是将乱七八糟的日志信息格式化的好看一些,或者变成实体类,之后的话,将格式化之后的日志信息 保存为文件

  • 客户端 要实时查看日志的接口

我们打开任务调度中心的项目,要实时查看某一个执行任务的日志,点击日志信息,就会调用接口

代码语言:javascript复制
前端调用这个方法  进行调用查看
logDetailCat()

当执行状态属于未完成的情况下,xxl-job日志控制台会循环调用该接口直至任务完成。

2 保存日志相关代码文件

核心源码里面 ,就涉及到这些文件

我们在自己的项目里面,记录日志,使用的是 XxlJobHelper.log(“hello world”);

所以就从这个方法开始,这个方法所在的文件是

进去找到这个方法,有两个同名方法,一个是我们普通的记录日志的,一个是对异常进行记录日志的,就是在catch里面进行记录日志的

首先看对异常进行记录日志的,一般就是在catch里面进行记录日志

代码语言:javascript复制
 /**
     * append exception stack
     * 添加异常堆栈
     * @param e
     */
    public static boolean log(Throwable e) {

        StringWriter stringWriter = new StringWriter();
        e.printStackTrace(new PrintWriter(stringWriter));
//        将异常变成  字符串 
        String appendLog = stringWriter.toString();

//  获取调用这个log方法的  类方法的所有信息
        StackTraceElement callInfo = new Throwable().getStackTrace()[1];

//  最后调用  另一个方法进行保存
        return logDetail(callInfo, appendLog);
    }

之后看 记录普通信息 的日志信息

代码语言:javascript复制
 /**
     * append log with pattern
     * 用模式追加日志
     * @param appendLogPattern  like "aaa {} bbb {} ccc"
     * @param appendLogArguments    like "111, true"    String[] str2={"rrrr","yyyyy"};
     */
    public static boolean log(String appendLogPattern, Object ... appendLogArguments) {
        // 使用slf4j解析器格式化日志内容
        FormattingTuple ft = MessageFormatter.arrayFormat(appendLogPattern, appendLogArguments);
        String appendLog = ft.getMessage();  // aaa rrrr bbb yyyyy ccc

        /*appendLog = appendLogPattern;
        if (appendLogArguments!=null && appendLogArguments.length>0) {
            appendLog = MessageFormat.format(appendLogPattern, appendLogArguments);
        }*/
        // 获得栈帧信息
//        这是获得调用栈帧方法,索引0为当前栈帧,
//        1为调用栈帧,以此类推,此处获得的是索引1,
//        也就是说获得的是调用该方法的栈帧信息,
//        可以通过StackTraceElement获得调用类名,方法名,行数等信息
        StackTraceElement callInfo = new Throwable().getStackTrace()[1];

//        记录 日志
        return logDetail(callInfo, appendLog);
    }

以上的两个log()结尾都调用了 logDetail(callInfo, appendLog) 参数callInfo 是调用方的所有信息,appendLog是具体的日志信息

代码语言:javascript复制
  /**
     * append log
     *  追加 日志
     * @param callInfo  哪个方法调用这个log方法,就把哪个方法的全部的信息 保存到StackTraceElement里
     * @param appendLog  我们要记录的日志
     */
    private static boolean logDetail(StackTraceElement callInfo, String appendLog) {
        // 获得当前上下文对象
        XxlJobContext xxlJobContext = XxlJobContext.getXxlJobContext();
        if (xxlJobContext == null) {
            return false;
        }

        /*// "yyyy-MM-dd HH:mm:ss [ClassName]-[MethodName]-[LineNumber]-[ThreadName] log";
        StackTraceElement[] stackTraceElements = new Throwable().getStackTrace();
        StackTraceElement callInfo = stackTraceElements[1];*/


        // 拼接格式化日志信息
//        就是拼接  哪个方法记录了哪个  日志
        StringBuffer stringBuffer = new StringBuffer();

        stringBuffer.append(DateUtil.formatDateTime(new Date())).append(" ")
                .append("["  callInfo.getClassName()   "#"   callInfo.getMethodName()  "]").append("-")
                .append("["  callInfo.getLineNumber()  "]").append("-")
                .append("["  Thread.currentThread().getName()  "]").append(" ")
                .append(appendLog!=null?appendLog:"");

//       最后的拼接的日志信息  里面包含 哪个方法记录哪个日志
        String formatAppendLog = stringBuffer.toString();

        // appendlog  // 获得日志文件路径
        String logFileName = xxlJobContext.getJobLogFileName();

        if (logFileName!=null && logFileName.trim().length()>0) {

            // 流的形式将日志写入本地文件
//            根据日志文件路径  ,将拼接的东西写进去
            XxlJobFileAppender.appendLog(logFileName, formatAppendLog);
            return true;
        } else {
            logger.info(">>>>>>>>>>> {}", formatAppendLog);
            return false;
        }
    }

以上代码的意思是;对传进来的日志信息做一定的格式化处理之后,调用 XxlJobFileAppender.appendLog(logFileName, formatAppendLog);

进行保存

就去了这个文件里面了

代码语言:javascript复制
	/**
	 * append log
	 * 添加日志内容
	 * @param logFileName  日志路径
	 * @param appendLog  日志内容
	 */
	public static void appendLog(String logFileName, String appendLog) {

		// log file
		if (logFileName==null || logFileName.trim().length()==0) {
			return;
		}
		File logFile = new File(logFileName);

		if (!logFile.exists()) {
			try {
				logFile.createNewFile();
			} catch (IOException e) {
				logger.error(e.getMessage(), e);
				return;
			}
		}

		// log
		if (appendLog == null) {
			appendLog = "";
		}
		appendLog  = "rn";
		
		// append file content
		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream(logFile, true);
			fos.write(appendLog.getBytes("utf-8"));
			fos.flush();
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		} finally {
			if (fos != null) {
				try {
					fos.close();
				} catch (IOException e) {
					logger.error(e.getMessage(), e);
				}
			}
		}
		
	}

以上代码就是 保存到具体的文件里面 了

3 服务端实时调用日志信息

代码语言:javascript复制
/**
 * 当我们后台打开任务日志时,服务端会到客户端来拉取日志
 * @author xuxueli 2015-12-19 16:13:16
 * 服务器  地址
 * 触发时间
 * 任务id
 * 从第几行开始读取
 *
 * 当执行状态属于未完成的情况下,xxl-job日志控制台会循环调用该接口直至任务完成。
 */
	@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()) {
//                根据日志id  从数据库获取日志信息
            	XxlJobLog jobLog = xxlJobLogDao.load(logId);
//            	如果  执行状态  大于0
                if (jobLog.getHandleCode() > 0) {
//                	设置 结果  为 TRUE
                    logResult.getContent().setEnd(true);
                }
            }

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

0 人点赞