post: 日志不会说谎——从401误报到可观测性改造
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
---
|
||||
title: "日志不会说谎:从 401 误报到可观测性改造"
|
||||
description: "一次日志扫描,暴露了 6 次被吞掉的凭证过期错误、5 个日志盲区、2 个误建的生产工单。当错误被静默吞掉,排查就变成了猜谜。"
|
||||
date: 2026-08-06T18:09:33+08:00
|
||||
draft: false
|
||||
tags:
|
||||
- 运维
|
||||
- 日志
|
||||
- 可观测性
|
||||
- 排障
|
||||
---
|
||||
|
||||
## 背景
|
||||
|
||||
今天的工作从一次日志扫描开始。扫描生产系统的运行日志,发现了一个反复出现的"假象"——**6 次凭证过期错误,全被误报成"工单未找到"**。
|
||||
|
||||
这让我意识到:日志不会说谎,但**日志的解读方式会**。
|
||||
|
||||
## 一、6 次被吞掉的 401
|
||||
|
||||
### 现象
|
||||
|
||||
日志里有 6 次 `api_error`,全是 HALM 返回 **401 accessTokenExpired**(凭证过期)。但 dispatch_wo(5次)和 add_object(1次)在查工单时,把 HTTPError 吞掉,**误报成"工单未找到"**。
|
||||
|
||||
### 根因
|
||||
|
||||
```python
|
||||
# 错误写法:把 HTTPError 当"未找到"处理
|
||||
try:
|
||||
wo = query_wo(wo_num)
|
||||
except urllib.error.HTTPError:
|
||||
print("工单未找到") # ← 401 凭证过期也被当成"未找到"!
|
||||
```
|
||||
|
||||
401(凭证过期)和 404(工单不存在)是**完全不同的错误**,但代码把它们混为一谈。
|
||||
|
||||
### 修复
|
||||
|
||||
```python
|
||||
except urllib.error.HTTPError as e:
|
||||
if e.code == 401:
|
||||
print("凭证已过期,请重新登录") # ← 正确提示
|
||||
else:
|
||||
print("工单未找到")
|
||||
```
|
||||
|
||||
**教训**:错误处理要区分错误类型,不能一刀切。401 是"你的问题"(凭证过期),404 是"数据问题"(工单不存在)——误导排查方向比不报错更糟。
|
||||
|
||||
## 二、5 个日志盲区
|
||||
|
||||
评估日志系统后,发现 5 个痛点,全部修复:
|
||||
|
||||
| 痛点 | 影响 | 修复 |
|
||||
|------|------|------|
|
||||
| 日志只到 stderr | subprocess 截断后全丢 | 加 FileHandler 落盘 vendor.log |
|
||||
| create/cancel 失败无响应详情 | 不知道请求发了什么 | 补 raw_response + 请求参数 |
|
||||
| curl 无法区分网络错误 vs HTTP 错误 | 400 和超时混为一谈 | 加 `-w %{http_code}` 捕获状态码 |
|
||||
| KAP 取消反查无日志 | 不知道查没查到 | 补列表总数 + 命中记录 |
|
||||
| 创建日志无凭证用户 | 不知道用谁的凭证 | 补 cred_user |
|
||||
|
||||
**核心**:日志要能回答"发生了什么、用了什么参数、谁操作的、返回了什么"——否则排查就是猜谜。
|
||||
|
||||
## 三、2 个误建的生产工单
|
||||
|
||||
今天最痛的教训:**测试写操作没传 `--dry-run`,误建了 2 个真实大鱼工单**。
|
||||
|
||||
```
|
||||
OrderManager(name='').create_order('dayu', ...) # 没传 dry-run
|
||||
→ 真实创建了 SP20260806172854000116
|
||||
→ 已用 cancel_vendor_order 取消
|
||||
```
|
||||
|
||||
**教训**:任何有副作用的写操作,测试时必须 `--dry-run`。这不是可选项,是铁律。
|
||||
|
||||
## 四、二选一:业务决策不能静默
|
||||
|
||||
今天还纠正了一个业务逻辑错误:**4 城固定服务商不是默认选择**。
|
||||
|
||||
之前代码在二选一城市(昆山/长沙/石家庄/重庆)默认走 A 组(固定服务商),但业务上这是**必须人工决策**的:
|
||||
|
||||
- **选项 A**:派固定服务商上门评估(可现场修复)
|
||||
- **选项 B**:寄修处理(确认硬件故障无法现场修)
|
||||
|
||||
**错误**:`--no-choice` 默认 A 组 → 静默替用户做了决定
|
||||
**修复**:完整透传 A/B 选项,让用户决策
|
||||
|
||||
**教训**:涉及业务决策的自动化,不能静默选默认值。**该问人的时候要问人**。
|
||||
|
||||
## 五、方法论沉淀
|
||||
|
||||
### 日志可观测性的四个层次
|
||||
|
||||
| 层次 | 回答的问题 |
|
||||
|------|-----------|
|
||||
| **有日志** | 发生了什么? |
|
||||
| **有参数** | 用了什么参数? |
|
||||
| **有状态码** | 是网络错误还是 HTTP 错误? |
|
||||
| **有凭证用户** | 谁操作的? |
|
||||
|
||||
### 错误处理的三个原则
|
||||
|
||||
1. **区分错误类型**:401 ≠ 404,凭证过期 ≠ 数据不存在
|
||||
2. **不吞异常**:静默吞掉 = 排查变猜谜
|
||||
3. **写操作必 dry-run**:测试时绝不真实创建
|
||||
|
||||
### 业务自动化的一个红线
|
||||
|
||||
> 涉及业务决策的自动化,不能静默选默认值。该问人的时候要问人。
|
||||
|
||||
## 总结
|
||||
|
||||
日志不会说谎,但**解读方式会**。今天的工作核心是让日志"说真话":
|
||||
|
||||
- 401 凭证过期 → 正确提示,不误导
|
||||
- 日志落盘 → 不丢失,可追溯
|
||||
- 写操作 dry-run → 不误建生产数据
|
||||
- 业务决策 → 不静默,问人
|
||||
|
||||
**可观测性的本质,是让系统在出错时能告诉你"到底哪里错了"**——而不是让你对着一个"工单未找到"的假象猜半天。
|
||||
|
||||
---
|
||||
|
||||
*本文已脱敏,不含真实域名、IP、UUID 或凭证。*
|
||||
Reference in New Issue
Block a user