当前位置:网站首页>xxl-job中 关于所有日志系统的源码的解读(一行一行源码解读)
xxl-job中 关于所有日志系统的源码的解读(一行一行源码解读)
2022-07-25 22:13:00 【一天不写代码难受】
1 寻找日志相关文件
xxl-job 中,什么地方会使用日志,就是在各个执行过程中,会记录日志,在服务端执行错误会保存日志,还有我们打开页面,查看日志的时候,会调用接口,从后台查看日志信息
- 首先是记录日志的相关代码文件

我们在使用xxl-job记录日志时只需要在任务执行过程中使用XxlJobHelper.log()即可,方法和log4j/slf4j一样简单。
你写代码,想记录日志,那么直接写
XxlJobHelper.log("hello world");
以上这个代码背后就会 先进行日志内容的格式化,也就是将乱七八糟的日志信息格式化的好看一些,或者变成实体类,之后的话,将格式化之后的日志信息 保存为文件
- 客户端 要实时查看日志的接口
我们打开任务调度中心的项目,要实时查看某一个执行任务的日志,点击日志信息,就会调用接口
前端调用这个方法 进行调用查看
logDetailCat()


当执行状态属于未完成的情况下,xxl-job日志控制台会循环调用该接口直至任务完成。
2 保存日志相关代码文件
核心源码里面 ,就涉及到这些文件

我们在自己的项目里面,记录日志,使用的是
XxlJobHelper.log(“hello world”);
所以就从这个方法开始,这个方法所在的文件是

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

首先看对异常进行记录日志的,一般就是在catch里面进行记录日志
/** * 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);
}
之后看 记录普通信息 的日志信息
/** * 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是具体的日志信息
/** * 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);
进行保存
就去了这个文件里面了
/** * 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 += "\r\n";
// 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 服务端实时调用日志信息

/** * 当我们后台打开任务日志时,服务端会到客户端来拉取日志 * @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());
}
}
边栏推荐
- Animation curves are used every day. Can you make one by yourself? After reading this article, you will!
- 在进行自动化测试,遇到验证码的问题,怎么办?
- Redis foundation 2 (notes)
- Why does redisv6.0 introduce multithreading?
- After three years of software testing at Tencent, I was ruthlessly dismissed in July, trying to wake up my brother who was paddling
- win10搭建flutter环境踩坑日记
- Synchronized and volatile
- 什么是类加载?类加载的过程?
- TS:typora代码片段缩进显示异常(已解决)-2022.7.24
- Preliminary study on Tesseract OCR
猜你喜欢

On the difference between break and continue statements

如何实现一个App应用程序,限制用户时间使用?

How to implement an app application to limit users' time use?

Selenium basic use and use selenium to capture the recruitment information of a website (continuously updating)

3. Editors (vim)

别投了,软件测试岗位饱和了...

Nuclear power plants strive to maintain safety in the heat wave sweeping Europe

kubernetes之VictoriaMetrics单节点

MySQL --- 子查询 - 列子查询(多行子查询)

如何将一个域名解析到多个IP地址?
随机推荐
什么是分区分桶?
手机端微信发朋友圈功能测试点总结
[dinner talk] those things that seem to be for the sake of the company but are actually incomprehensible (2: soft quality "eye edge" during interview)
Jmeter--- set proxy recording request
自动化测试岗花20K招人,到最后居然没一个合适的,招两个应届生都比他们强吧
What should I do if I encounter the problem of verification code during automatic testing?
The reisson distributed lock renewal failed due to network reasons, resulting in the automatic release of the lock when the business is still executing but the lock is not renewed.
Mouseevent event -- mouse coordinate description -- Focus event -- input event -- throttle -- mousewheel (wheel event)
Redis foundation 2 (notes)
[test development methodology] experience of test development platform PK - choice
测试工作不受重视,你换位思考了吗?
c sqlite ... ...
Don't vote, software testing posts are saturated
jenkins+SVN配置
什么是类加载?类加载的过程?
The automation testing post spent 20K recruiting, but in the end, there was no suitable one. Both fresh students are better than them
TFrecord写入与读取
Three ways to allocate disk space
Don't know mock test yet? An article to familiarize you with mock
2day