元数据卡
- 前置知识:第6章·读懂栈调用、第6章·日志基础、第6章·最小复现
- 预计时间:20 分钟
- 完成标志:完成热身和排障练习
写在前面
理论学完了。但你不会因为"看过"就掌握 Debug——它跟编程一样,是练出来的。下面几个练习,按难度排列。
热身(5 分钟,必做)
故意写一段会报错的代码,观察栈调用的每一行。
java
// 文件: CrashMe.java
// 运行: javac CrashMe.java && java CrashMe
public class CrashMe {
public static void main(String[] args) {
int[] arr = new int[3];
System.out.println(arr[5]); // 数组越界
}
}运行后你会看到类似这样的输出:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException:
Index 5 out of bounds for length 3
at CrashMe.main(CrashMe.java:4)练习步骤:
- 把索引改成
arr[10]再跑,观察行号变化 - 把错误换成
null对象调用(String s = null; s.length();) - 换成 Python 跑一遍同样的场景,对比两种格式
关键观察:行号永远指向出问题的代码行——你改了哪一行,报错就指向哪一行。
挑战(15 分钟,选做)
在一个已有项目里加上日志库,然后故意制造错误,从日志中找到它。
步骤:
- 随便找一个你之前写的项目
- 给启动入口、关键函数入口、异常 catch 三处加日志
- 故意制造一个 bug(比如把配置文件名改错、把数据库密码改错)
- 运行,看日志文件里有没有记录这个错误
- 用
grep ERROR app.log过滤出你的错误
排障案例 1:NoClassDefFoundError
你启动一个 Java 服务,报错:
Exception in thread "main" java.lang.NoClassDefFoundError:
com/fasterxml/jackson/core/JsonFactory你明明在 pom.xml 里写了 Jackson 依赖,为什么还会找不到?
思路排查:
| 排查点 | 方法 |
|---|---|
| 依赖类型 | 是不是用了 <scope>provided</scope>? |
| 构建方式 | mvn compile 不会打包依赖,要用 mvn package |
| 依赖树 | mvn dependency:tree 查看 Jackson-core 是否传递进来了 |
| 打包方式 | 是不是打了 fat jar(shade/assembly)? |
你用的是 mvn compile 然后直接跑?还是 mvn package 后跑 fat jar?前者不会把 Jackson 的 jar 拷过来。
排障案例 2:日志路径找不到
你部署了应用,用户说报错了。你登上去看日志——没有日志文件。
查了半天发现:日志配置写的 ./logs/app.log 在 Docker 里写到了 /app/current/logs/app.log,而你一直在看 /var/log/app.log。
bash
# 先确认程序在哪个目录运行
ps aux | grep myapp
# 在对应目录下找日志
cd /usr/local/myapp/
find . -name "*.log" -type f
# 如果日志太大,不要用 cat
tail -n 50 app.log # 最后 50 行
less app.log # 分页浏览两个经典错误类型
NullPointerException/NoneType has no ...——几乎所有语言的 #1 错误:你用它的时候它不存在ClassNotFoundException/ModuleNotFoundError——import 了一个东西,运行时找不到(依赖没装对)
旅人笔记
程序总会出错——但你会读栈调用、会搜错误信息、会加日志、会写最小复现。这些技能比任何一门编程语言都持久。每次 Debug 都是一次"缩小嫌疑范围"的过程。它不是天赋,是一套可以练习、优化的方法。
验收标准
本章完成后,你应该能:
- 读懂任意语言的栈调用,找到 bug 位置和类型
- 用关键词 + 错误信息进行有效搜索
- 至少一种语言正确配置并写入日志文件
- 用
grep、tail、less查看和过滤日志 - 写出最小复现隔离和报告 bug
- 理解为什么不能用
System.out替代日志
→ 下一站预告
日志和报错你学会读了。但有些时候,程序不在你的机器上跑——它在 Docker 容器里。你需要一个方法,把你的项目打包起来到任何机器上都能跑。
→ 第7章:Docker(即将到来)