Log 循環紀錄部署(TAMS + HMI)#
- TAMS:每小時更新當天 log;每日
00:10完整匯出前一天。 - HMI:每日
09:00從172.18.35.29:3100完整匯出前一天。 - 兩者皆保留 90 天。
- 輸出格式為 JSONL。
- Log 儲存根目錄為
/Data/Log/。 - 使用
loki-readers群組控管讀取權限。
目錄結構:
/Data/Log/
├── tams/
│ ├── 2026-08-04.jsonl
│ └── 2026-08-05.jsonl
├── hmi/
│ └── 2026-08-04.jsonl
├── loki-export-cron.log
└── loki-export-hmi-cron.log1. 安裝 LogCLI#
已安裝者可跳過。
LogCLI 建議與 Loki 使用相同版本。以下以 Loki v2.9.2、Linux amd64 為例:
sudo apt-get update
sudo apt-get install -y curl unzip util-linux
tmp_dir="$(mktemp -d)"
curl -fL \
https://github.com/grafana/loki/releases/download/v2.9.2/logcli-linux-amd64.zip \
-o "$tmp_dir/logcli.zip"
unzip "$tmp_dir/logcli.zip" -d "$tmp_dir"
sudo install \
-m 0755 \
"$tmp_dir/logcli-linux-amd64" \
/usr/local/bin/logcli
rm -rf "$tmp_dir"
sudo /usr/local/bin/logcli --version2. 建立群組授權#
建議使用群組授權,不要直接開放所有帳號讀取 backend log。
建立系統群組:
sudo groupadd --system loki-readers 2>/dev/null || true將一般使用者加入群組。以下以 compal 為例:
sudo usermod -aG loki-readers compal使用者需重新登入,新的群組權限才會生效。
也可以在目前終端立即切換群組:
newgrp loki-readers確認:
id compal輸出應包含:
loki-readers新增其他可讀取使用者:
sudo usermod -aG loki-readers 使用者名稱3. 建立輸出與腳本目錄#
建立腳本目錄:
sudo install -d -m 0750 /opt/loki-export建立 Log 目錄,並指定 loki-readers 群組:
sudo install \
-d \
-o root \
-g loki-readers \
-m 2750 \
/Data/Log
sudo install \
-d \
-o root \
-g loki-readers \
-m 2750 \
/Data/Log/tams
sudo install \
-d \
-o root \
-g loki-readers \
-m 2750 \
/Data/Log/hmi2750 中的 2 代表 setgid。
在這些目錄內建立的新檔案或子目錄,會自動繼承 loki-readers 群組。
確認目錄權限:
ls -ld \
/Data/Log \
/Data/Log/tams \
/Data/Log/hmi預期類似:
drwxr-s--- root loki-readers /Data/Log
drwxr-s--- root loki-readers /Data/Log/tams
drwxr-s--- root loki-readers /Data/Log/hmi4. 建立共用匯出腳本#
sudo tee /opt/loki-export/fetch-backend-logs.sh > /dev/null <<'EOF'
#!/usr/bin/env bash
set -Eeuo pipefail
export TZ="${TZ:-Asia/Taipei}"
export LOKI_ADDR="${LOKI_ADDR:-http://localhost:3100}"
LOGCLI="${LOGCLI:-/usr/local/bin/logcli}"
OUTPUT_DIR="${OUTPUT_DIR:-/Data/Log/tams}"
RETENTION_DAYS="${RETENTION_DAYS:-90}"
MODE="${1:-today}"
if ! getent group loki-readers > /dev/null; then
echo "Error: group loki-readers does not exist" >&2
exit 1
fi
if [[ -z "${QUERY:-}" ]]; then
QUERY='{compose_service="backend"}'
fi
today="$(date '+%Y-%m-%d')"
case "$MODE" in
today)
target_date="$today"
start_time="$(
date \
--date="${target_date} 00:00:00" \
'+%Y-%m-%dT%H:%M:%S%:z'
)"
end_time="$(date '+%Y-%m-%dT%H:%M:%S%:z')"
;;
yesterday)
target_date="$(date --date='yesterday' '+%Y-%m-%d')"
start_time="$(
date \
--date="${target_date} 00:00:00" \
'+%Y-%m-%dT%H:%M:%S%:z'
)"
end_time="$(
date \
--date="${today} 00:00:00" \
'+%Y-%m-%dT%H:%M:%S%:z'
)"
;;
*)
echo "Usage: $0 today|yesterday" >&2
exit 2
;;
esac
mkdir -p "$OUTPUT_DIR"
output_file="${OUTPUT_DIR}/${target_date}.jsonl"
temp_file="$(mktemp "${output_file}.tmp.XXXXXX")"
cleanup() {
rm -f "$temp_file"
}
trap cleanup EXIT HUP INT TERM
"$LOGCLI" query \
--timezone=Local \
--from="$start_time" \
--to="$end_time" \
--forward \
--quiet \
--output=jsonl \
--limit=0 \
--batch=1000 \
--retries=3 \
"$QUERY" > "$temp_file"
chgrp loki-readers "$temp_file"
chmod 0640 "$temp_file"
mv "$temp_file" "$output_file"
trap - EXIT HUP INT TERM
if [[ "$MODE" == "yesterday" ]]; then
find "$OUTPUT_DIR" \
-type f \
-name '????-??-??.jsonl' \
-mtime "+$((RETENTION_DAYS - 1))" \
-delete
fi
echo "$(date --iso-8601=seconds) exported ${target_date} to ${output_file}"
EOF設定腳本權限:
sudo chown root:root /opt/loki-export/fetch-backend-logs.sh
sudo chmod 0750 /opt/loki-export/fetch-backend-logs.sh檢查 Shell 語法:
sudo bash -n /opt/loki-export/fetch-backend-logs.sh注意:LogCLI 查詢最後必須是:
"$QUERY"不要額外加入任何 }。
5. 設定既有檔案權限#
若 /Data/Log/ 已有匯出的 JSONL 檔案:
sudo find /Data/Log \
-type f \
-name '*.jsonl' \
-exec chown root:loki-readers {} \; \
-exec chmod 0640 {} \;預期檔案權限:
-rw-r----- 1 root loki-readers ... 2026-08-04.jsonl6. 手動測試 TAMS#
匯出前一天的 TAMS backend log:
sudo /usr/bin/flock --verbose -n \
/run/loki-export.lock \
/usr/bin/env \
OUTPUT_DIR=/Data/Log/tams \
RETENTION_DAYS=90 \
/opt/loki-export/fetch-backend-logs.sh yesterday匯出今天截至目前的 TAMS backend log:
sudo /usr/bin/flock --verbose -n \
/run/loki-export.lock \
/usr/bin/env \
OUTPUT_DIR=/Data/Log/tams \
/opt/loki-export/fetch-backend-logs.sh today7. 手動測試 HMI#
匯出前一天的 HMI backend log:
sudo /usr/bin/flock --verbose -n \
/run/loki-export-hmi.lock \
/usr/bin/env \
LOKI_ADDR=http://172.18.35.29:3100 \
OUTPUT_DIR=/Data/Log/hmi \
RETENTION_DAYS=90 \
QUERY='{container="polymed-hmi-backend"}' \
/opt/loki-export/fetch-backend-logs.sh yesterday8. 確認匯出結果#
列出所有 JSONL:
sudo find /Data/Log \
-type f \
-name '*.jsonl' \
-ls查看 TAMS 前一天檔案:
sudo head -n 5 \
/Data/Log/tams/"$(date --date='yesterday' '+%Y-%m-%d')".jsonl查看 HMI 前一天檔案:
sudo head -n 5 \
/Data/Log/hmi/"$(date --date='yesterday' '+%Y-%m-%d')".jsonl9. 建立 Cron 執行紀錄檔#
先建立 Cron log,並指定群組與權限:
sudo install \
-o root \
-g loki-readers \
-m 0640 \
/dev/null \
/Data/Log/loki-export-cron.log
sudo install \
-o root \
-g loki-readers \
-m 0640 \
/dev/null \
/Data/Log/loki-export-hmi-cron.log確認:
ls -l \
/Data/Log/loki-export-cron.log \
/Data/Log/loki-export-hmi-cron.log預期:
-rw-r----- 1 root loki-readers ... /Data/Log/loki-export-cron.log
-rw-r----- 1 root loki-readers ... /Data/Log/loki-export-hmi-cron.log10. 設定 root Cron#
編輯 root crontab:
sudo crontab -e加入:
# 每小時第 5 分鐘,覆寫更新當天 TAMS log
5 * * * * OUTPUT_DIR=/Data/Log/tams /usr/bin/flock -n /run/loki-export.lock /opt/loki-export/fetch-backend-logs.sh today >> /Data/Log/loki-export-cron.log 2>&1
# 每天 00:10,完整匯出前一天 TAMS log,保留 90 天
10 0 * * * OUTPUT_DIR=/Data/Log/tams RETENTION_DAYS=90 /usr/bin/flock -n /run/loki-export.lock /opt/loki-export/fetch-backend-logs.sh yesterday >> /Data/Log/loki-export-cron.log 2>&1
# 每天 09:00,完整匯出前一天 HMI backend log,保留 90 天
0 9 * * * /usr/bin/flock --verbose -n /run/loki-export-hmi.lock /usr/bin/env LOKI_ADDR=http://172.18.35.29:3100 OUTPUT_DIR=/Data/Log/hmi RETENTION_DAYS=90 QUERY='{container="polymed-hmi-backend"}' /opt/loki-export/fetch-backend-logs.sh yesterday >> /Data/Log/loki-export-hmi-cron.log 2>&1確認 Cron:
sudo crontab -l11. 查看 Cron 執行紀錄#
查看 TAMS 執行紀錄:
sudo tail -f /Data/Log/loki-export-cron.log查看 HMI 執行紀錄:
sudo tail -f /Data/Log/loki-export-hmi-cron.log清空 Cron log 時,建議使用:
sudo truncate -s 0 /Data/Log/loki-export-cron.log
sudo truncate -s 0 /Data/Log/loki-export-hmi-cron.log不要直接刪除:
sudo rm /Data/Log/loki-export-cron.log
sudo rm /Data/Log/loki-export-hmi-cron.log若檔案被刪除後由 Cron 重新建立,檔案群組與權限可能受到 root umask 影響。
12. 驗證群組讀取權限#
確認使用者群組:
id compal確認目錄:
ls -ld \
/Data/Log \
/Data/Log/tams \
/Data/Log/hmi確認檔案:
ls -l /Data/Log/tams
ls -l /Data/Log/hmi以 compal 使用者測試讀取:
sudo -u compal \
head -n 1 \
/Data/Log/tams/"$(date --date='yesterday' '+%Y-%m-%d')".jsonl檢查路徑上每一層權限:
namei -l /Data/Log/tams13. 常用維護指令#
查看目前匯出檔案容量:
sudo du -sh /Data/Log/tams
sudo du -sh /Data/Log/hmi查看最新檔案:
ls -lht /Data/Log/tams | head
ls -lht /Data/Log/hmi | head檢查腳本語法:
sudo bash -n /opt/loki-export/fetch-backend-logs.sh測試 Loki 是否可連線:
LOKI_ADDR=http://localhost:3100 \
/usr/local/bin/logcli labels測試 HMI Loki:
LOKI_ADDR=http://172.18.35.29:3100 \
/usr/local/bin/logcli labels