← Retour
#!/bin/bash
# Sync logs depuis Loki vers O2switch (archivage cold storage)
# Cron: 0 3 * * * /stock_8to/33800-stack/scripts/logs/sync-logs-o2switch.sh
set -e
DATE=$(date -d "yesterday" +%Y-%m-%d)
LOKI_URL="http://192.168.1.12:3100"
O2SWITCH="o2switch"
REMOTE_DIR="backup/logs"
TMP_DIR="/tmp/logs-export-$$"
LOG_FILE="/var/log/sync-logs-o2switch.log"
BATCH_SIZE=1000
CURL_TIMEOUT=30
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}
cleanup() {
rm -rf "$TMP_DIR"
}
trap cleanup EXIT
mkdir -p "$TMP_DIR"
log "=== Debut sync logs $DATE vers O2switch ==="
# Fonction export logs par query Loki (avec pagination)
export_logs() {
local query="$1"
local output_path="$2"
local start="${DATE}T00:00:00Z"
local end="${DATE}T23:59:59Z"
local output_dir=$(dirname "$TMP_DIR/$output_path")
mkdir -p "$output_dir"
# Fichier de sortie
local outfile="$TMP_DIR/$output_path"
> "$outfile"
local current_start="$start"
local total_lines=0
local page=0
while true; do
page=$((page + 1))
local response=$(curl -s --max-time "$CURL_TIMEOUT" -G "$LOKI_URL/loki/api/v1/query_range" \
--data-urlencode "query=$query" \
--data-urlencode "start=$current_start" \
--data-urlencode "end=$end" \
--data-urlencode "limit=$BATCH_SIZE" \
--data-urlencode "direction=forward" 2>/dev/null)
# Verifier que la reponse est du JSON valide
if ! echo "$response" | jq -e '.status' >/dev/null 2>&1; then
log " ! $output_path: erreur Loki page $page"
break
fi
# Extraire les lignes de log
local batch_file="/tmp/loki-batch-$$"
echo "$response" | jq -r '.data.result[].values[][1]' 2>/dev/null > "$batch_file" || true
local batch_lines=$(wc -l < "$batch_file" 2>/dev/null || echo 0)
if [ "$batch_lines" -eq 0 ] || [ ! -s "$batch_file" ]; then
rm -f "$batch_file"
break
fi
cat "$batch_file" >> "$outfile"
total_lines=$((total_lines + batch_lines))
# Si on a moins que BATCH_SIZE, c'est la derniere page
if [ "$batch_lines" -lt "$BATCH_SIZE" ]; then
rm -f "$batch_file"
break
fi
# Avancer le curseur : dernier timestamp + 1 nanoseconde
local last_ts=$(echo "$response" | jq -r '.data.result[-1].values[-1][0]' 2>/dev/null)
if [ -z "$last_ts" ] || [ "$last_ts" = "null" ]; then
rm -f "$batch_file"
break
fi
current_start="$((last_ts + 1))"
rm -f "$batch_file"
done
if [ -s "$outfile" ]; then
gzip -f "$outfile"
log " OK $output_path.gz ($total_lines lignes, $page pages)"
return 0
else
rm -f "$outfile"
return 1
fi
}
# Export par host et type
log "Export des logs..."
# PVE
export_logs '{host="pve",type="system"}' "prod/pve/system/${DATE}.log" || true
export_logs '{host="pve",job="journal"}' "prod/pve/journal/${DATE}.log" || true
# Nginx
export_logs '{host="nginx",type="access"}' "prod/nginx/access/${DATE}.log" || true
export_logs '{host="nginx",type="vhost-access"}' "prod/nginx/vhost-access/${DATE}.log" || true
export_logs '{host="nginx",type="vhost-error"}' "prod/nginx/vhost-error/${DATE}.log" || true
# GitLab
export_logs '{host="gitlab",service="gitlab-rails"}' "prod/gitlab/rails/${DATE}.log" || true
export_logs '{host="gitlab",service="gitlab-nginx"}' "prod/gitlab/nginx/${DATE}.log" || true
# prod-portainer (Docker containers)
export_logs '{host="prod-portainer"}' "prod/prod-portainer/docker/${DATE}.log" || true
# dev-portainer (Docker DEV)
export_logs '{host="dev-portainer"}' "dev/dev-portainer/docker/${DATE}.log" || true
# Compter fichiers exportes
EXPORTED=$(find "$TMP_DIR" -name "*.gz" | wc -l)
log "Total: $EXPORTED fichiers exportes"
if [ "$EXPORTED" -gt 0 ]; then
# Creer structure sur O2switch
log "Sync vers O2switch..."
ssh -o ConnectTimeout=10 "$O2SWITCH" "mkdir -p ~/$REMOTE_DIR" 2>/dev/null || true
rsync -avz "$TMP_DIR/" "$O2SWITCH:~/$REMOTE_DIR/" 2>&1 | tail -5
log "=== Sync termine: $EXPORTED fichiers ==="
else
log "=== Aucun log a exporter pour $DATE ==="
fi
# Nettoyage vieux logs o2switch (> 90 jours)
log "Nettoyage logs > 90 jours sur O2switch..."
ssh -o ConnectTimeout=10 "$O2SWITCH" "find ~/$REMOTE_DIR -name '*.gz' -mtime +90 -delete 2>/dev/null" || true
log "=== Fin sync logs ==="