服务器日志里藏着一个被改过的日志数字。上周排查一个订单金额异常时,修改信息我翻到某条记录:用户ID 8837,日志原本支付金额是修改信息 299,结果变成了 199。日志日志只留了一行“update order set amount=199 where id=5521”,修改信息没有操作人,日志没有时间戳之外的修改信息任何线索。这就是日志日志的脾气——它不撒谎,但也不主动告诉你谁在撒谎。修改信息
很多人以为查日志就是日志 grep 一下错误码。真干起来你会发现,修改信息修改信息的日志痕迹往往不在 error 级别里。它们混在 info 甚至 debug 里,修改信息像沙滩上的日志脚印,潮水一冲就没了。我见过一个运维把日志级别调到 warn,结果所有 SQL 变更记录全被过滤掉,后来数据对不上,他花了三天才反应过来是自己把证据关了。
具体到“修改信息”这件事,日志能告诉你的分两种。一种是数据库层的 binlog 或 general log,它记的是原始 SQL。另一种是应用层的业务日志,比如“用户 8837 将收货地址从 A 改为 B”。前者精确但难读,后者可读但可能被代码漏掉。我习惯两边对照着看。有一次应用日志显示“修改成功”,binlog 里却根本没有 update 语句——后来发现是缓存更新了,数据库没动。这种坑,光看一边永远踩不明白。
那怎么从日志里捞出真正的修改记录?我的做法是先锁定时间窗口。别一上来就翻全量,几千万行能把你眼睛看瞎。比如用户投诉“昨天下午价格变了”,那就把范围缩到那两小时。然后别只搜 update,搜 set、alter、modify、change,甚至搜等号。有些框架打印 SQL 时会把 update 写成大写,或者用反引号包字段名,正则写死了就漏。
还有一个细节:日志里的“修改”经常不是单独出现的。它前后会有 select 做铺垫。比如先查一下原值,再 update 新值。你看到一条 select 紧跟着一条 update,基本就能还原出操作路径。我抓过一次内部刷单,就是靠这个顺序:先 select 出订单状态,再 update 成已支付,中间隔了 0.3 秒。正常用户不可能这么快。
当然,日志本身也会被改。有些老系统日志文件权限是 777,谁都能写。我就遇到过运维为了掩盖误操作,手动编辑了日志文件,把那条 delete 删了。结果文件大小对不上,inode 变更时间也露馅。所以查日志修改信息,还得看一眼日志文件自己的元数据。ls -l 看修改时间,stat 看变更时间,对不上就有鬼。
最后说一个反直觉的:不是所有修改都值得追。有些字段天天变,比如 last_login_time,你追它纯属浪费生命。真正要盯的是金额、状态、权限、归属人这类。我一般会在日志系统里给这些字段加单独标签,改一次就告警一次。别等出事了再翻,那时候日志可能已经轮转删掉了。
日志不会主动喊“有人改数据了”。它只是安静地记着,等你来问。问得够细,它什么都招。