Linux如何用脚本监控Oracle发送警告日志ORA-报错发送邮件
Linux如何用脚本监控Oracle发送警告日志ORA-报错发送邮件
前言
公司有购买的监控软件北塔系统监控,由于购买的版权中只包含了有限台数据库服务器的监控,所以只监控了比较重要的几台服务器。
后边出现过没有监控的数据库服务器表空间爆满导致生产业务出现问题,后续手工处理数据也麻烦。
因此领导让我想办法能用什么方法监控上目前没有监控的数据库。
当然,我想到的只有三种,
- OEM 13C,Oracle本家的产品,好处多多;
- 自己写脚本监控,比较锻炼人和实惠,功能比较单一;
- 第三方的监控软件,鉴于北塔在数据库方面的监控效果,本人不是看好第三方的
捣鼓了几天OEM 13C,最后公司暂时没有资源装新的OEM服务器,遂放弃。
自己写脚本吧。。
思路
我的思路是:
- (步骤1)每次检查的时候,截取警告日志中需要检查的内容到另外的日志文件中(比如new_alert.log);
- (步骤2)过滤该日志文件(new_alert.log)中存在的ORA报错信息,存放至另外的日志文件中(比如err_alert.log);
- (步骤3)将日志(err_alert.log)的报错内容发送至指定的邮箱中,达到报警的目的。
下边一步一步来写脚本解决吧。
步骤1
首先我用的shell,脚本的例行开头为:
#!/bin/bash
source /home/oracle/.bash_profile
然后需要考虑几个问题,
- 怎么知道警告日志的路径和警告日志名字,其实你可以固定在一个变量中。
但是由于服务器不止一台,又想直接拷贝到其他服务器用的时候尽量少的改到脚本,因此我的想法是动态获取路径。
警告日志名字的话当时就是alert_$ORACLE_SID.log了。
因此我是这么做的,查找警告日志路径然后赋值给变量dir:# 查找alert日志所在的路径
sqlplus -s /nolog &> /dev/null << EOF
set feedback off heading off verify off trimspool on timing off
set pagesize linesize
conn / as sysdba;
set timing off
set time off
spool /tmp/tmpdir.txt
select value from v\$parameter where name='background_dump_dest';
spool off
exit;
EOF #是否成功获取到路径
errs=`grep 'ERROR' /tmp/tmpdir.txt | wc -l`
if [ $errs -gt ]; then
echo "query alert log direction run error, please check the /tmp/tmpdir.txt for details."
exit
else
dir=`cat /tmp/tmpdir.txt`
fi 日志找到了,检查内容的起点和终点如何确定?
终点好确定,就是警告日志的最后一行,那起点呢?
当然是上一次检查的终点那一行+1。
因此,我需要用多一个文件保存上次的终点行数,该文件用/tmp/rownum.log保存。
首先判断是否存在文件/tmp/rownum.log,不存在则表示第一次运行警告日志检查,因此肯定是从第一行开始到最后一行结束全部都检查一遍。##如果文件不存在,则创建,并且将数字""保存至文件中表示从第1行开始获取检查
##如果文件存在,不会执行if fi代码块中的内容
if [ ! -f "/tmp/rownum.log" ];then
touch /tmp/rownum.log
echo > /tmp/rownum.log
fi之后起点用变量row1表示,终点用变量row2表示。
因此
row1=`sed -n '1p' /tmp/rownum.log`
row2=`wc -l $dir/alert_$ORACLE_SID.log |awk '{print $1}'`这里考虑一个问题,如果警告日志被备份走了,比如我会不定时mv alert_test.log alert_test.log.20200711避免日志过大等问题。
如果日志被备份走了,那么新的日志在本次检查中肯定都是需要检查的,因此,
用变量text1保存上次检查最后一行的文本内容值/tmp/rownum.log,变量text2保存当前警告日志的第$row1行的文本内容,如果有,
$text1!=$text2,表示日志被备份移动走,这时候将row1重置为1表示新产生的日志文件中要从第1行开始检查。
最终如下:#获取上次检查点,该检查点为这次日志检查的起点
row1=`sed -n '1p' /tmp/rownum.log`
text1=`sed -n '2p' /tmp/rownum.log`
text2=`sed -n ''$row1'p' $dir/alert_$ORACLE_SID.log` ##$text1!=$text2,表示日志被备份移动走,相等则不会执行if fi代码块中的内容
if [ "$text1" != "$text2" ]; then
row1=
fi
row2=`wc -l $dir/alert_$ORACLE_SID.log |awk '{print $1}'`另外,如果上次检查和这次检查期间,没有日志产生,则直接退出shell即可。
##若是相等表示间隔检查期间无新日志产生
if [ "$row1" == "$row2" ]; then
exit
fi然后开始更新/tmp/rownum.log中的记录。
把此次检查的终点更新进去,+1之后表示下次检查的起点echo $row2 > /tmp/rownum.log
sed -n ''$row2'p' $dir/alert_$ORACLE_SID.log >> /tmp/rownum.log然后获取起点到终点的内容,保存至前文所说的new_alert.log。
这里我还是用alert_$ORACLE_SID.log表示,就不用new_alert.log了。
##获取文本
row1=$((row1+))
sed -n "${row1},${row2}p" $dir/alert_$ORACLE_SID.log > /getORAerror/alert_$ORACLE_SID.log
至此,步骤1完成。
步骤2
有个perl脚本check_alert.pl,专门取ORA错误的包括前后信息的。
#!/usr/bin/perl use POSIX; my $alert = $ARGV[];
my $days = $ARGV[];
&checkAlert($alert, $days); sub checkAlert {
my $fileName = shift;
my $days = shift;
my $t = localtime;
$t -= $days**;
my $stop = strftime "%a %b %d", localtime(time-$days**);
my @lines;
open F, $fileName or die "can not open $fileName, $!";
my $i = -;
my $line;
while(seek F, --$i, ) {
$line = <F>;
if($line =~ /^\n/) {
seek F, $i+, ;
$line = <F>;
if($line =~ /^$stop/) {
last;
}
if($line =~ /^ORA-/
|| $line =~ /^Mon /
|| $line =~ /^Tue /
|| $line =~ /^Wed /
|| $line =~ /^Thu /
|| $line =~ /^Fri /
|| $line =~ /^Sat /
|| $line =~ /^Sun /
|| $line =~ /^Errors /
) {
push @lines, $line;
}
}
} my $tim = "";
my $len = @lines;
for($i = $len-; $i>=; $i--) {
if($lines[$i] =~ /^ORA-/||$lines[$i] =~ /^Errors/) {
print $tim.$lines[$i];
$tim = "";
} else {
$tim = "\n".$lines[$i];
}
} close F;
}
效果如下:
Fri Sep ::
Errors in file /app/oracle/diag/rdbms/xxxxxxxxxx/xxxxxxxxxx1/trace/xxxxxxxxxx1_lgwr_15763.trc:
ORA-: open failed for members of log group of thread
ORA-: online log thread : '+ARCH/xxxxxxxxxx/onlinelog/group_1.487.974760013'
ORA-: ksfdopn: Failed to open file +ARCH/xxxxxxxxxx/onlinelog/group_1.487.974760013
ORA-: ASM file '+ARCH/xxxxxxxxxx/onlinelog/group_1.487.974760013' does not exist
ORA-: online log thread : '+DATA/xxxxxxxxxx/onlinelog/group_1.265.974760013'
ORA-: ksfdopn: Failed to open file +DATA/xxxxxxxxxx/onlinelog/group_1.265.974760013
ORA-: ASM file '+DATA/xxxxxxxxxx/onlinelog/group_1.265.974760013' does not exist
Errors in file /app/oracle/diag/rdbms/xxxxxxxxxx/xxxxxxxxxx1/trace/xxxxxxxxxx1_lgwr_15763.trc:
ORA-: open failed for members of log group of thread
ORA-: online log thread : '+ARCH/xxxxxxxxxx/onlinelog/group_1.487.974760013'
ORA-: ksfdopn: Failed to open file +ARCH/xxxxxxxxxx/onlinelog/group_1.487.974760013
ORA-: ASM file '+ARCH/xxxxxxxxxx/onlinelog/group_1.487.974760013' does not exist
ORA-: online log thread : '+DATA/xxxxxxxxxx/onlinelog/group_1.265.974760013'
ORA-: ksfdopn: Failed to open file +DATA/xxxxxxxxxx/onlinelog/group_1.265.974760013
ORA-: ASM file '+DATA/xxxxxxxxxx/onlinelog/group_1.265.974760013' does not exist
步骤3
首先获取错误信息,然后判断是否有错误信息生成。
没有错误信息生成,则退出脚本,不继续执行。
#获取错误信息
/usr/bin/perl /getORAerror/check_alert.pl /getORAerror/alert_$ORACLE_SID.log > /getORAerror/err_alert_$ORACLE_SID.log ##判断是否有ORA错误
err_row=`wc -l /getORAerror/err_alert_$ORACLE_SID.log |awk '{print $1}'`
if [ $err_row -eq ]; then
exit
fi
接下来,所有的错误信息都在文件err_alert_$ORACLE_SID.log中,只需要将该文件中的内容发送到邮箱即可。
第一可以用Linux系统本身的客户端,比如mail/sendmail/mutt等命令,不过要求需要连通互联网,并且发送腾讯邮箱是接收不了的。
但是可以用163邮箱是可以接收的,这里有我2016年的时候用mail命令发送邮件的记录。
具体命令的用法问度娘,比较简单的。
第二种就是服务器是在内网,无法访问互联网,我现在就是这种情况。
而且我们监控用的邮箱就是腾讯企业邮箱,也无法接收。
那么我采用的方法是用Oracle自身发邮件的功能,这个比第一种麻烦。
首先Oracle数据库需要访问到你的alert_$ORACLE_SID.log文件内容,我创建外部表进行访问。
15:34:30 SYS@xxxxxxxxxx(714)> create directory get_ORA as '/getORAerror'; Directory created. Elapsed: 00:00:00.02 15:51:19 SYS@xxxxxxxxxx(714)> create table getORAerror
15:51:37 2 (message nvarchar2(400))
15:51:37 3 organization external
15:51:37 4 (type ORACLE_LOADER default directory get_ORA location('err_alert_xxxxxxxxxx.log')); Table created. Elapsed: 00:00:00.03
之后利用存储过程,采用游标访问外部表,发送邮件就行。
存储过程主体网上就有,利用Oracle数据库发送邮件,根据我自己的环境我改造了下。
CREATE OR REPLACE PROCEDURE send_mail
IS
v_mailhost VARCHAR2(30) := 'xxx.xx.xx.xx';
v_user VARCHAR2(30) := 'problem';
v_pass VARCHAR2(20) := 'problem';
v_sender VARCHAR2(50) := 'problem@xxxxxxxx.xxx.xx';
p_recipient VARCHAR2(50) := 'problem@xxxxxxxx.xxx.xx';
p_subject VARCHAR2(100) := '某某数据库(instance_name)存在ORA错误,请检查!!!';
p_message VARCHAR2(32767) := '错误信息如下:'||chr(13);
p_tmp VARCHAR2(400) := '';
v_conn UTL_SMTP. connection ;
v_msg varchar2(32767);
cursor data_query_cur is select message from getORAerror;
BEGIN
open data_query_cur;
loop fetch data_query_cur into p_tmp;
exit when data_query_cur%notfound;
p_message := p_message||p_tmp ||chr(13);
end loop;
close data_query_cur;
v_conn := UTL_SMTP.open_connection(v_mailhost, 25);
UTL_SMTP.ehlo(v_conn, v_mailhost);
UTL_SMTP.command(v_conn, 'AUTH LOGIN' );
UTL_SMTP.command(v_conn,UTL_RAW.cast_to_varchar2(UTL_ENCODE.base64_encode(UTL_RAW.cast_to_raw(v_user))));
UTL_SMTP.command(v_conn,UTL_RAW.cast_to_varchar2(UTL_ENCODE.base64_encode(UTL_RAW.cast_to_raw(v_pass))));
UTL_SMTP.mail(v_conn, v_sender);
UTL_SMTP.rcpt(v_conn, p_recipient);
v_msg := 'Date:' || TO_CHAR(SYSDATE, 'dd mon yy hh24:mi:ss' )
|| UTL_TCP.CRLF || 'From: ' || '<' || v_sender || '>'
|| UTL_TCP.CRLF || 'To: ' || '<' || p_recipient || '>'
|| UTL_TCP.CRLF || 'Subject: ' || p_subject
|| UTL_TCP.CRLF || UTL_TCP.CRLF
|| p_message;
UTL_SMTP.open_data(v_conn);
UTL_SMTP.write_raw_data(v_conn, UTL_RAW.cast_to_raw(v_msg));
UTL_SMTP.close_data(v_conn);
UTL_SMTP.quit(v_conn);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.put_line(DBMS_UTILITY.format_error_stack);
DBMS_OUTPUT.put_line(DBMS_UTILITY.format_call_stack);
END send_mail;
/
注意,变量p_message是正文,就是你的ORA得错误存放变量,一开始我发送邮件之后,
全部的信息都在一行乱掉了,后边用chr(13)进行回车换行。
注意,chr(10)表示换行 chr(13)表示回车。好像跟C语言是一样的。
另外,v_mailhost表示发送邮件的服务器地址,应该也是SMTP地址,我用的是公司私有的服务器,
所以不需要互联网,各位根据自己的情况改。
还有就是不需要接收邮件的服务器地址,因为我只需要发送邮件即可,problem@xxxxxxxx.xxx.xx
发送给自己problem@xxxxxxxx.xxx.xx,之后你用比如Foxmail登陆就能够收到(Foxmail配置了另外接收邮件的服务器)。
最后,就一开始的shell脚本,加上调用存储过程发邮件的部分就行。
sqlplus / as sysdba <<eof
begin
p_get_ora_err_node1;
end;
/
exit
eof
全部有两个脚本,一个步骤2中的脚本。
另外一个就是步骤1中一直说明的脚本,比较分散,这个统一一下内容。
#!/bin/bash
source /home/oracle/.bash_profile
##如果文件不存在,则创建
if [ ! -f "/tmp/rownum.log" ];then
touch /tmp/rownum.log
echo > /tmp/rownum.log
fi # 查找alert日志所在的路径
sqlplus -s /nolog &> /dev/null << eof
set feedback off heading off verify off trimspool on timing off
set pagesize linesize
conn / as sysdba;
set timing off
set time off
spool /tmp/tmpdir.txt
select value from v\$parameter where name='background_dump_dest';
spool off
exit;
eof errs=`grep 'ERROR' /tmp/tmpdir.txt | wc -l`
if [ $errs -gt ]; then
echo "query alert log direction run error, please check the /tmp/tmpdir.txt for details."
exit
else
dir=`cat /tmp/tmpdir.txt`
fi #获取上次检查点,该检查点为这次日志检查的起点
row1=`sed -n '1p' /tmp/rownum.log`
text1=`sed -n '2p' /tmp/rownum.log`
text2=`sed -n ''$row1'p' $dir/alert_$ORACLE_SID.log` ##比较上次检查时最后一行和最后一行对应行号来对应当前行的文本是否一致
##一致表示警告日志没有被归档
if [ "$text1" != "$text2" ]; then
row1=
fi
row2=`wc -l $dir/alert_$ORACLE_SID.log |awk '{print $1}'` ##若是相等表示间隔检查期间无新日志产生
if [ "$row1" == "$row2" ]; then
exit
fi echo $row2 > /tmp/rownum.log
sed -n ''$row2'p' $dir/alert_$ORACLE_SID.log >> /tmp/rownum.log ##获取新增的警告日志内容
row1=$((row1+))
sed -n "${row1},${row2}p" $dir/alert_$ORACLE_SID.log > /getORAerror/alert_$ORACLE_SID.log #获取错误信息
/usr/bin/perl /getORAerror/check_alert.pl /getORAerror/alert_$ORACLE_SID.log > /getORAerror/err_alert_$ORACLE_SID.log ##判断是否有ORA错误
err_row=`wc -l /getORAerror/err_alert_$ORACLE_SID.log |awk '{print $1}'`
if [ $err_row -eq ]; then
exit
fi sqlplus / as sysdba <<eof
begin
send_mail;
end;
/
exit
eof
Linux如何用脚本监控Oracle发送警告日志ORA-报错发送邮件的更多相关文章
- Linux简单Shell脚本监控MySQL、Apache Web和磁盘空间
Linux简单Shell脚本监控MySQL.Apache Web和磁盘空间 1. 目的或任务 当MySQL数据库.Apache Web服务器停止运行时,重新启动运行,并发送邮件通知: 当服务器磁盘的空 ...
- 使用zabbix监控oracle的后台日志
本文将介绍如何使用zabbix监控oracle的后台日志,当oracle后台日志出现“ORA-”或“Error”时,第一时间将该信息报警出来 zabbix agent端 以下所有操作均用root执行 ...
- linux下启动dbca或netmgr类的图形界面报错解决
linux下启动dbca或netmgr类的图形界面报错解决 Xlib: connection to ":0.0" refused by server Xlib: No pro ...
- Oracle中建立物化视图报错
Oracle中建立物化视图报错 今天在建立视图的时候,报了一个错:ORA-01723: zero-length columns are not allowed. 建视图的语句: create mate ...
- 将Linux中文语言修改成英文的具体操作方法及报错解决
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 3 ...
- 归档—监控ORACLE数据库告警日志
ORACLE的告警日志里面包含许多有用的信息,尤其是一些ORACLE的ORA错误信息,所以有必要及时归档.监控数据库告警日志的ORA错误,及时提醒数据库管理员DBA处理这些错误信息,那么我们首先来看看 ...
- oracle 12c 警告日志位置
Oracle 12c环境下查询,alert日志并不在bdump目录下,看到网上和书上都写着可以通过初始化参数background_dump_dest来查看alter日志路径,还说警告日志文件的缺省位置 ...
- 【zabbix监控问题】记录zabbix控制面板报错及日志报错的解决方法
问题1: 上图是我已经解决了的截图.在百度查询的资料中,说是把zabbix_agentd.conf文件中server监听的主机127.0.0.1去掉,但是我去掉之后问题仍然没有解决,最后在这篇博客上发 ...
- oracle 19c dataguard aws ORA-03186报错
环境说明 在亚马逊云AWS上面安装了一套oracle 19c dataguard,linux centos 7.7的操作系统,开始时同步正常,实时应用redolog,一会儿之后就不行了.报错如下: o ...
随机推荐
- cb37a-_c++_STL_算法_复制元素copy_copy_backward
cb37a-_c++_STL_算法_复制元素copy_copy_backward copy(),同一个容器内部区间的拷贝,或者容器与容器之间的拷贝copy_backward()//向后copy 注意: ...
- 三星note8港版如何显示电量百分比呢?
设置-通知-状态栏,显示电量百分比打钩即可.
- Shiro密码重试次数限制
如在 1 个小时内密码最多重试 5 次,如果尝试次数超过 5 次就锁定 1 小时,1 小时后可再次重试,如果还是重试失败,可以锁定如 1 天,以此类推,防止密码被暴力破解.我们通过继承 HashedC ...
- Github删除分支下所有提交记录
[本文版权归微信公众号"代码艺术"(ID:onblog)所有,若是转载请务必保留本段原创声明,违者必究.若是文章有不足之处,欢迎关注微信公众号私信与我进行交流!] 有时候,我们提交 ...
- JavaWeb网上图书商城完整项目--13.项目所需环境的搭建
1.首先安装mysql 创建项目所需的数据库,直接运行项目提供的goods.sql文库 2.myeclipse创建一个web project ,项目的名称是goods 把视频中提供的项目原型下的提供的 ...
- 计算机网络之tcp四次挥手
TCP的四次挥手(Four-Way Wavehand)1.前言对于"三次握手"我们耳熟能详,因为其相对的简单.但是,我们却不常听见“四次挥手”,就算听过也未必能详细地说明白它的具体 ...
- .net Core中如何读取Appsetting配置文件
现在APPSetting下面配置以下节点 { "Logging": { "IncludeScopes": false, "LogLevel" ...
- Sharepoint 编辑WebPart时,WebPart属性为灰色不可用
一般在客户端设置就是灰色的,解决方法就是,要在服务器上进行设置,就可以了.:)
- 我打算用JAVA实现GB/T32960 监控平台的tcp server
之前是用golang写得 ,因为对golang不是很熟练,打算基于netty再写一个,开源出来. 如果近期时间宽裕,就准备着手了. 有兴趣的朋友也可以留言一起做.
- 阿里P7岗位面试,面试官问我:为什么HashMap底层树化标准的元素个数是8
前言 先声明一下,本文有点标题党了,像我这样的菜鸡何德何能去面试阿里的P7岗啊,不过,这确实是阿里p7级岗位的面试题,当然,参加面试的人不是我,而是我部门的一个大佬.他把自己的面试经验分享给了我,也让 ...