24.系统日志查看方法与实战
系统日志查看方法与实战:从本地到分布式的完整指南
面试考点
面试官问"你是怎么查看系统日志的",实际是在考察:
- 是否具备独立分析和定位问题的能力
- 是否熟悉不同环境下的日志查看方式(本地、服务器、容器)
- 能否根据日志快速判断问题根因
- 是否掌握链路追踪和跨系统排查能力
一、面试标准回答(可直接背诵)
回答框架
我在测试过程中非常重视日志分析,因为日志是定位问题最直接的依据。我通常从三个层面查看系统日志:
第一层:客户端日志
对于App或Web测试,我会在复现问题时打开debug模式,查看客户端本地日志。比如:
- Android:使用
adb logcat或Android Studio的Logcat面板- iOS:通过Xcode的控制台或设备日志
- Web:浏览器的Network面板,查看请求状态码、响应数据、Console的JS报错
第二层:服务端日志
这是我最常用的排查方式。项目大多部署在Linux环境,我会通过以下步骤定位:
- 登录服务器:
ssh user@server- 定位日志路径:通常在
/var/log或项目的logs/目录- 常用查看命令:
tail -f app.log:实时跟踪日志输出grep "ERROR" app.log:过滤错误信息grep -C 10 "traceId=xxx" app.log:根据traceId查看上下文less app.log:分页查看大文件第三层:链路日志
在微服务架构下,我会通过 traceId 追踪完整请求链路:
- 从网关日志提取traceId
- 逐个服务查询对应日志
- 定位在哪个环节出现异常
日志等级关注重点:
DEBUG:调试信息(测试环境开启)INFO:常规流程信息WARN:潜在风险,需要关注ERROR:明确异常,影响业务流程核心排查思路总结:
- 明确问题发生的时间点
- 确定请求路径(接口、参数)
- 通过traceId查全链路日志
- 结合错误堆栈判断根因
- 修复后反向验证日志是否正常
能看懂日志并会分析日志,是测试从功能型成长为技术型的分水岭。
二、不同环境的日志查看方法
1. 本地开发环境
IDE控制台
# IDEA查看Spring Boot日志
- 直接看Run窗口输出
- 配置logback.xml调整日志级别#### 本地文件
```bash
# Windows
type C:\app\logs\app.log | findstr ERROR# Linux/Mac
tail -f ~/project/logs/app.log | grep ERROR
2. 测试/生产服务器
登录方式
# SSH登录
ssh username@192.168.1.100# 跳板机登录
ssh -J jumpserver@jump.com username@internal-server
常用日志路径
# 应用日志
/opt/app/logs/app.log
/var/log/tomcat/catalina.out
/home/user/project/logs/# 系统日志
/var/log/syslog # Debian/Ubuntu系统日志
/var/log/messages # CentOS/RHEL系统日志
/var/log/secure # SSH登录日志# Web服务器日志
/var/log/nginx/access.log
/var/log/nginx/error.log
/var/log/apache2/error.log
实时查看命令
# 实时跟踪(最常用)
tail -f app.log# 实时过滤ERROR
tail -f app.log | grep --color=auto ERROR# 实时查看最后500行
tail -n 500 -f app.log# 文件被删除后继续跟踪
tail -F app.log
历史日志查询
# 查看今天的ERROR日志
grep "$(date +%Y-%m-%d)" app.log | grep ERROR# 查看昨天的WARN日志
grep "$(date -d yesterday +%Y-%m-%d)" app.log | grep WARN# 查看特定时间段
sed -n '/2024-01-15 10:00/,/2024-01-15 11:00/p' app.log | grep ERROR# 统计ERROR数量
grep -c "ERROR" app.log# 查看ERROR的上下文(前后各5行)
grep -C 5 "NullPointerException" app.log
跨服务器日志查询
# 在多台服务器上同时查询
for ip in 192.168.1.{10..20}; doecho "=== Server $ip ==="ssh user@$ip "grep 'traceId=abc123' /opt/app/logs/app.log"
done
3. Docker容器日志
查看容器日志
# 查看运行中的容器
docker ps# 实时查看容器日志
docker logs -f <container_id># 查看最后100行
docker logs --tail 100 <container_id># 查看特定时间后的日志
docker logs --since "2024-01-15T10:00:00" <container_id># 过滤ERROR
docker logs <container_id> 2>&1 | grep ERROR
进入容器查看文件日志
# 进入容器
docker exec -it <container_id> /bin/bash# 查看日志
cd /opt/app/logs
tail -f app.log
4. Kubernetes (K8s) 日志
查看Pod日志
# 列出所有Pod
kubectl get pods# 查看Pod日志
kubectl logs <pod_name># 实时跟踪
kubectl logs -f <pod_name># 查看前一个崩溃的容器日志
kubectl logs <pod_name> --previous# 多容器Pod指定容器
kubectl logs <pod_name> -c <container_name># 查看最近1小时的日志
kubectl logs <pod_name> --since=1h
查看多个Pod日志
# 查看Deployment下所有Pod日志
kubectl logs -l app=myapp -f --max-log-requests=10
5. 日志平台(ELK/Grafana Loki)
Elasticsearch (Kibana界面)
1. 打开Kibana:http://kibana.company.com
2. 进入Discover页面
3. 选择索引模式:app-logs-*
4. 时间范围:选择问题发生时间
5. 查询语法:- level: ERROR- traceId: "abc123"- message: *NullPointerException*- host: "192.168.1.100" AND level: ERROR
Grafana Loki (LogQL)
# 查询特定服务的ERROR日志
{app="order-service"} |= "ERROR"# 查询包含traceId的日志
{app="order-service"} |= "traceId=abc123"# 正则表达式匹配
{app="order-service"} |~ "Exception|Error"# 统计错误数量
sum(count_over_time({app="order-service"} |= "ERROR" [5m]))
三、实战案例:STAR法则
案例:支付成功但订单状态未更新
S - Situation(背景)
电商支付项目,用户反馈部分订单支付成功但系统状态显示未支付。
T - Task(目标)
快速定位问题原因,确定是前端展示问题、接口异常,还是后端逻辑/数据库问题。
A - Action(执行步骤)
Step 1:复现问题,抓包验证
# Charles抓包确认支付网关返回
{"code": "SUCCESS","orderId": "202401150001","payTime": "2024-01-15 10:30:25"
}
结论:支付网关返回成功,问题在后端。
Step 2:登录服务器,定位订单服务日志
ssh user@order-server
cd /opt/order-service/logs# 搜索订单号
grep "orderId=202401150001" app.log
发现日志:
2024-01-15 10:30:26 INFO [order-service] traceId=abc123 orderId=202401150001 收到支付回调
2024-01-15 10:30:27 ERROR [order-service] traceId=abc123 更新订单状态失败: update order timeout
结论:订单状态更新超时。
Step 3:通过traceId追踪完整链路
# 在订单服务日志中搜索traceId
grep "traceId=abc123" app.log# 输出:
2024-01-15 10:30:27 INFO 调用库存服务扣减库存
2024-01-15 10:30:57 ERROR 库存服务超时(30s)
结论:问题出在库存服务。
Step 4:定位库存服务日志
ssh user@inventory-server
cd /opt/inventory-service/logsgrep "traceId=abc123" app.log
发现日志:
2024-01-15 10:30:28 INFO 开始扣减库存 sku=A123
2024-01-15 10:30:28 DEBUG 执行SQL: UPDATE inventory SET stock=stock-1 WHERE sku='A123'
2024-01-15 10:30:58 ERROR SQL执行超时: Lock wait timeout exceeded
结论:数据库锁等待超时。
Step 5:查看数据库慢日志
# 连接数据库
mysql -u root -p# 查看慢查询日志
SHOW VARIABLES LIKE 'slow_query_log_file';
# 输出:/var/log/mysql/slow.log# 查看慢查询
exit
sudo tail -n 100 /var/log/mysql/slow.log
发现问题:
# Query_time: 30.5 Lock_time: 30.2
UPDATE inventory SET stock=stock-1 WHERE sku='A123';
结论:sku 字段缺少索引,导致全表扫描和锁等待。
R - Result(结果)
与DBA确认后,为 sku 字段添加索引:
CREATE INDEX idx_sku ON inventory(sku);
效果:
- SQL执行时间从30s降至5ms
- 订单状态更新成功率从85%提升至99.9%
- 支付成功但状态未更新的投诉归零
R - Reflection(复盘)
关键收获:
- 日志不仅是排错工具,更是性能调优和稳定性监控的依据
- 测试在日志分析中要学会"跨层级"定位:
- 客户端日志 → 确认请求发送成功
- 接口日志 → 定位业务逻辑异常
- 服务日志 → 追踪调用链路
- 数据库日志 → 定位SQL性能问题
- traceId是分布式系统排查的核心,必须在所有服务中打印
四、日志分析核心技巧
1. 快速定位关键信息
时间点定位
# 查看10:30-10:35的日志
sed -n '/2024-01-15 10:30/,/2024-01-15 10:35/p' app.log# 查看最近10分钟的ERROR
grep "$(date -d '10 minutes ago' '+%Y-%m-%d %H:%M')" app.log | grep ERROR
traceId追踪
# 提取traceId
traceId=$(grep "orderId=202401150001" app.log | grep -oP 'traceId=\K\w+' | head -1)# 追踪完整链路
grep "traceId=$traceId" /opt/*/logs/app.log
错误堆栈提取
# 提取完整堆栈(从异常开始到下一个日志时间戳)
awk '/NullPointerException/,/^[0-9]{4}-[0-9]{2}-[0-9]{2}/' app.log
2. 统计分析
错误统计
# 统计各类错误数量
grep "ERROR" app.log | awk '{print $NF}' | sort | uniq -c | sort -rn# 输出示例:
# 125 NullPointerException
# 87 TimeoutException
# 42 DatabaseException
接口调用量统计
# 统计今日各接口调用次数
grep "$(date +%Y-%m-%d)" app.log | grep "Request" | awk '{print $5}' | sort | uniq -c | sort -rn# 输出示例:
# 5423 /api/order/create
# 3211 /api/user/login
# 1876 /api/product/list
性能分析
# 提取接口响应时间
grep "cost time" app.log | awk '{print $NF}' | sort -n | tail -20# 计算平均响应时间
grep "cost time" app.log | awk '{sum+=$NF; count++} END {print sum/count}'
3. 多服务器并行查询
Shell脚本批量查询
#!/bin/bash
# search_logs.shSERVERS=("192.168.1.10" "192.168.1.11" "192.168.1.12")
KEYWORD="$1"
LOG_PATH="/opt/app/logs/app.log"for server in "${SERVERS[@]}"; doecho "=== Searching on $server ==="ssh user@$server "grep '$KEYWORD' $LOG_PATH" &
donewait
echo "Search completed."
使用方法:
./search_logs.sh "traceId=abc123"
五、面试追问应对
Q1:你怎么看出哪个日志是关键的?
我会先根据时间点和traceId过滤日志,只看对应请求链路的关键信息。然后重点关注:
- ERROR级别日志:明确的异常信息
- WARN级别日志:可能的性能瓶颈或资源不足
- 业务关键节点日志:如订单创建、支付回调、库存扣减等
- 响应时间异常的日志:超过阈值的慢请求
Q2:线上日志太多怎么快速定位?
我会采用以下策略:
- 使用traceId或requestId检索:在ELK中精确查询
- 时间范围缩小:只查问题发生前后10分钟的日志
- 关键字过滤:按业务单号,操作IP,操作时间,方法签名等精确定位
- 分层定位:先看网关日志确认请求是否到达,再看具体服务日志
- 使用日志平台的聚合功能:如Kibana的Aggregations统计错误分布
Q3:你怎么看ERROR日志和WARN日志的区别?
- ERROR:明确的异常,已经影响业务流程,必须立即处理。例如:数据库连接失败、空指针异常、接口超时。
- WARN:潜在风险,当前不影响业务,但需要关注。例如:缓存未命中、降级策略触发、资源使用率达到80%。
在测试中,我会重点关注ERROR日志,WARN日志则作为性能优化和容量规划的参考。
Q4:如果日志没有打印错误信息怎么办?
这种情况我会:
- 查看DEBUG日志:如果测试环境开启了DEBUG级别
- 查看上下文日志:根据时间点查看前后的业务流程日志
- 交叉验证:查看调用链路中其他服务的日志
- 查看系统日志:
/var/log/syslog或dmesg查看系统级错误(如OOM)- 开启详细日志:临时调高日志级别,复现问题
- 代码Review:检查是否有异常被吞掉(空catch块)
Q5:你怎么看日志分析和测试的关系?
日志分析是测试定位bug的"放大镜",能帮助测试:
- 快速判断问题归属:是前端、后端、数据库还是第三方接口
- 提高缺陷报告质量:附带日志截图和traceId,开发能快速复现
- 发现隐藏问题:通过WARN日志发现性能瓶颈或资源泄漏
- 验证修复效果:修复后通过日志确认异常是否消失
- 积累业务理解:从日志中学习系统架构和业务流程
六、日志最佳实践
1. 日志规范建议
// ❌ 不好的日志
log.info("错误"); // 没有上下文信息// ✅ 好的日志
log.error("订单状态更新失败, orderId={}, userId={}, targetStatus={}, errorMsg={}", orderId, userId, targetStatus, e.getMessage(), e);
2. 必须打印日志的场景
- 接口入口和出口(请求参数、响应结果)
- 外部调用(数据库、Redis、第三方API)
- 业务关键节点(订单创建、支付成功、库存扣减)
- 异常捕获(完整堆栈)
- 性能监控点(响应时间超过阈值)
3. 不应该打印日志的场景
- 敏感信息(密码、身份证号、银行卡号)
- 大对象(完整的请求体、大文件内容)
- 高频循环内(会产生海量日志)
总结
系统日志查看的核心能力:
- 多层次定位:客户端 → 服务端 → 数据库
- 工具熟练度:
grep、tail、awk、sed、ELK、Kibana - 链路追踪思维:通过traceId串联分布式系统
- 统计分析能力:不仅看单条日志,还要做聚合分析
- 问题定位流程:时间点 → 关键字 → 上下文 → 根因
面试金句:
“日志是系统的黑匣子,能看懂日志的测试,才能真正理解系统的运行状态,这是从功能测试成长为技术测试的关键能力。”
