Oracle数据库的告警日志(alert log)记录了实例启动关闭、内部错误、空间告警、死锁等几乎所有重要事件,是故障诊断的第一手资料。但一台跑了多年的生产库,告警日志动辄几百兆,里面夹杂着大量重复的checkpoint信息和无用的trace提示,靠肉眼逐行翻看几乎不可能。把这些日志里的关键字段提取出来,浓缩成一份可读的巡检报告,才是正确的打开方式。

一、先找到告警日志的位置,搞清楚要提取什么
11g之后,Oracle引入ADR(Automatic Diagnostic Repository)机制,告警日志默认存放在ADR目录下。定位方式有两种,一是查参数:
-- 11g及以后 SELECT value FROM v$diag_info WHERE name = 'Diag Trace'; -- 对应目录下 alert_<SID>.log 即告警日志 -- 10g及以前 SHOW PARAMETER background_dump_dest;
也可以直接用ADRCI命令行工具查看,进入adrci后执行show alert就能看到日志路径,比查参数更直接。
拿到文件之后,关键在于明确要提取哪些关键字。实践中最有价值的通常包括以下几类:ORA-开头的所有内部错误,尤其是ORA-00600、ORA-07445、ORA-01555这类严重错误;Deadlock detected死锁记录;ORA-16014和Archival Error这类归档失败信息;tablespace配合full或unable to extend的空间告警;还有ORA-01631、ORA-01632等对象达到maxextends上限的报错。把这些关键字列清楚,后面的过滤工作就有了明确目标。
二、用Shell脚本结合grep做第一轮粗提取
最简单直接的办法是用grep配合正则表达式过滤。grep的-E参数支持扩展正则,-i忽略大小写,-n输出行号方便回溯上下文。一个典型的过滤命令如下:
#!/bin/bash
LOGFILE=/u01/app/oracle/diag/rdbms/orcl/ORCL/trace/alert_ORCL.log
# 提取ORA错误、死锁、空间告警等关键行,带行号输出
grep -n -E "ORA-|Deadlock|unable to extend|Archival Error|Checkpoint not complete" $LOGFILE \
| grep -v "ORA-12012" \
| sort -t: -k1,1n | uniq > /tmp/alert_summary.txt
wc -l /tmp/alert_summary.txt这段脚本做的事情很朴素:用一条正则把所有关键行连同行号抓出来,再用grep -v剔除已知的噪音(比如ORA-12012作业执行报错往往只是业务层面的干扰),最后去重输出。行号的意义在于,一旦发现某条ORA-00600记录,可以用sed -n '12300,12320p' $LOGFILE直接定位到上下文,查看伴随的trace文件名。
需要注意的是,同一类错误往往成片出现,比如归档目录写满时每三分钟刷一次ORA-16014,一天就能刷出几百条重复记录。这时建议在排序去重的基础上再做一层按错误号聚合,用grep -oE "ORA-[0-9]+" | sort | uniq -c | sort -rn统计每个错误出现的次数,输出的就是一份错误频次排行榜,一眼就能看出数据库当前最突出的问题是什么。
三、用ADRCI做时间维度的精确检索
grep虽然好用,但有个短板:告警日志的时间戳格式不统一,想查某个时间段的信息写正则很费劲。ADRCI天然支持按时间过滤,适合精准定位故障窗口。常用命令如下:
adrci << EOF set homepath diag/rdbms/orcl/ORCL # 查看最近24小时内的严重错误 show alert -p "MESSAGE_TEXT LIKE '%ORA-%' AND ORIGINATING_TIMESTAMP > SYSDATE - 1" # 查看incident列表,每个ORA-00600都会生成incident show incident -p "SEVERITY_ID = 4" show problem EOF
ADRCI的-p参数支持类似SQL的谓词过滤,除了MESSAGE_TEXT还能按SEVERITY_ID(严重级别)、INCIDENT_ID等字段筛选,输出是结构化文本,比裸grep更适合做程序化处理。show problem命令尤其值得一提,它会把零散的incident自动归并成problem组,同一个ORA-00600内部错误即使发生一百次,也只显示一行问题记录加发生次数,省去了大量人工归类的工作。
把ADRCI的输出落盘后,同样可以交给Shell做二次加工。很多DBA的巡检平台就是这样搭的:定时任务调用adrci拉取当天数据,管道传给awk提取字段,最终生成HTML邮件报表。相比直接读原始日志,这种方案的报告体量能缩小两个数量级。
四、进阶方案:外部表把日志当表查
如果团队更熟悉SQL,还可以把告警日志定义成Oracle外部表,直接用SQL做过滤和聚合。定义方式依赖ORACLE_LOADER访问驱动:
CREATE DIRECTORY alert_dir AS '/u01/app/oracle/diag/rdbms/orcl/ORCL/trace';
CREATE TABLE alert_log_ext (line VARCHAR2(400))
ORGANIZATION EXTERNAL (
TYPE ORACLE_LOADER
DEFAULT DIRECTORY alert_dir
ACCESS PARAMETERS (
RECORDS DELIMITED BY NEWLINE
FIELDS TERMINATED BY WHITESPACE OPTIONAL ENCLOSED BY '<'
(line CHAR(400)))
LOCATION ('alert_ORCL.log')
)
REJECT LIMIT UNLIMITED;
-- 统计各类ORA错误的分布
SELECT regexp_substr(line, 'ORA-[0-9]+') err_code, COUNT(*) cnt
FROM alert_log_ext
WHERE line LIKE '%ORA-%'
GROUP BY regexp_substr(line, 'ORA-[0-9]+')
ORDER BY cnt DESC;外部表方案最大的好处是复用SQL生态,配合regexp_substr可以灵活切分错误码、时间戳、trace文件路径等字段,还能和现有监控表做join。缺点也有:每次全量扫描大文件性能不佳,适合每天一次的批量分析,不适合实时监控;另外日志文件轮转后需要更新LOCATION指向,管理上多了一步。
五、落地建议:组合成一套定时巡检流程
综合前面几种手段,一个务实的落地姿势是分层处理:日常巡检用ADRCI按时间窗提取,遇到需要深挖的场景再回退到grep和sed查原始日志,周期性的趋势分析交给外部表跑SQL。巡检脚本本身要注意两点,一是日志路径要动态获取而不是写死,不同环境ADR路径差异很大;二是报告里除了错误码本身,务必带上错误出现的首末时间,这对判断问题是持续恶化还是偶发至关重要。
另外别忘了告警日志里的时间戳是数据库服务器本地时间,如果应用报错时间和日志时间对不上,先检查服务器时区再怀疑代码。把这套关键字提取流程固化下来,数据库出了问题时,你拿到的将不再是几百万行的原始文本,而是一份几十行的重点摘要,排障效率会完全不同。
Oracle告警日志日志分析ORA错误修改时间:2026-09-09 06:34:37