システム運用を行う上で、システムが正常に稼働していることを確認するための監視運用は必須の項目となります。
大規模な設備を備えたデータセンター等は、監視サービスを提供しているところが多いですが、監視対象の項目数制限や追加料金等で桁違いの額を要求されることが一般的です。
例えば、ログを監視するサービスを活用するにしても、httpd(webアラートログ),oracle(DBアラートログ)等のように、監視対象となるログファイルが複数に分散している場合、当然別々の料金がかかってしまいます。
出来れば、可能な限り監視対象となるファイルは一元化しておくことが、金額面以外にもメンテナンス性からみても都合が良いのは明白です。
実際には、障害発生時のログ(アラート情報)は、すべてシステムログへ出力することで監視対象ファイルの一元化を測ることが一般的です。
そこで、シェルスクリプトからシステムログへアラートログを書き込む関数を作成します。
シスログ出力機能を実装する
前提
Beエンジニアでシェルスクリプトを実行する環境は下記の通りとします。
実行環境
BASE_DIR(任意のディレクトリ)
- scripts
- bin(実行スクリプト格納領域)
- func.sh (実行ファイル)
- com(共通スクリプト格納領域)
- comFunc.shrc(共通関数定義ファイル)
- etc(設定ファイル等の格納領域)
- message.conf(メッセージ定義ファイル)
- log(スクリプト実行ログの格納領域)
- スクリプト名.log
- tmp(テンポラリ領域)
- rep(レポート出力領域)
- bin(実行スクリプト格納領域)
外部ファイルは「 <BASE_DIR>/scripts/etc/message.conf 」配下へ作成されるものとして作成します。
メッセージ定義ファイルの作成
今回は、指定された引数の数が正しくなかった場合(引数の値が2つ未満の場合にエラー)、システム(/var/log/messages)ログへエラーメッセージを出力します。
※ 引数が最低3つ以上無いとエラーとします。
message.conf
E-00001 user.err "The number of arguments is incorrect. args_count: ["$#"]"
前回使用したメッセージ定義ファイルをそのまま流用します。
シスログ出力関数の作成
この記事で作成するログ出力ロジックの対象は下記を想定しています。
標準出力ログを${LOG_PATH}/<スクリプト名>.logへ出力します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# -------------------------------------------------- # Output the system log. # -------------------------------------------------- # param1 Message ID as the first argument # return N/A # -------------------------------------------------- logSys() { msgId=${1} shift facility=`cat ${MSG_CONF} | grep "${msgId}" | awk '{print $2}'` sysMsg="$(eval echo `getMsg ${msgId} "${facility}"`)" logger "${facility}" "${sysMsg}" logger -t $SCRIPT_NAME -p "${facility}" "${sysMsg}" } |
1-6行目:コメント
7行目:関数「logSys ()」の宣言
8行目:第一引数(メッセージID)を${msgId}へ格納
9行目:引数をシフト(メッセージIDを除いた引数を取得したメッセージへ使用する)
10行目:ファシリティー取得
11行目:メッセージ定義ファイルから、引数に指定された番号のメッセージを取得して変数へ格納
12行目:システムログに「日時 ホスト名 ユーザー名: sysMsg」を記録する場合の出力
13行目:ログの各行に指定したタグを出力する場合の出力
※ 12行目と13行目は、監視対象となる文字列に合わせて選択してください。
共通関数定義ファイルへの実装
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 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# shell scripts common resource #_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ # # common.shrc ver.1.0.0 2020.04.24 # # Usage: # -------- # # Description: # 各種機能より呼び出される共通機能を実装する。 # # 設計書 # none # #_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ # ------------------------------------------------------------ # Constant declaration(定数の宣言領域) # ------------------------------------------------------------ BASE_PATH=${BASE_PATH:-"/root/scripts"} COM_PATH=${BASE_PATH}/com ETC_PATH=${BASE_PATH}/etc LOG_PATH=${BASE_PATH}/log TMP_PATH=${BASE_PATH}/tmp REP_PATH=${BASE_PATH}/rep SCRIPT_NAME=`basename $0` JOB_OK=0 JOB_WR=1 JOB_ER=2 MSG_CONF=${ETC_PATH}/message.conf # ------------------------------------------------------------ # functions (関数を記述する領域) # ------------------------------------------------------------ (省略)前回までの関数が記述されている領域 # -------------------------------------------------- 👈 ここから追記 # Output the system log. # -------------------------------------------------- # param1 Message ID as the first argument # return N/A # -------------------------------------------------- logSys() { msgId=${1} shift facility=`cat ${MSG_CONF} | grep "${msgId}" | awk '{print $2}'` sysMsg="$(eval echo `getMsg ${msgId} "${facility}"`)" logger "${facility}" "${sysMsg}" logger -t $SCRIPT_NAME -p "${facility}" "${sysMsg}" } |
関数が増えていくたびに共通関数定義ファイルが長くなってしまうので、前回までの作成関数などは、省略しています。
呼び出し側のシェルスクリプト作成
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 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
#!/bin/sh #_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ # # ver.1.0.0 yyyy.mm.dd # # Usage: # # sh /root/scripts/bin/func.sh # # Description: # 例題コマンド実行スクリプト # # 設計書 # なし # #_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ . `dirname $0`/../com/comFunc.shrc # ---------------------------------------------------------- # variables (変数の宣言領域) # ---------------------------------------------------------- scope="var" rc=${JOB_ER} # ---------------------------------------------------------- # functions (関数を記述する領域) # ---------------------------------------------------------- scope="func" # -------------------------------------------------- # devider. # -------------------------------------------------- # return N/A # -------------------------------------------------- line (){ echo -e "\\n ------------" echo -e " ▼ ${1}" } # ---------------------------------------------------------- # Check the validity of the argument. # ---------------------------------------------------------- # param 1 source file # param 2 destination file # return N/A # ---------------------------------------------------------- checkArgs() { if [ $# -le 2 ]; then logOut $(eval echo $(getMsg E-00001)) 👈 ログ出力関数呼び出し(../log/func.log) logSys "E-00001" "$@" 👈 シスログ出力関数呼び出しを追記 (/var/log/messages) exitLog 2 fi } # ---------------------------------------------------------- # pre-process (事前処理ロジックを記述する領域) # ---------------------------------------------------------- scope="pre" startLog # Check the validity of the argument. checkArgs "$@" # ---------------------------------------------------------- # main-process (メインロジックを記述する領域) # ---------------------------------------------------------- scope="main" if [ $? -eq ${JOB_OK} ]; then rc=${JOB_OK} fi # ---------------------------------------------------------- # post-process (事後処理ロジックを記述する領域) # ---------------------------------------------------------- scope="post" exitLog $rc |
52行目:シスログ出力関数の呼び出し
書式:logSys "メッセージID" "全引数"
システムログ出力関数の実行
あえてエラーを発生させるために引数を「No1 No2」の2つで実行させます。
# 実行シェルスクリプトからエラーログの出力テスト
$ <BASE_DIR>/scripts/bin/func.sh No1 No2
1 2 3 4 5 6 7 8 9 10 11 |
[root@CentOS7 bin]# sh func.sh no1 no2 The log file was output to the [ /root/scripts/log ]. >> /root/scripts/log/func.log [root@CentOS7 bin]#tail -f /var/log/messages Apr 27 12:33:43 CentOS7 systemd: Starting Network Manager Script Dispatcher Service... Apr 27 12:33:43 CentOS7 dhclient[7014]: bound to 192.168.109.131 -- renewal in 877 seconds. Apr 27 12:33:43 CentOS7 dbus[6577]: [system] Successfully activated service 'org.freedesktop.nm_dispatcher' Apr 27 12:33:43 CentOS7 systemd: Started Network Manager Script Dispatcher Service. Apr 27 12:33:43 CentOS7 nm-dispatcher: req:1 'dhcp4-change' [ens33]: new request (4 scripts) Apr 27 12:33:43 CentOS7 nm-dispatcher: req:1 'dhcp4-change' [ens33]: start running ordered scripts... Apr 27 12:36:39 CentOS7 root: user.err The number of arguments is incorrect. args_count: [2] 👈 これ Apr 27 12:36:39 CentOS7 func.sh: The number of arguments is incorrect. args_count: [2] 👈 これ |
ちょっと分かりずらいですが、10行目と11行目が出力結果です。
例として、ログ監視サービスへ、10行目と11行目の[ARGS_NUM_ERR] を監視対象文字として設定しておくことで、ログ監視サービスは、障害発生時にこの文字列がログに出現次第、エスカレーション動作(アラートメールを担当者に送る等)を実行すると言った感じです。監視対象ファイルがシスログに一元化できることがメリットです。
※ 本スクリプト利用により発生した利用者の損害全てに対し、いかなる責任をも負わないものとし、損害賠償をする一切の義務はないものとします。