Reading guide
XXL job not only has its own rpc, registration center, but also its own log system. Although a sparrow is small, it has all kinds of internal organs.
This chapter will analyze the logging system of XXL job from the source code level. When using XXL job to record logs, we only need to use xxljobhelper during task execution Log (), which is as simple as log4j/slf4j. We can see the real-time log of the task running through the console.
XxlJobHelper.log("hello world");
This is too advanced. The log can be accurate to the task level, and it can also be viewed in real time on the console. There are scheduling methods and class information. So how does it achieve? Next, I will take you to analyze the implementation of XXL job.
Source code analysis
This time, let's directly push the log system logic forward and locate the log method
com.xxl.job.core.context.XxlJobHelper#log(java.lang.String, java.lang.Object...)
public static boolean log(String appendLogPattern, Object ... appendLogArguments) { // Use slf4j parser to format log content FormattingTuple ft = MessageFormatter.arrayFormat(appendLogPattern, appendLogArguments); String appendLog = ft.getMessage(); // Get stack frame information StackTraceElement callInfo = new Throwable().getStackTrace()[1]; return logDetail(callInfo, appendLog); }
Note that stacktraceelement callinfo = new throwable() getStackTrace()[1];
This is to obtain the calling stack frame method. Index 0 is the current stack frame, 1 is the calling stack frame, and so on. Index 1 is obtained here, that is, the stack frame information of calling the method is obtained. The calling class name, method name, line number and other information can be obtained through StackTraceElement
Continue to com Xxl job. core. context. XxlJobHelper#logDetail
private static boolean logDetail(StackTraceElement callInfo, String appendLog) { // Gets the current context object XxlJobContext xxlJobContext = XxlJobContext.getXxlJobContext(); if (xxlJobContext == null) { return false; } // Splice format log information 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(); // Get log file path String logFileName = xxlJobContext.getJobLogFileName(); if (logFileName!=null && logFileName.trim().length()>0) { // The log is written to the local file in the form of stream XxlJobFileAppender.appendLog(logFileName, formatAppendLog); return true; } else { logger.info(">>>>>>>>>>> {}", formatAppendLog); return false; } }
Here is a key piece of code
XxlJobContext xxlJobContext = XxlJobContext.getXxlJobContext();
This is the context object of the current task, which will be initialized when it is scheduled, as I mentioned earlier[ [XXL job source code 01] XXL job source code interpretation magical time wheel trigger process interpretation ]Yes, it's not here
We can see that XXL job writes logs to local files and does not push them to the server. Here, the log is not in the push mode, but in the pull mode. When we open the task log in the background, the server will pull the log from the client.
Navigate to interface com Xxl job. admin. controller. JobLogController#logDetailCat
@RequestMapping("/logDetailCat") @ResponseBody public ReturnT<LogResult> logDetailCat(String executorAddress, long triggerTime, long logId, int fromLineNum){ try { // Get the remote instance of the executor ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(executorAddress); // Call the client netty http interface to pull logs ReturnT<LogResult> logResult = executorBiz.log(new LogParam(triggerTime, logId, fromLineNum)); // Judge whether the log ends 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()); } }
When the execution status is incomplete, the XXL job log console will call the interface repeatedly until the task is completed.
Next, let's take a look at the code related to the log file read by the client. Com Xxl job. core. biz. impl. ExecutorBizImpl#log
@Override public ReturnT<LogResult> log(LogParam logParam) { // log filename: logPath/yyyy-MM-dd/9999.log // Get log file name String logFileName = XxlJobFileAppender.makeLogFileName(new Date(logParam.getLogDateTim()), logParam.getLogId()); // Read stream information LogResult logResult = XxlJobFileAppender.readLog(logFileName, logParam.getFromLineNum()); return new ReturnT<LogResult>(logResult); }
com.xxl.job.core.log.XxlJobFileAppender#readLog
public static LogResult readLog(String logFileName, int fromLineNum){ if (logFileName==null || logFileName.trim().length()==0) { return new LogResult(fromLineNum, 0, "readLog fail, logFile not found", true); } File logFile = new File(logFileName); if (!logFile.exists()) { return new LogResult(fromLineNum, 0, "readLog fail, logFile not exists", true); } // read file StringBuffer logContentBuffer = new StringBuffer(); int toLineNum = 0; LineNumberReader reader = null; try { reader = new LineNumberReader(new InputStreamReader(new FileInputStream(logFile), "utf-8")); String line = null; while ((line = reader.readLine())!=null) { toLineNum = reader.getLineNumber(); // [from, to], start as 1 if (toLineNum >= fromLineNum) { logContentBuffer.append(line).append("\n"); } } } catch (IOException e) { logger.error(e.getMessage(), e); } finally { if (reader != null) { try { reader.close(); } catch (IOException e) { logger.error(e.getMessage(), e); } } } LogResult logResult = new LogResult(fromLineNum, toLineNum, logContentBuffer.toString(), false); return logResult; }
The XXL job client will save the log file to the disk. When the log console is opened, the server will request the client circularly. The client will read the log with the specified number of lines in the form of io stream and return it to the server
link
[XXL job source code 02] the application of RPC netty developed by the registry?