33800 Docs

← 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 ==="