商用プロジェクトは1から100に至るまで、すべてエビデンスの世界です。システムに障害は付きものですので、障害報告を行う際には、必ず「1次報告」「中間報告」「最終報告」をエビデンス付きで提出しなければなりません。
シェルスクリプトを作成する場合、予め障害が発生することを念頭に入れて設計を進めていきます。基盤として挙げるなら「CPU」や「メモリ」、「ディスク」など、リソース周りの障害は約束されていることです。では、そのエビデンスとして必要になるものは何でしょう?
エビデンスとして必ず必要になるものとは、ずばり「ログ」です。
実行から障害に至るまでの経緯を時系列にログとして記録していなければ、対象方法が見つかりません。「ログ出力なくしてシステム開発にあらず!」システムの成功は、すべて「ログの出力の有無」にかかっているといっても過言ではありません!
そこで、ちょっとしたログ出力のロジックを作成してみることにしました。
運用自動化ツール
🟡 運用自動化ツール
📌 面倒な作業を一括効率化!シェルスクリプトで実現する運用自動化術
├─ 基本共通
| ├─【Shellの基礎知識】簡単なログ出力ロジックを作ってみました。
| ├─【Shellの基礎知識】シェルスクリプトの作成を時短!テンプレートで効率化する方法
| ├─【Shellの基礎知識】共通関数定義クラスの完全ガイド!設計から実践まで徹底解説
├─ 開発環境構築
| ├─【RHEL系Linux】開発サーバー初期設定スクリプトの完全自動化
| ├─【RHEL系Linux】Apache+Let's Encrypt 自動構築スクリプト|バーチャルホスト対応
| ├─【RHEL系Linux】Tomcatを自動インストール・設定するスクリプトの作成と活用法
| └─【RHEL系Linux】PostgreSQLを自動インストールするシェルスクリプトの使い方
└─ 運用・保守
├─【RHEL系Linux】任意サービスを簡単制御!汎用サービススクリプトの活用術
├─【RHEL系Linux】ファイルやログを自動圧縮する汎用スクリプトの実装と活用法
├─【RHEL系Linux】リソース(CPU・MEM)監視スクリプトで使用率・異常を検知する仕組み
├─【RHEL系Linux】中間ファイル連携を完全制御するファイル転送スクリプト
├─【RHEL系Linux】信頼性を重視した完了保証型ディレクトリ転送スクリプトの設計と実装
├─【RHEL系Linux】ディスク使用率を自動監視するシェルスクリプトの実装
└─【RHEL系Linux】サーバーの障害検知と自動通知|systemdログ監視の実装例
共通ログ出力クラスの概要と役割
ログ管理は、運用現場の効率化やトラブル解決において間接的ながらも大きな役割を果たします。しかし、現場ではその重要性が認識されにくく、属人的な対応や管理の手間が課題となることが多々あります。共通ログ出力クラスは、こうした非効率を解消し、ログ管理を標準化することで、システムの運用をスムーズにするために設計されています。
共通ログ出力クラスの目的
共通ログ出力クラスは、シェルスクリプト内で発生するイベントやエラーを記録し、運用効率を向上させるための仕組みを提供します。
このクラスを導入することで以下の目的を達成できます:
- ログ記録の統一化:
ログフォーマットを統一し、複数のスクリプト間で一貫性を保つ。 - デバッグの効率化:
スクリプト内で発生したエラーや処理結果を記録し、問題発生時の迅速な原因特定を可能にする。 - 運用保守性の向上:
手動でのログ管理や記録ミスを防ぎ、運用の手間を削減する。
例えば、複数のスクリプトが同一のログフォーマットで出力することで、エラー解析や動作確認が格段にスムーズになります。
ログ管理の重要性と課題解決のポイント
ログ管理はシステムの信頼性を支える重要な要素ですが、直接的な利益を生まないことから、多くの現場で軽視される傾向があります。その結果、エラー発生時に原因の特定が困難になり、トラブルシューティングに余計な時間と労力を費やすなど、非効率な状況が発生することが少なくありません。
ログ管理の重要性
システム運用においてログ管理は、障害発生時の原因追及や運用状況の可視化に欠かせない要素です。
特にシェルスクリプトでは、簡易的な処理が多い反面、エラーが発生しても原因が記録されないことが頻繁に起こります。これにより、以下のような問題が発生します:
- エラーの再現が困難になる。
- 複数のスクリプト間でログフォーマットが異なり、解析に手間がかかる。
- 障害発生時に必要な情報が欠落する。
課題解決のポイント
共通ログ出力クラスを使用することで、以下の課題を解決します:
- ログフォーマットの統一:
日時、ログレベル、メッセージを標準化し、可読性を向上させます。 - エラーの記録自動化:
スクリプトのエラーや成功状態を自動で記録し、トラブル対応の時間を短縮します。 - ログのローテーション:
古いログを自動削除し、ディスク容量の枯渇を防ぎます。
共通ログ出力クラスの設計の基本方針
共通ログ出力クラスは、以下の設計方針を基に構築されています:
基本方針
- 汎用性を重視
- どのスクリプトからでも利用できるよう、関数形式で実装。
- ログ出力先やフォーマットを環境変数でカスタマイズ可能に設計。
- 簡単な導入手順
- スクリプトに数行のコードを追加するだけで利用可能。
- 必要な設定を最小限に抑え、即時使用を実現。
- 可読性と保守性の向上
- ログメッセージには「日時」「ログレベル」「メッセージ本文」を含め、誰が見ても理解しやすい構造。
- ログの出力先は標準出力、ファイル、syslog など複数選択肢を提供。
- エラーへの耐性
- ログ出力に失敗してもスクリプトの動作に影響を与えないよう設計。
共通ログ出力クラスを活用することで、シェルスクリプトの運用効率を格段に向上させるだけでなく、運用トラブルに迅速に対応できる体制を整えることが可能です。次回の記事では、具体的な実装方法とサンプルコードについて解説します。
設計書の構成と設計要素
共通ログ出力クラスを効率的に設計・実装するためには、動作環境、使用する変数、実装された関数の詳細を体系的に把握することが重要です。ここでは、これらの要素を表形式でまとめ、各要素の内容を簡潔に比較・理解しやすいようにしました。
クラス設計の前提条件
共通ログ出力クラスの動作環境や設計時の注意点を表にまとめました。この情報は、スクリプトを異なる環境に導入する際の参考になります。
| 項目 | 内容 |
|---|---|
| 対応OS | RHEL系Linuxメイン。必要に応じてDebian系やWSLも可。 |
| 対応シェル | Bash(4.x以上を推奨)。Bourne Shell(sh)でも動作可能。 |
| 依存関係 | 標準コマンド(echo, date, catなど)を使用し、外部ツールへの依存なし。 |
| ディレクトリ構成 | /log ディレクトリにログファイルを保存(出力先のカスタマイズ可能)。 |
使用する変数一覧
ここでは、共通ログ出力クラスで使用されるグローバル変数を種類ごとに整理しています。この表は、グローバル変数の役割を明確にし、スクリプトのカスタマイズやトラブルシューティングを効率化することを目的としています。
| 変数名 | 説明 | 初期値 |
|---|---|---|
| BASE_PATH | ベースディレクトリのパスを指定。 | /work/scripts/ |
| COM_PATH | 共通関数やクラスを保存するディレクトリを指定。 | ${BASE_PATH}/com |
| DEFAULT_LOG_MODE | ログの出力先を指定(例: CONSOLE, FILE, SYSLOG)。 | CONSOLE |
| ETC_PATH | 設定ファイルを保存するディレクトリを指定。 | ${BASE_PATH}/etc |
| INFRA_MSG_CONF | メッセージ設定ファイルのパスを指定。 | ${ETC_PATH}/infraMessage.cfg |
| JOB_OK | 正常終了コードを定義。 | 0 |
| JOB_WR | 警告終了コードを定義。 | 1 |
| JOB_ER | エラー終了コードを定義。 | 2 |
| LOG_FORMAT | ログのフォーマットを指定(例: %s [ %-5s] %s\n)。 | %s [ %-5s] %s\n |
| LOG_LEVEL | ログ出力のレベルを指定(例: DEBUG, INFO, WARNING, ERROR)。 | INFO(※1) |
| LOG_PATH | ログファイルの保存ディレクトリを指定。 | ${BASE_PATH}/log |
| REP_PATH | レポート出力用ディレクトリを指定。 | ${BASE_PATH}/rep |
| SCRIPT_NAME | 実行中のスクリプト名を取得。 | $(basename "$0") |
| TIMER_START | タイマーの開始時刻を記録。 | 0 |
| TMP_PATH | 一時ファイルを保存するディレクトリを指定。 | ${BASE_PATH}/tmp |
※1:INFO 設定時に DEBUG は記録されません。
実装されている関数の詳細
以下は、共通ログ出力クラスに実装されている主要な関数とその目的をまとめた表です。この表を利用することで、関数の役割を短時間で理解でき、実際のコードに素早く適用できます。
| 関数名 | 目的 | 説明 |
|---|---|---|
| divider | 区切り線の表示 | メッセージを区切り線とともに出力します。 |
| startLog | ログ出力の初期化 | ログモードに応じて出力先を設定し、ログの開始メッセージを記録します。 |
| exitLog | ログ出力の終了 | スクリプトの終了コードに応じた終了メッセージを記録します。 |
| logOut | ログメッセージの記録 | 指定されたログレベルとメッセージをフォーマットして出力します。 |
| getMsg | メッセージの取得 | メッセージ設定ファイルから指定されたメッセージIDに対応する文言を取得します。 |
| startTimer | タイマーの開始 | 現在時刻を記録し、後続処理の実行時間を計測します。 |
| endTimer | タイマーの終了 | 開始時刻からの経過時間を計算し、ログに記録します。 |
| parseArgs | コマンドライン引数の解析 | ログレベルやログモードなどの引数を解析して設定します。 |
共通ログ出力クラスの設定手順
共通ログ出力クラスを正しく利用するためには、クラスの設置場所や設定方法を適切に行う必要があります。以下では、設置場所の選定から設定手順、ログ保存先のカスタマイズまで、具体的な手順を説明します。
共通ログ出力クラスは、他のスクリプトから容易に利用できるよう、以下のディレクトリ構造を推奨します。
前提となる実行環境
Beエンジニアでシェルスクリプトを実行する環境は下記の通りとします。
実行環境
BASE_DIR(任意のディレクトリ)
- scripts
- bin(実行スクリプト格納領域)
- <<各種実行スクリプト>>.sh (実行ファイル)
- com(共通スクリプト格納領域)
- logger.shrc(共通ログ出力ファイル)
- utils.shrc(共通関数定義ファイル)
- etc(設定ファイル等の格納領域)
- infraMessage.conf(メッセージ定義ファイル)
- log(スクリプト実行ログの格納領域)
- スクリプト名.log
- tmp(テンポラリ領域)
- rep(レポート出力領域)
- bin(実行スクリプト格納領域)
| ディレクトリ | 説明 |
|---|---|
| scripts/bin/ | 実行可能なスクリプト(メインロジック)を配置するディレクトリ。 |
| scripts/com/ | 共通関数やクラス(例: logger.shrc)を格納するディレクトリ。 |
| scripts/etc/ | 設定ファイル(環境変数やコンフィグ)を配置するディレクトリ。 |
| scripts/log/ | ログファイルを保存するディレクトリ。 |
| scripts/tmp/ | 一時ファイルや中間データを保存するディレクトリ。 |
| scripts/rep/ | レポート出力ディレクトリ。集計用の元データなどを格納する。 |
設置例: 共通ログ出力クラス(例: logger.shrc)は scripts/com/ に配置します。以下は、scripts/com/logger.shrc に配置する共通ログ出力クラスのソースコード例です。
#!/bin/bash
#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
#
# logger.sh ver.1.0.0 2025.01.24
#
# Usage:
# --------
#
# Description:
# 各種スクリプトより呼び出されるlog出力機能を提供する。
#
# 設計書
# none
#
#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
# <変更履歴>
# Ver. 変更管理No. 日付 更新者 変更内容
# 1.0 PR-0001 2025/01/16 Bepro 新規作成
#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
# 共通クラスの読み込み
. $(dirname $0)/../com/utils.shrc
# ------------------------------------------------------------
# ログレベルの優先度定義
# ------------------------------------------------------------
declare -A LOG_LEVEL_PRIORITY=(
['DEBUG']='0'
['INFO']='1'
['WARNING']='2'
['ERROR']='3'
)
# ------------------------------------------------------------
# グローバル変数
# ------------------------------------------------------------
DEFAULT_LOG_MODE="CONSOLE" # ログの出力モード (FILE, CONSOLE, SYSLOG)
BASE_PATH=${BASE_PATH:-"//home/bepro/projects/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")
INFRA_MSG_CONF="${ETC_PATH}/infraMessage.cfg"
LOG_FORMAT="%s [ %s ] [ %s ] %s" # デフォルトのログフォーマット
LOG_LEVEL=${LOG_LEVEL:-"INFO"} # デフォルトのログレベル
TIMER_START=0
JOB_OK=0
JOB_WR=1
JOB_ER=2
export INFRA_MSG_CONF
export SCRIPT_NAME
hostname=$(hostname -s)
# ------------------------------------------------------------
# 関数定義
# ------------------------------------------------------------
scope="func"
# 区切り線の表示
divider() {
local message="$1"
echo -e "\n ------------"
echo -e " ▼ ${message}"
}
# ログ開始処理
startLog() {
if [[ "${DEFAULT_LOG_MODE}" == "FILE" ]]; then
exec >> "${LOG_PATH}/${SCRIPT_NAME%%.*}.log" 2>&1
fi
logOut "INFO" "SCRIPT:[${SCRIPT_NAME}] PID:[$$] STARTED LOG."
}
# ログ終了処理
exitLog() {
local rc=${1:-${JOB_ER}}
local status
case "${rc}" in
0) status="INFO" ;;
1) status="WARNING" ;;
2) status="ERROR" ;;
*) status="FATAL" ;;
esac
logOut "${status}" "SCRIPT:[${SCRIPT_NAME}] PID:[$$] ENDED LOG."
exit "${rc}"
}
# ログ出力関数
logOut() {
local level="$1"
shift
local message="$*"
if (( LOG_LEVEL_PRIORITY["${level}"] >= LOG_LEVEL_PRIORITY["${LOG_LEVEL}"] )); then
local formatted_message
formatted_message=$(printf "${LOG_FORMAT}" "$(date +"%Y-%m-%d %H:%M:%S")" "${level}" "${scope}" "${message}")
case "${DEFAULT_LOG_MODE}" in
"FILE") echo "${formatted_message}" >> "${LOG_PATH}/${SCRIPT_NAME%%.*}.log" ;;
"CONSOLE") echo "${formatted_message}" ;;
"SYSLOG") logger -p user."${level,,}" "${formatted_message}" ;;
*) echo "Invalid log mode: ${DEFAULT_LOG_MODE}" ;;
esac
fi
}
# 外部ファイルからメッセージを取得して展開
getMsg() {
local msg_id="$1"
if [[ ! -f ${INFRA_MSG_CONF} ]]; then
logOut "ERROR" "Message configuration file not found: ${INFRA_MSG_CONF}"
return ${JOB_ER}
fi
local message
message=$(awk -v id="${msg_id}" -F= '$1 == id {print $2}' "${INFRA_MSG_CONF}")
if [[ -z "${message}" ]]; then
logOut "WARNING" "Message ID not found: ${msg_id}"
return ${JOB_WR}
fi
# 二重展開を実施
eval "echo \"${message}\""
}
# タイマー開始
startTimer() {
TIMER_START=$(date +%s)
}
# タイマー終了と実行時間出力
endTimer() {
local end_time=$(date +%s)
local elapsed=$((end_time - TIMER_START))
logOut "INFO" "Execution time: ${elapsed} seconds."
}
# コマンドライン引数の解析
parseArgs() {
while [[ $# -gt 0 ]]; do
case "$1" in
--log-level)
LOG_LEVEL="$2"
shift 2
;;
--log-mode)
DEFAULT_LOG_MODE="$2"
shift 2
;;
*)
echo "Unknown argument: $1"
exit 1
;;
esac
done
}
# --------------------------------------------------
# Level conversion for outputting the log to the console.
# --------------------------------------------------
# param1 facility.serverity
# param2 messages
# return N/A
# --------------------------------------------------
cnvServerityToLevel() {
local level=$(lower "${1##*.}")
local msg=$(eval echo "$2")
case "$level" in
emerg|panic|crit|error|err ) logOut "ERROR" "$msg" ;;
alert|warn|notice ) logOut "WARN" "$msg" ;;
info ) logOut "INFO" "$msg" ;;
debug ) logOut "DEBUG" "$msg" ;;
trace|* ) logOut "ERROR" "$msg" ;; # 未定義レベルは ERROR 扱い
esac
}
# --------------------------------------------------
# Get the message from an external file.
# --------------------------------------------------
# param1 messages id
# param2 facility.serverity
# return N/A
# --------------------------------------------------
getSysMsg() {
awk -v id="$1" -v field="$2" '
/^[[:space:]]*$/ { next }
/^#/ { next }
NF >= 3 && $1 == id && $2 == field {
for (i = 3; i <= NF; i++) {
printf "%s%s", (i > 3 ? OFS : ""), $i
}
print ""
exit
}
' "$msg_conf"
}
# --------------------------------------------------
# Output the system log.
# --------------------------------------------------
# param1 messages id
# return N/A
# --------------------------------------------------
logSystem() {
msg_conf="$ETC_PATH/$hostname/message.conf"
if [ ! -f "$msg_conf" ]; then
logOut "ERROR" "Configuration file can not be found [ $msg_conf ]."
exitLog 2
fi
fac_serv=$(awk -v id="$1" 'NF >= 2 && $1 == id { print $2; exit }' "$msg_conf")
if [ -z "$fac_serv" ]; then
logOut "WARNING" "Logger priority is missing for id [$1]. Message not sent to syslog."
return
fi
raw_msg=$(getSysMsg "$1" "$fac_serv")
e_msg=$(eval "echo \"$raw_msg\"")
logOut "[DEBUG] fac_serv=[$fac_serv]" >&2
logOut "[DEBUG] e_msg=[$e_msg]" >&2
logger -t "$SCRIPT_NAME" -p "$fac_serv" "$e_msg"
}
# ------------------------------------------------------------
# 使用例
# ------------------------------------------------------------
# parseArgs "$@"
# export LOG_LEVEL="INFO"
# export DEFAULT_LOG_MODE="CONSOLE"
# startLog
# startTimer
# logOut "INFO" "This is an info message."
# logOut "WARNING" "This is a warning message."
# logOut "ERROR" "This is an error message."
# getMsg "MSG001"
# endTimer
# exitLog ${JOB_OK}
Systemログ出力用メッセージファイル
シスログメッセージ出力ロジックを追加したため、それに伴い「メッセージ定義ファイル(message.conf)」を追加記載してます。
2025/08/03 Bepro
logger.shrc の logSystem() が参照するメッセージ定義ファイル(例:$ETC_PATH/$hostname/message.conf)の仕様をまとめます。RHEL系 rsyslog 前提、文字コードは UTF-8(BOMなし) を推奨します。
ポイント
- 1行=1メッセージ(空行可、行頭 # はコメント)。
- 列は「ID(数値)/facility.severity/"message"」の順。
- 本文中の $変数 は呼び出し元スクリプトで事前にセットしておく。
- レベルは運用上の混乱防止のため user.warn(警告)/user.err(致命) に統一。本文中の表記も [WARN]/[ERROR] に合わせる。
【定義フォーマット例(CPU/Mem/FileSystem)】
# CPU
21001 user.err "[ERROR] CPU使用率がしきい値を超過しました(超過回数: $count_exceed / 許容回数: $threshold_count、しきい値: $threshold%、現在値: $usage_val_int%、$SCRIPT_NAME)。"
11001 user.warn "[WARN] CPU使用率がしきい値を超過しました(超過回数: $count_exceed / 許容回数: $threshold_count、しきい値: $threshold%、現在値: $usage_val_int%、$SCRIPT_NAME)。"
# MEM
21002 user.err "[ERROR] メモリ使用率がしきい値を超過しました(超過回数: $count_exceed / 許容回数: $threshold_count、しきい値: $threshold%、現在値: $usage_val_int%、$SCRIPT_NAME)。"
11002 user.warn "[WARN] メモリ使用率がしきい値を超過しました(超過回数: $count_exceed / 許容回数: $threshold_count、しきい値: $threshold%、現在値: $usage_val_int%、$SCRIPT_NAME)。"
$ DISK
21003 user.err "[ERROR] ファイルシステムの使用率がしきい値を超過しました(超過回数: $count_exceed / 許容回数: $warn_crit、しきい値: $crit_thres%、現在値: $usage_now%、ファイルシステム: $fs、$SCRIPT_NAME)。"
11003 user.warn "[WARN] ファイルシステムの使用率がしきい値を超過しました(超過回数: $count_exceed / 許容回数: $warn_crit、しきい値: $warn_thres%、現在値: $usage_now%、ファイルシステム: $fs、$SCRIPT_NAME)。"
スクリプト側は ID だけ 渡し、本文と syslog レベル(facility.severity)はファイルに集約して管理します。文言変更やレベル変更をコード改修なしで反映できます。
ホスト単位の配置を推奨(例:$ETC_PATH/dev01/message.conf)。BOM 付きUTF-8は文字化け要因になるため避ける。
共通ログ出力クラスの設定方法
クラスを利用するためには、実行スクリプト内でクラスを読み込む設定を行います。以下に設定手順を示します。
- スクリプト内でクラスを読み込む
実行スクリプト内で source コマンドを使って共通ログ出力クラスを読み込みます。source ./com/logger.shrc
- ログファイルの初期設定
ログファイルの保存先やログレベルを環境変数で設定します。LOG_FILE="./log/my_script.log"
LOG_LEVEL="INFO" - 必要な関数を呼び出す
スクリプト内で関数を順序立てて呼び出し、ログ出力を有効化します。startLog
logOut "INFO" "スクリプト開始"
# 処理コード closeLog
設置例: ログ出力テストクラス(例: testLog.sh)は scripts/bin/ に配置します。以下は logger.shrc を使ってログ出力を行うソースコードの例です。
#!/bin/bash
# テスト用スクリプト: 共通ログ機能の動作確認
# ====== グローバル変数の設定 ======
BASE_PATH="/work/scripts" # ベースディレクトリ(全体のルートパス)
LOG_PATH="${BASE_PATH}/log" # ログファイルの保存先ディレクトリ
LOG_LEVEL="INFO" # ログレベル(DEBUG, INFO, WARNING, ERROR)
DEFAULT_LOG_MODE="CONSOLE" # ログ出力先(CONSOLEまたはFILE)
ETC_PATH="${BASE_PATH}/etc" # 設定ファイルを保存するディレクトリ
JOB_OK=0 # 正常終了コード
# ====== 必要なディレクトリ作成 ======
mkdir -p "${LOG_PATH}" # ログ保存用ディレクトリを作成
mkdir -p "${ETC_PATH}" # 設定ファイル保存用ディレクトリを作成
# ====== メッセージ設定ファイルの作成 ======
cat <<EOF > "${ETC_PATH}/infraMessage.cfg"
MSG001=Hello, \${USER}! Today is \${DATE}. # ユーザーへの挨拶メッセージ
MSG002=Backup completed successfully. # バックアップ成功メッセージ
EOF
# ====== 共通ログ機能の読み込み ======
source "${BASE_PATH}/com/logger.shrc" # 共通ログ出力クラスを読み込む
# ====== テスト開始 ======
startLog # ログ出力を初期化
startTimer # 実行時間計測用タイマー開始
logOut "DEBUG" "This is a debug message for developers." # デバッグ用メッセージ
logOut "INFO" "This is an informational message." # 情報メッセージ
logOut "WARNING" "This is a warning message." # 警告メッセージ
logOut "ERROR" "This is an error message." # エラーメッセージ
# ====== メッセージを取得して出力 ======
getMsg "MSG001" # メッセージID MSG001 の内容を取得して出力
getMsg "MSG002" # メッセージID MSG002 の内容を取得して出力
endTimer # タイマーを終了
exitLog ${JOB_OK} # ログ出力を終了し、スクリプトを終了
※ 本スクリプト利用により発生した利用者の損害全てに対し、いかなる責任をも負わないものとし、損害賠償をする一切の義務はないものとします。
便宜的に「infraMessage.cfg」をプログラム内で作成していますが、実際の運用では、想定されるエラーメッセージや通知メッセージをあらかじめ集約・管理しておくための設定ファイルとして利用します。このファイルは運用前に手動で準備し、必要に応じて内容を更新していくものです。プログラムで動的に作成されるファイルではない点にご注意ください。
実行結果
[root@localhost bin]# sh testLog.sh 2025-01-29 02:43:19 [ INFO ] SCRIPT:[testLog.sh] PID:[443589] STARTED LOG. 2025-01-29 02:43:19 [ INFO ] This is an informational message. 2025-01-29 02:43:19 [ WARNING] This is a warning message. 2025-01-29 02:43:19 [ ERROR] This is an error message. Hello, root! Today is . # ユーザーへの挨拶メッセージ Backup completed successfully. # バックアップ成功メッセージ 2025-01-29 02:43:19 [ INFO ] Execution time: 0 seconds. 2025-01-29 02:43:19 [ INFO ] SCRIPT:[testLog.sh] PID:[443589] ENDED LOG. [root@localhost bin]#
ログ保存先ディレクトリの設定
共通ログ出力クラスでは、ログファイルの保存先を柔軟に設定できます。
| 設定方法 | 説明 |
|---|---|
| デフォルト設定 | ディレクトリ /log にログを保存します。 |
| 環境変数による設定 | 環境変数 LOG_FILE を設定することで、任意の保存先を指定可能です。 |
| 動的ディレクトリ作成 | 保存先ディレクトリが存在しない場合、自動で作成されます(例: mkdir -p コマンドを使用)。 |
保存先ディレクトリに書き込み権限がない場合、ログの記録に失敗する可能性があります。保存先が適切に設定されているかを事前に確認することを推奨します。
実践的な利用方法とサンプルコード
共通ログ出力クラスを実際のスクリプトに適用することで、ログ管理を効率化し、運用のトラブル対応を迅速化することができます。このセクションでは、基本的な利用方法と具体的なサンプルコードを紹介します。また、よくある利用ケースについても解説します。
基本的な使い方
共通ログ出力クラスを使用すると、ログの出力先やログレベルを柔軟に設定できます。ログ出力先(CONSOLE または FILE)の設定により、メッセージを標準出力に表示するか、ログファイルに記録するかを切り替えることができます。
ログ出力先の設定
| モード | 説明 | 設定方法 |
|---|---|---|
| CONSOLE | 標準出力(コンソール)に表示 | DEFAULT_LOG_MODE="CONSOLE" |
| FILE | 指定したログファイルに記録 | DEFAULT_LOG_MODE="FILE" |
使い分けのポイント:
- CONSOLE: デバッグ時や短期間の確認用に便利です。
- FILE: 長期間のログ記録や、後で分析が必要な場合に適しています。
FILEモードの追加設定:
出力先をファイルにする場合、以下の設定を追加してください。
LOG_PATH="/work/scripts/log"
LOG_FILE="${LOG_PATH}/script.log"
mkdir -p "${LOG_PATH}"
ログレベルの設定
共通ログ出力クラスでは、記録するログメッセージの重要度を制御するためにログレベルを設定します。
| レベル | 説明 | 設定方法 |
|---|---|---|
| DEBUG | 詳細なデバッグ情報を記録 | LOG_LEVEL="DEBUG" |
| INFO | 情報メッセージを記録(デフォルト) | LOG_LEVEL="INFO" |
| WARNING | 警告メッセージを記録 | LOG_LEVEL="WARNING" |
| ERROR | エラーメッセージのみ記録 | LOG_LEVEL="ERROR" |
ログレベルの動作例:
例えば、 LOG_LEVEL="INFO" を設定した場合、 INFO、 WARNING、 ERROR のメッセージは記録されますが、 DEBUG メッセージは無視されます。ログレベルは「重要度の低いメッセージを除外するフィルター」として機能します。
コード例
以下は、ログ出力先を FILE に設定し、ログレベルを INFO に設定した場合のスクリプト例です。
#!/bin/bash
# グローバル変数の設定
BASE_PATH="/work/scripts"
LOG_PATH="${BASE_PATH}/log"
LOG_FILE="${LOG_PATH}/script.log"
DEFAULT_LOG_MODE="FILE" # ログ出力先をファイルに設定
LOG_LEVEL="INFO" # 記録するログレベルを設定
# 必要なディレクトリ作成
mkdir -p "${LOG_PATH}"
# 共通ログ出力クラスの読み込み
source "${BASE_PATH}/com/logger.shrc"
# ログ出力
startLog
logOut "DEBUG" "This is a debug message." # 記録されない
logOut "INFO" "This is an informational message." # 記録される
logOut "WARNING" "This is a warning message." # 記録される
logOut "ERROR" "This is an error message." # 記録される
closeLog
出力結果例
ログファイル( /work/scripts/log/script.log)には、以下の内容が記録されます:
==== ログ開始: 2025-01-28 12:00:00 ====
[INFO] This is an informational message.
[WARNING] This is a warning message.
[ERROR] This is an error message.
==== ログ終了: 2025-01-28 12:00:02 ====
よくある利用ケース
共通ログ出力クラスは、さまざまなシナリオで活用できます。以下に代表的なケースを示します。
スクリプトのデバッグログの記録
デバッグログを活用すると、スクリプトの実行状況や変数の状態を詳細に追跡できます。以下は変数の値を記録する例です。
logOut "DEBUG" "変数 value の値は: $value"
プロセスのエラー追跡ログの活用
エラーが発生したプロセスやコマンドを追跡する場合、以下のように logOut を活用します。
if ! cp source.txt destination.txt; then
logOut "ERROR" "ファイルのコピーに失敗しました"
fi
共通ログ出力クラスを導入するメリット
共通ログ出力クラスを導入することで、スクリプトの運用効率や保守性が飛躍的に向上します。ここでは、主なメリットを3つの観点から解説します。
5.1 ログ管理の効率化
ログ管理が効率化されることで、以下のような利点があります:
- 一貫性のあるログフォーマット: ログ出力が標準化されるため、複数スクリプト間でフォーマットの違いを気にする必要がなくなります。これにより、ログ解析やエラーの追跡が簡単になります。
- 自動的なログディレクトリ作成: 保存先ディレクトリが存在しない場合でも、動的に作成する機能を備えており、手動での事前準備が不要です。
- 柔軟な出力先の指定: 環境変数を利用して、ログの保存先を簡単にカスタマイズできます。これにより、ローカル環境や本番環境の要件に応じた運用が可能です。
5.2 スクリプト保守性の向上
スクリプト保守の手間を削減し、長期的な運用に適した状態を実現します。
- コードの再利用性向上: ログ出力の仕組みを共通クラスとして切り出すことで、複数のスクリプト間で同じロジックを使い回すことができます。これにより、重複したコードの記述を減らし、保守性が向上します。
- 可読性の向上: ログに日時やログレベルが付与されるため、スクリプトの実行内容を明確に把握できます。これにより、第三者がコードをレビューする際の負担が軽減されます。
- 変更時の影響範囲を最小化: ログ管理に関する処理を共通クラスに集約しているため、変更が必要な場合でもクラス内の修正だけで対応可能です。
5.3 トラブルシューティングの迅速化
エラーや問題が発生した際の対応速度を格段に向上させます。
