跳到主要内容

Linux/Java 生产排查台账:定时任务没执行,连日志在哪都不知道,怎么查?

01 前置理论与核心排查思路​

1. “定时任务没执行”,先查哪一步?​

业务反馈“文件没上传”,先确定任务卡在什么环节。

调度触发 → 读取配置 → 判断执行条件 → 处理文件 → 上传到目标端 → 返回结果

通常分为四种情况:

  1. 没有触发: 到了执行时间,调度器没有启动任务。
  2. 触发后跳过: 任务已启动,但开关关闭或执行条件不满足。
  3. 执行中失败: 任务开始处理,随后出现权限、网络、认证或程序异常。
  4. 执行成功但业务未收到: 继续检查目标路径、上传回执和下游处理状态。

排查重点:找到任务实际执行到哪一步。

2. 刚接手服务器,怎么找日志?​

先找到业务进程,再根据运行方式定位日志。

运行方式日志定位方法
nohup java -jar ... >> nohup.out 2>&1 &查看 /proc/PID/fd/1 和 /proc/PID/fd/2
Logback / Log4j2 写文件查看进程打开的日志文件、日志框架配置
systemd 启动 Java 服务journalctl -u 服务名,以及服务配置中的日志路径
Docker / Kubernetesdocker logs / kubectl logs,或应用自己的文件日志
cron / systemd timer 启动脚本先查调度记录,再定位脚本或业务程序输出

Java 服务如果使用标准输出,优先查 /proc/PID/fd/1;如果使用独立日志文件,再查进程打开的文件和日志配置。

3. 通用排查路线​

找到业务进程 → 定位日志 → 搜索故障时间 → 查看上下文 → 判断故障环节 → 反馈处理人。

先用只读命令完成定位。确认原因后,再按实际权限处理配置或业务恢复。


02 故障排查与验证 SOP​

步骤一:确认业务进程​

查找当前运行的 Java 服务:

ps -ef | grep '[j]ava'

从输出中找到对应应用,记下 PID、JAR 名称和运行用户。

如果 Java 进程较多,查看目标进程的完整启动信息:

ps -p 12345 -o pid,user,etime,args

12345 替换为现场 PID。再根据应用名、启动参数或业务端口核对进程归属。

如果应用进程已经退出,转查启动脚本、服务管理记录和历史日志;如果任务由 cron、systemd timer 或独立调度平台执行,则直接查对应调度记录。

步骤二:从进程定位日志​

查看标准输出和标准错误:

ls -l /proc/12345/fd/1 /proc/12345/fd/2

假设返回:

/proc/12345/fd/1 -> /var/log/file-sync-service/nohup.out
/proc/12345/fd/2 -> /var/log/file-sync-service/nohup.out

说明进程的标准输出、标准错误都写入 nohup.out。

如果应用使用独立日志文件,查看进程当前打开的日志:

lsof -p 12345 | grep -E '\.(log|out)([[:space:]]|$)'

根据实际情况继续查看 Logback、Log4j2 配置或 systemd、容器日志。

步骤三:根据故障时间定位日志​

先确认业务反馈的日期和时间,再按日志实际时间格式检索。

例如任务计划在 2026 年 10 月 10 日凌晨 0 点执行:

grep -n -m 1 '2026-10-10 at 00:00' /path/to/app.log
  • -n:显示日志行号。
  • -m 1:找到第一条匹配记录后停止。
  • /path/to/app.log:换成第二步找到的日志路径。

假设返回第 130010 行,就从这里查看后续记录。

如果同一时刻有多个任务,可以加任务名、任务编号或请求 ID 缩小范围;故障时间不精确时,先按日期搜索:

grep -n '2026-10-10' /path/to/app.log | head -n 20

如果当天日志已经轮转,继续检查相应的历史日志文件:

zgrep -n '2026-10-10' /path/to/app.log.1.gz | head

步骤四:查看故障前后日志​

从第 130010 行向后查看 10 行:

sed -n '130010,+10p' /path/to/app.log

这里会显示起始行和后续 10 行,共 11 行。根据现场情况调整起始行和行数。

已经知道具体异常关键字时,也可以直接查看其前后 10 行:

grep -n -C 10 '任务标识或报错关键字' /path/to/app.log

重点看四类记录:任务触发、读取配置、执行动作、最终结果。

步骤五:判断问题出在哪一环​

日志表现判断方向下一步检查
到点没有任务触发记录调度入口时区、任务配置、调度状态、日志轮转、执行节点
有触发记录,随后出现 enabled=false / skip执行条件配置来源、任务开关、缓存、配置变更记录
出现 Permission denied文件权限运行用户、文件属主、目录权限、读写路径
出现 timeout / Connection refused网络或目标服务目标地址、端口、网络连通性、服务状态
出现认证失败身份认证账号权限、密钥或令牌状态、目标端授权
上传接口返回成功,但业务未收到上传结果与下游处理目标路径、文件名、回执、下游消费记录

如果完全没有任务触发日志,继续检查调度方式:

系统 cron:

crontab -l

查看指定运行用户的 cron 任务:

sudo crontab -u appuser -l

系统级任务还可以检查 /etc/crontab 和 /etc/cron.d/。

systemd timer:

systemctl list-timers --all

找到 timer 后查看其配置及对应 service 的执行记录。

Java 内部调度: 检查 Spring @Scheduled、Quartz、XXL-JOB 等实际使用的任务配置、执行日志和调度平台记录。

步骤六:整理证据并交接​

把排查结果整理成四项:

  1. 故障时间和任务名称: 什么时候、哪个任务出现异常。
  2. 实际执行情况: 未触发、触发后跳过,还是执行过程中失败。
  3. 关键日志: 保留触发、配置、异常和结果对应的日志片段。
  4. 后续负责人: 明确由研发、业务或配置负责人继续核查什么。

例如:

10 月 10 日 00:00,文件上传任务正常触发;应用读取到 enabled=false 后跳过上传。已附关键日志,请研发确认任务配置来源及变更情况,业务侧确认是否需要补传。

排查定位到这里即可交接。配置修复、补传和业务验证按实际职责继续处理。


03 典型生产场景分析​

案例一:任务在 0 点触发,却没有上传文件​

现象

业务反馈:每月 10 日凌晨 0 点自动上传文件,本月没有上传。刚接手服务器,不清楚程序和日志的位置。

排查

先找到 Java 进程和日志文件:

ps -ef | grep '[j]ava'
ls -l /proc/70030/fd/1

进程的标准输出指向 /var/log/file-sync-service/nohup.out。

根据故障时间找行号:

grep -n -m 1 '2026-10-10 at 00:00' /var/log/file-sync-service/nohup.out

第一条匹配出现在第 130010 行。查看后续日志:

sed -n '130010,+10p' /var/log/file-sync-service/nohup.out

关键日志如下(节选):

2026-10-10 at 00:00:00.000 INFO - 定时文件上传任务触发, taskCode=MONTHLY_FILE_UPLOAD
2026-10-10 at 00:00:00.002 DEBUG - ==> Preparing: SELECT task_code, enabled FROM scheduled_job_config WHERE task_code = ?
2026-10-10 at 00:00:00.004 DEBUG - ==> Parameters: MONTHLY_FILE_UPLOAD(String)
2026-10-10 at 00:00:00.007 DEBUG - <== Row: MONTHLY_FILE_UPLOAD, false
2026-10-10 at 00:00:00.008 DEBUG - <== Total: 1
2026-10-10 at 00:00:00.010 INFO - 任务配置加载完成, enabled=false
2026-10-10 at 00:00:00.012 ERROR - 定时任务未开启,跳过文件上传

结论与交接

任务正常触发,程序读取到 enabled=false,因此跳过文件上传。把查询结果和跳过执行的日志反馈给研发,核查开关来源及变更记录。

本案例根据真实故障经历在测试环境复现;PID、路径和行号仅对应本案例,实际操作以现场结果为准。

案例二:到点没有任务日志,但服务进程仍在​

现象

Java 服务持续运行,其他业务日志正常,预定时间却没有目标任务的记录。

排查方向

  1. 查看同一时间段是否有日志轮转或归档。
  2. 核对服务器时区、应用时区和任务执行时间。
  3. 根据调度方式检查 Cron 表达式、任务开关、调度器日志。
  4. 如果任务由多节点调度,检查实际执行节点的日志。

处理方向

确认任务有没有进入调度器,以及实际执行节点在哪里。找到任务触发记录后,继续查执行链路;确认调度未触发时,交由对应调度负责人排查。

案例三:任务按时触发,但上传过程中失败​

现象

日志出现 task started,随后报上传超时、认证失败或 Permission denied,没有成功回执。

排查方向

  • 本地文件: 确认源文件、运行用户、目录读写权限。
  • 网络连接: 核对目标 IP、端口、目标服务状态及超时记录。
  • 远端认证: 查账号权限、密钥或令牌是否有效。
  • 远端处理: 查目标路径、文件上传回执及下游处理结果。

处理方向

按实际报错确定异常发生的位置,保留对应日志和请求信息,交给负责该环节的人员处理。


04 生产排障命令速查表​

命令里的 PID、时间、日志路径使用现场实际值。

排查目标命令查看结果
找 Java 进程ps -ef | grep '[j]ava'进程号、JAR 名、运行用户
查看启动参数ps -p 12345 -o pid,user,etime,args业务进程的完整启动信息
找标准输出日志ls -l /proc/12345/fd/1标准输出指向的文件或管道
找标准错误日志ls -l /proc/12345/fd/2标准错误指向的位置
查看进程工作目录readlink -f /proc/12345/cwd程序当前工作目录
查看进程打开的日志lsof -p 12345 | grep -E '\.(log|out)'独立日志文件路径
看最新日志tail -n 10 /path/to/app.log最近 10 行
根据时间查行号grep -n -m 1 '2026-10-10' /path/to/app.log第一条匹配的行号
按行号看上下文sed -n '130010,+10p' /path/to/app.log指定行及后续 10 行
按报错看前后文grep -n -C 10 'ERROR' /path/to/app.log报错前后各 10 行
查压缩历史日志zgrep -n '2026-10-10' /path/to/app.log.1.gz已归档日志的匹配记录
查 systemd 服务日志journalctl -u 服务名 --since '2026-10-10 00:00:00'指定时间之后的服务日志
查当前用户 croncrontab -l当前用户的定时配置
查指定用户 cronsudo crontab -u appuser -l目标运行用户的定时配置
查 systemd 定时任务systemctl list-timers --alltimer 及触发时间

最短排查路径:ps 找进程 → /proc/PID/fd 找日志 → grep -n 找时间 → sed -n 看上下文。


05 面试应答参考话术​

问题:刚接手一台陌生 Linux 服务器,业务反馈 Java 定时任务没执行,你怎么排查?

我先确认任务所属应用和计划执行时间,再用 ps -ef | grep '[j]ava' 找到 Java 进程和 PID。

根据 PID 查看 /proc/PID/fd/1、fd/2,定位控制台日志。如果应用使用 Logback、Log4j2 单独写文件,就查进程打开的日志和配置。

找到日志后,用 grep -n 按故障时间定位行号,再用 sed 查看前后内容,判断任务是没触发、触发后被跳过,还是执行过程中失败。


06 面试高频追问与应答预案​

Q1:为什么先查进程,不直接用 find 搜日志?​

从进程能直接确认服务是否运行、进程号和启动方式,再顺着输出位置找日志。路径明确后再检索文件,效率更高。

Q2:/proc/PID/fd/1 和 fd/2 有什么区别?​

fd/1 是标准输出,fd/2 是标准错误。查看它们指向的路径,就能知道控制台信息写到了哪里。

Q3:Java 使用 Logback、Log4j2 写文件日志,怎么找?​

先执行 lsof -p PID 查看已打开的日志文件,再查 logback.xml、log4j2.xml 等配置中的文件路径。

Q4:为什么用 grep '[j]ava'?​

匹配 Java 进程,同时避免把 grep 自己的进程匹配出来,输出更干净。

Q5:grep -n -m 1 是干什么的?​

-n 显示行号,-m 1 找到第一条就停止。获取行号后,再结合任务名或任务标识核对日志。

Q6:sed -n '130010,+10p' 会修改日志吗?​

不会。它只输出第 130010 行及后续 10 行,共 11 行。读取日志时使用 -n 和 p 即可。

Q7:找到 ERROR 后怎么分析?​

查看报错前后的任务触发、配置查询、执行动作和返回结果。如果有异常堆栈,再沿调用过程定位具体失败环节。

Q8:日志显示 enabled=false,下一步怎么做?​

先核对配置来源、开关变更记录和启用条件,把证据交给配置负责人。确认业务影响和重跑风险后,再安排修复或补传。

Q9:故障时间搜不到日志,接着查什么?​

依次检查时区、日志格式、轮转文件、调度日志和实际执行节点;找到完整日志源后继续检索。

Q10:Java 进程已经退出,怎么找日志?​

通过 systemd 服务定义、启动脚本、应用日志配置或容器记录定位日志文件,再查服务退出时间和错误信息。

Q11:任务显示成功,业务却没收到文件,怎么排查?​

核对实际上传文件名、大小、目标路径、校验值和服务端回执,再确认下游是否已经处理完成。

Q12:运维查出原因后,怎么交接?​

说明故障时间、任务名称、实际执行情况和关键日志,明确接手人员及下一步操作。后续由对应负责人完成修复、补传和业务验证。


07 通用日志定位辅助脚本(只读)​

适合日志文件已经找到、需要反复按时间查找的情况。输入日志路径、时间关键字、向后查看的行数,自动输出匹配行号和上下文。

保存为 trace_job_log.sh:

#!/usr/bin/env bash
# 用法:bash trace_job_log.sh /path/to/app.log '2026-10-10 at 00:00' [向后行数]
set -euo pipefail

if (( $# < 2 || $# > 3 )); then
echo "用法: bash $0 日志文件 时间或关键字 [向后行数]" >&2
exit 2
fi

log_file=$1
keyword=$2
after=${3:-10}

if [[ ! -f "$log_file" || ! -r "$log_file" ]]; then
echo "日志不存在或没有读取权限: $log_file" >&2
exit 1
fi

if [[ ! "$after" =~ ^[0-9]+$ ]] || (( ${#after} > 3 )) || (( 10#$after > 100 )); then
echo '向后行数必须是 0 到 100 的整数' >&2
exit 2
fi

match=$(grep -n -m 1 -F -- "$keyword" "$log_file") || {
echo "没有匹配到: $keyword" >&2
exit 1
}

line=${match%%:*}
printf '文件: %s\n匹配行: %s\n' "$log_file" "$line"
sed -n "${line},+${after}p" "$log_file"

使用示例:

bash trace_job_log.sh /var/log/myapp/app.log '2026-10-10 at 00:00' 10

运行后会显示匹配行号,以及该行往后的 10 行日志。时间格式和日志路径按现场修改。


08 现场注意事项与复现资料说明​

  • 先定位: 优先查进程、日志和调度记录,确定异常环节后再执行变更。
  • 核对时间: 留意服务器时区、应用日志时间和日志轮转情况。
  • 保留证据: 交接时提供时间、任务标识、关键日志和初步判断。
  • 注意脱敏: 对外分享日志前处理账号、令牌、地址和业务敏感信息。
  • 恢复确认: 开关调整、重跑、补传由对应负责人确认,最后验证业务结果。

配套故障复现素材包作为独立下载附件,供测试环境练习使用;本文以生产排查方法为主。

完整内容已隐藏

请联系作者或在线获取阅读密码。