Oracle 11g アラートログ(alert.log)やリスナーログ(listener.log)のログローテーションスクリプト

はじめに
===

Linuxサーバ上に構築したOracle 11gサーバ(11.1.0.7.2)のOracleアラートログ(alert.log)やリスナーログ(listener.log)のログローテーションスクリプトについて記載致します。

OracleサーバのOracleアラートログやリスナーログには随時ログが追記されていく為、ログローテーションをしないと、ログサイズが肥大化してディスク容量を圧迫してしまいます。

ログファイルサイズが増え続けて、Oracleサーバのディスク空き容量が枯渇してしまうと、データベース障害が発生し、Oracleを利用するサービスが停止する事になる為、ログローテーションが必要になります。

概要
===

後述のOracleアラートログやリスナーログをログローテーションするスクリプトを作成し、Oracle 11gサーバのoracleユーザのcrontabに登録する事で、1日1回Oracleアラートログやリスナーログファイルをログローテーションさせております。

crontabでログローテーションスクリプトを定期実行するようにして1年以上経過しましたが、今のところログローテーション失敗したり、本番環境と開発環境Oracleサーバの動作やOracleを利用しているサービスに影響を与える事なく、正常にログローテーション稼動しております。

なお、Oracle 10gの頃は、リスナーログファイルをローテーションさせる時は、以下コマンドを利用してログファイルの切り替えを行っておりましたが、Oacle 11gでADRを有効化している場合、以下コマンドではログローテーション出来なかったので、今回のような方法でログローテーションさせる事にしました。

```
lsnrctl set log_file リスナーログファイル名
```

Oracleアラートログやリスナーログファイルのログローテーションスクリプト
===

Oracle 11gサーバの任意のディレクトリに、以下のようなログローテーションスクリプトを作成します。Oracleサーバのホスト名等、変数の値はサンプル用に修正しております。

なお、スクリプト中では、アラートログやリスナーログファイルをmvコマンドでリネームしております。Oracle 11g(11.1.0.7.2)では、リネームしてアラートログやリスナーログファイルが存在しない場合、バックグラウンドプロセスやリスナープロセスがログを出力する時にログファイルを新規作成する挙動でした。touchコマンドで空のログファイルを作成したり、lsnrctlコマンドでリスナープロセスを再起動しなくても、ログファイルは新規作成され、アラートログやリスナーログは新しいログファイルに追記される挙動でした。

```
[oracle@example-oracle-11g-active ~]$ vi oracle_alert_log_rotate.sh
```

```shell-session:oracle_alert_log_rotate.sh
#!/bin/sh

#####
# サーバ名取得
Host=`hostname -s`

# 本番環境Oracleサーバか開発環境Oracleサーバのどちらで実行しているか判定する
# 本番環境Oracleサーバ
if [ "${Host}" = "example-oracle-11g-active" ] || [ "${Host}" = "example-oracle-11g-standby" ] ; then

	Disk_Name="/oracle_example_production"
	SidName="testsid1"      # ORACLE_SIDを指定する

	MailAddress="hogehoge-production@example.com" # ログローテーション結果メールの通知先メールアドレスを指定する

	MailSubjectText="[$Host] [production] Oracleアラートログとリスナーログローテーション結果"

# 開発環境Oracleサーバ
else

	Disk_Name="/oracle_example_staging"
	SidName="testsid2"      # ORACLE_SIDを指定する

	MailAddress="hogehoge-staging@example.com"    # ログローテーション結果メールの通知先メールアドレスを指定する

	MailSubjectText="[$Host] [staging] Oracleアラートログとリスナーログローテーション結果"

fi

#####
# スクリプトの2重起動チェック
procname="oracle_alert_log_rotate"
lock_fname="/tmp/${procname}.lock"

if [ -f "${lock_fname}" ] ; then

	echo "バッチ [$0 $@] が実行中です。"
	echo "バッチの多重起動を禁止している為、処理を実行せずに終了します。"

	echo "バッチを強制的に実行したい場合、既存のバッチ [$0] を停止して、以下のロックファイルを削除して下さい。"
	echo "${lock_fname}"
	ls -lrta ${lock_fname}
	exit 1

fi

echo "$$ $0 $@" > ${lock_fname}

##### 待機系Oracleサーバではスクリプトを実行させないチェック処理
# ${Disk_Name}で指定したディレクトリがマウントされていなければ、待機系サーバと判断してシェルを実行しないこととする。
Mount_Chk=`df -Pk | grep -v grep | grep "${Disk_Name}" | wc -l`

if [ "${Mount_Chk}" -lt "1" ] ; then

	# ロックファイル削除
	rm -f ${lock_fname}

	exit 0

fi

#####
# Oracle11gリスナーログ(XML形式とテキスト形式両方)、アラートログのログローテーションを実行する

#####
# ログローテーション対象のOracleリスナーログを記述する
LogNameList="\
	${Disk_Name}/opt/oracle/app/oracle/diag/tnslsnr/${Host}/listener/alert/log.xml \
	${Disk_Name}/opt/oracle/app/oracle/diag/tnslsnr/${Host}/listener/trace/listener.log \
	${Disk_Name}/opt/oracle/app/oracle/diag/rdbms/${SidName}/${SidName}/alert/log.xml \
	${Disk_Name}/opt/oracle/app/oracle/diag/rdbms/${SidName}/${SidName}/trace/alert_${SidName}.log \
"

#####
# メール件名を日本語表記とする為、nkfで文字コード変換を実行
Subject=`echo ${MailSubjectText} | nkf -j`
echo "${MailSubjectText}" > /tmp/${procname}
echo "" >> /tmp/${procname}

#####
date_str=`date "+%Y%m%d"`
LogCount=0

# ログローテーション実行
for LogName in ${LogNameList}
do

	LogCount=`expr ${LogCount} + 1`
	echo "対象ログファイル名:${LogName}" >> /tmp/${procname}

	if [ -f "${LogName}" ] ; then

		# ログファイル名をリネーム
		mv ${LogName} ${LogName}.${date_str}

		# リネームしたログファイルを圧縮
		gzip ${LogName}.${date_str}

		if [ -f "${LogName}.${date_str}.gz" ] ; then

			echo "ログファイル圧縮 成功" >> /tmp/${procname}
			echo "  ログファイル名: ${LogName}.${date_str}.gz"  >> /tmp/${procname}

		else

			echo "ログファイル圧縮 失敗!!"     >> /tmp/${procname}
			echo "  ログファイル名: ${LogName}.${date_str}"     >> /tmp/${procname}

		fi

	else

		echo "以下のログファイルはありません" >> /tmp/${procname}
		echo "  ログファイル名:${LogName}"    >> /tmp/${procname}

	fi

	echo "" >> /tmp/${procname}

done

##### ログローテーションして一定時間が経過した古いログファイルを削除する
if [ -d "${Disk_Name}/opt/oracle/app/oracle/diag/rdbms/${SidName}/${SidName}/trace" ] ; then
	find ${Disk_Name}/opt/oracle/app/oracle/diag/rdbms/${SidName}/${SidName}/trace -name "${SidName}_*.trm" -mtime +0 -print | xargs rm -f
	find ${Disk_Name}/opt/oracle/app/oracle/diag/rdbms/${SidName}/${SidName}/trace -name "${SidName}_*.trc" -mtime +0 -print | xargs rm -f
	find ${Disk_Name}/opt/oracle/app/oracle/diag/rdbms/${SidName}/${SidName}/trace -name "cdmp_*" -mtime +7 -print | xargs rm -f -r
	echo "${Disk_Name}/opt/oracle/app/oracle/diag/rdbms/${SidName}/${SidName}/trace 配下の古いログファイルを削除しました。" >> /tmp/${procname}
else
	echo "${Disk_Name}/opt/oracle/app/oracle/diag/rdbms/${SidName}/${SidName}/trace ディレクトリは存在しません。" >> /tmp/${procname}
fi

if [ -d "${Disk_Name}/opt/oracle/app/oracle/diag/tnslsnr/${Host}/listener/alert" ] ; then
	find ${Disk_Name}/opt/oracle/app/oracle/diag/tnslsnr/${Host}/listener/alert -name "log*.xml*.gz" -mtime +14 -print | xargs rm -f
	echo "${Disk_Name}/opt/oracle/app/oracle/diag/tnslsnr/${Host}/listener/alert 配下の古いログファイルを削除しました。" >> /tmp/${procname}
else
	echo "${Disk_Name}/opt/oracle/app/oracle/diag/tnslsnr/${Host}/listener/alert ディレクトリは存在しません。" >> /tmp/${procname}
fi

if [ -d "${Disk_Name}/opt/oracle/app/oracle/diag/tnslsnr/${Host}/listener/trace" ] ; then
	find ${Disk_Name}/opt/oracle/app/oracle/diag/tnslsnr/${Host}/listener/trace -name "listener*.gz" -mtime +14 -print | xargs rm -f
	echo "${Disk_Name}/opt/oracle/app/oracle/diag/tnslsnr/${Host}/listener/trace 配下の古いログファイルを削除しました。" >> /tmp/${procname}
else
	echo "${Disk_Name}/opt/oracle/app/oracle/diag/tnslsnr/${Host}/listener/trace ディレクトリは存在しません。" >> /tmp/${procname}
fi

if [ -d "${Disk_Name}/opt/oracle/app/oracle/diag/rdbms/${SidName}/${SidName}/alert" ] ; then
	find ${Disk_Name}/opt/oracle/app/oracle/diag/rdbms/${SidName}/${SidName}/alert -name "log*.xml*.gz" -mtime +14 -print | xargs rm -f
	echo "${Disk_Name}/opt/oracle/app/oracle/diag/rdbms/${SidName}/${SidName}/alert 配下の古いログファイルを削除しました。" >> /tmp/${procname}
else
	echo "${Disk_Name}/opt/oracle/app/oracle/diag/rdbms/${SidName}/${SidName}/alert ディレクトリは存在しません。" >> /tmp/${procname}
fi

if [ -d "${Disk_Name}/opt/oracle/app/oracle/diag/rdbms/${SidName}/${SidName}/trace" ] ; then
	find ${Disk_Name}/opt/oracle/app/oracle/diag/rdbms/${SidName}/${SidName}/trace -name "alert_${SidName}*.gz" -mtime +14 -print | xargs rm -f
	find ${Disk_Name}/opt/oracle/app/oracle/diag/rdbms/${SidName}/${SidName}/trace -name "${SidName}_*.trc*" -mtime +1 -print | xargs rm -f
	find ${Disk_Name}/opt/oracle/app/oracle/diag/rdbms/${SidName}/${SidName}/trace -name "${SidName}_*.trm*" -mtime +1 -print | xargs rm -f
	echo "${Disk_Name}/opt/oracle/app/oracle/diag/rdbms/${SidName}/${SidName}/trace 配下の古いログファイルを削除しました。" >> /tmp/${procname}
else
	echo "${Disk_Name}/opt/oracle/app/oracle/diag/rdbms/${SidName}/${SidName}/trace ディレクトリは存在しません。" >> /tmp/${procname}
fi

# 古いインシデントトレースログファイルを削除
if [ -d "${Disk_Name}/opt/oracle/app/oracle/diag/rdbms/${SidName}/${SidName}/incident" ] ; then
	find ${Disk_Name}/opt/oracle/app/oracle/diag/rdbms/${SidName}/${SidName}/incident -name "incdir_*" -mtime +7 -print | xargs rm -f -r
	echo "${Disk_Name}/opt/oracle/app/oracle/diag/rdbms/${SidName}/${SidName}/incident 配下の古いログファイルを削除しました。" >> /tmp/${procname}
else
	echo "${Disk_Name}/opt/oracle/app/oracle/diag/rdbms/${SidName}/${SidName}/incident ディレクトリは存在しません。" >> /tmp/${procname}
fi

#####
# ログローテーション結果の通知メール送信
cat /tmp/${procname} | nkf -j > /tmp/${procname}.sjis
mail -s "${Subject}" ${MailAddress} < /tmp/${procname}.sjis
rm -f /tmp/${procname} /tmp/${procname}.sjis

#####
# ロックファイル削除
rm -f ${lock_fname}
```

スクリプトに実行権限を設定します。

```
[oracle@example-oracle-11g-active ~]$ chmod 755 oracle_alert_log_rotate.sh
```

Oracle 11gサーバのcrontabでログローテーションスクリプトを定期実行する例
===

Oracle 11gサーバのoracleユーザのcrontabに対して、以下のようにログローテーションスクリプトを定期実行するよう追加します。
以下は毎日朝6時30分にログローテーションを実行する例です。

まず、oracleユーザの変更前のcrontab情報をバックアップします。

```
[oracle@example-oracle-11g-active ~]$ crontab -l > /tmp/oracle_cron_backup.`date "+%Y%m%d_%H%M%S"`
[oracle@example-oracle-11g-active ~]$

[oracle@example-oracle-11g-active ~]$ ll /tmp/oracle_cron_backup.20150126_225845
-rw-rw-r--. 1 oracle XXXXXXXX XXX Jan 26 22:58 /tmp/oracle_cron_backup.20150126_225845
[oracle@example-oracle-11g-active ~]$
```

oracleユーザのcrontabに以下のようにログローテーションスクリプトを追加します。

```
[oracle@example-oracle-11g-active ~]$ crontab -e
　　(末尾に以下を追加します)
30 6 * * * /****/*****/****/****/oracle_alert_log_rotate.sh
```

oracleユーザのcrontabにログローテーションスクリプトが追加された事を確認します。念の為、追加したcronエントリ以外の他のcronエントリを誤って変更していないか確認します。

```
[oracle@example-oracle-11g-active ~]$ crontab -l > /tmp/oracle_cron_addafter.`date "+%Y%m%d_%H%M%S"`
[oracle@example-oracle-11g-active ~]$
[oracle@example-oracle-11g-active ~]$ ll /tmp/oracle_cron_addafter.20150126_230034
-rw-rw-r--. 1 oracle XXXXXXXX XXX Jan 26 23:00 /tmp/oracle_cron_addafter.20150126_230034
[oracle@example-oracle-11g-active ~]$

[oracle@example-oracle-11g-active ~]$ diff /tmp/oracle_cron_backup.20150126_225845 /tmp/oracle_cron_addafter.20150126_230034
XXaXX
> 30 6 * * * /****/*****/****/****/oracle_alert_log_rotate.sh
[oracle@example-oracle-11g-active ~]$
```

ログローテーションスクリプト実行後のログファイル状態
===

oracleユーザのcrontab または 手動でログローテーションスクリプトを実行すると、以下のようにアラートログやリスナーログファイルがローテーションされます。

```
[oracle@example-oracle-11g-active ~]$ ll /oracle_example_production/opt/oracle/app/oracle/diag/rdbms/${ORACLE_SID}/${ORACLE_SID}/trace/alert_${ORACLE_SID}.log*
-rw-r----- 1 oracle oinstall  8670  1月 23 09:43 /oracle_example_production/opt/oracle/app/oracle/diag/rdbms/${ORACLE_SID}/${ORACLE_SID}/trace/alert_${ORACLE_SID}.log
-rw-r----- 1 oracle oinstall  5400  1月  8 06:27 /oracle_example_production/opt/oracle/app/oracle/diag/rdbms/${ORACLE_SID}/${ORACLE_SID}/trace/alert_${ORACLE_SID}.log.20150108.gz
-rw-r----- 1 oracle oinstall  5791  1月  9 06:29 /oracle_example_production/opt/oracle/app/oracle/diag/rdbms/${ORACLE_SID}/${ORACLE_SID}/trace/alert_${ORACLE_SID}.log.20150109.gz
-rw-r----- 1 oracle oinstall  5643  1月 10 06:26 /oracle_example_production/opt/oracle/app/oracle/diag/rdbms/${ORACLE_SID}/${ORACLE_SID}/trace/alert_${ORACLE_SID}.log.20150110.gz
-rw-r----- 1 oracle oinstall  5397  1月 11 06:28 /oracle_example_production/opt/oracle/app/oracle/diag/rdbms/${ORACLE_SID}/${ORACLE_SID}/trace/alert_${ORACLE_SID}.log.20150111.gz
-rw-r----- 1 oracle oinstall  5657  1月 12 06:27 /oracle_example_production/opt/oracle/app/oracle/diag/rdbms/${ORACLE_SID}/${ORACLE_SID}/trace/alert_${ORACLE_SID}.log.20150112.gz
-rw-r----- 1 oracle oinstall  5341  1月 13 06:29 /oracle_example_production/opt/oracle/app/oracle/diag/rdbms/${ORACLE_SID}/${ORACLE_SID}/trace/alert_${ORACLE_SID}.log.20150113.gz
-rw-r----- 1 oracle oinstall  5929  1月 14 06:29 /oracle_example_production/opt/oracle/app/oracle/diag/rdbms/${ORACLE_SID}/${ORACLE_SID}/trace/alert_${ORACLE_SID}.log.20150114.gz
-rw-r----- 1 oracle oinstall  5714  1月 15 06:26 /oracle_example_production/opt/oracle/app/oracle/diag/rdbms/${ORACLE_SID}/${ORACLE_SID}/trace/alert_${ORACLE_SID}.log.20150115.gz
-rw-r----- 1 oracle oinstall  5463  1月 16 06:26 /oracle_example_production/opt/oracle/app/oracle/diag/rdbms/${ORACLE_SID}/${ORACLE_SID}/trace/alert_${ORACLE_SID}.log.20150116.gz
-rw-r----- 1 oracle oinstall  5776  1月 17 06:22 /oracle_example_production/opt/oracle/app/oracle/diag/rdbms/${ORACLE_SID}/${ORACLE_SID}/trace/alert_${ORACLE_SID}.log.20150117.gz
-rw-r----- 1 oracle oinstall  6041  1月 18 06:29 /oracle_example_production/opt/oracle/app/oracle/diag/rdbms/${ORACLE_SID}/${ORACLE_SID}/trace/alert_${ORACLE_SID}.log.20150118.gz
-rw-r----- 1 oracle oinstall  5866  1月 19 06:28 /oracle_example_production/opt/oracle/app/oracle/diag/rdbms/${ORACLE_SID}/${ORACLE_SID}/trace/alert_${ORACLE_SID}.log.20150119.gz
-rw-r----- 1 oracle oinstall  5367  1月 20 06:30 /oracle_example_production/opt/oracle/app/oracle/diag/rdbms/${ORACLE_SID}/${ORACLE_SID}/trace/alert_${ORACLE_SID}.log.20150120.gz
-rw-r----- 1 oracle oinstall  6306  1月 21 06:30 /oracle_example_production/opt/oracle/app/oracle/diag/rdbms/${ORACLE_SID}/${ORACLE_SID}/trace/alert_${ORACLE_SID}.log.20150121.gz
-rw-r----- 1 oracle oinstall 15266  1月 22 06:25 /oracle_example_production/opt/oracle/app/oracle/diag/rdbms/${ORACLE_SID}/${ORACLE_SID}/trace/alert_${ORACLE_SID}.log.20150122.gz
-rw-r----- 1 oracle oinstall  5394  1月 23 06:30 /oracle_example_production/opt/oracle/app/oracle/diag/rdbms/${ORACLE_SID}/${ORACLE_SID}/trace/alert_${ORACLE_SID}.log.20150123.gz
[oracle@example-oracle-11g-active ~]$
```

```

[oracle@example-oracle-11g-active ~]$ ll /oracle_example_production/opt/oracle/app/oracle/diag/tnslsnr/example-oracle-11g-active/listener/trace/listener.log*
-rw-r----- 1 oracle oinstall 137829706  1月 23 09:49 /oracle_example_production/opt/oracle/app/oracle/diag/tnslsnr/example-oracle-11g-active/listener/trace/listener.log
-rw-r----- 1 oracle oinstall  37494669  1月  8 06:30 /oracle_example_production/opt/oracle/app/oracle/diag/tnslsnr/example-oracle-11g-active/listener/trace/listener.log.20150108.gz
-rw-r----- 1 oracle oinstall  46068011  1月  9 06:30 /oracle_example_production/opt/oracle/app/oracle/diag/tnslsnr/example-oracle-11g-active/listener/trace/listener.log.20150109.gz
-rw-r----- 1 oracle oinstall  42470357  1月 10 06:30 /oracle_example_production/opt/oracle/app/oracle/diag/tnslsnr/example-oracle-11g-active/listener/trace/listener.log.20150110.gz
-rw-r----- 1 oracle oinstall  39848463  1月 11 06:30 /oracle_example_production/opt/oracle/app/oracle/diag/tnslsnr/example-oracle-11g-active/listener/trace/listener.log.20150111.gz
-rw-r----- 1 oracle oinstall  39091872  1月 12 06:30 /oracle_example_production/opt/oracle/app/oracle/diag/tnslsnr/example-oracle-11g-active/listener/trace/listener.log.20150112.gz
-rw-r----- 1 oracle oinstall  39935321  1月 13 06:30 /oracle_example_production/opt/oracle/app/oracle/diag/tnslsnr/example-oracle-11g-active/listener/trace/listener.log.20150113.gz
-rw-r----- 1 oracle oinstall  40086978  1月 14 06:30 /oracle_example_production/opt/oracle/app/oracle/diag/tnslsnr/example-oracle-11g-active/listener/trace/listener.log.20150114.gz
-rw-r----- 1 oracle oinstall  36727982  1月 15 06:30 /oracle_example_production/opt/oracle/app/oracle/diag/tnslsnr/example-oracle-11g-active/listener/trace/listener.log.20150115.gz
-rw-r----- 1 oracle oinstall  39134265  1月 16 06:30 /oracle_example_production/opt/oracle/app/oracle/diag/tnslsnr/example-oracle-11g-active/listener/trace/listener.log.20150116.gz
-rw-r----- 1 oracle oinstall  39316351  1月 17 06:30 /oracle_example_production/opt/oracle/app/oracle/diag/tnslsnr/example-oracle-11g-active/listener/trace/listener.log.20150117.gz
-rw-r----- 1 oracle oinstall  40550423  1月 18 06:30 /oracle_example_production/opt/oracle/app/oracle/diag/tnslsnr/example-oracle-11g-active/listener/trace/listener.log.20150118.gz
-rw-r----- 1 oracle oinstall  39599325  1月 19 06:30 /oracle_example_production/opt/oracle/app/oracle/diag/tnslsnr/example-oracle-11g-active/listener/trace/listener.log.20150119.gz
-rw-r----- 1 oracle oinstall  45284694  1月 20 06:30 /oracle_example_production/opt/oracle/app/oracle/diag/tnslsnr/example-oracle-11g-active/listener/trace/listener.log.20150120.gz
-rw-r----- 1 oracle oinstall  41283860  1月 21 06:30 /oracle_example_production/opt/oracle/app/oracle/diag/tnslsnr/example-oracle-11g-active/listener/trace/listener.log.20150121.gz
-rw-r----- 1 oracle oinstall  36591758  1月 22 06:30 /oracle_example_production/opt/oracle/app/oracle/diag/tnslsnr/example-oracle-11g-active/listener/trace/listener.log.20150122.gz
-rw-r----- 1 oracle oinstall  44881318  1月 23 06:30 /oracle_example_production/opt/oracle/app/oracle/diag/tnslsnr/example-oracle-11g-active/listener/trace/listener.log.20150123.gz
[oracle@example-oracle-11g-active ~]$
```

最後に、Oracleアラートログやリスナーログのローテーションスクリプトは問題なく動いているものの、昔書いたスクリプトなので、時間出来たら、もう少し綺麗にスクリプト書き直したいと思っております。

Oracleアラートログやリスナーログのログローテーションの一例として、ご参考になりましたら幸いです。

以上になります。