Create joplin_server_daily_diag.sh
This commit is contained in:
349
joplin_server_daily_diag.sh
Normal file
349
joplin_server_daily_diag.sh
Normal file
@@ -0,0 +1,349 @@
|
||||
cat /home/scripts/joplin_server_daily_diag.sh
|
||||
#!/bin/bash
|
||||
|
||||
########################################
|
||||
# Rapport quotidien serveur + Discord
|
||||
# - Ping API Joplin
|
||||
# - Espace disque global
|
||||
# - Ressources CPU / RAM / top process
|
||||
# - Événements majeurs des 24h (journalctl -p 0..3)
|
||||
# - Espace disque par user Linux (/home)
|
||||
# - Espace disque par user Joplin (PostgreSQL)
|
||||
# - Envoi Discord (message + log en pièce jointe)
|
||||
########################################
|
||||
|
||||
# === CONFIG DISCORD ===
|
||||
WEBHOOK="https://discord.com/api/webhooks/1234567890000000987654321/hsagsklzjkldhfgasouihfgdhfdousahFLDSAHFOUHFJNDAFOUADHFAOUSFHDOU"
|
||||
|
||||
# Dossier de logs
|
||||
LOG_DIR="/var/log/server-daily-diag"
|
||||
mkdir -p "${LOG_DIR}"
|
||||
TS="$(date '+%Y-%m-%d_%H-%M-%S')"
|
||||
LOG_FILE="${LOG_DIR}/server_daily_diag_${TS}.log"
|
||||
|
||||
HOSTNAME="$(hostname -f 2>/dev/null || hostname)"
|
||||
|
||||
# === CONFIG PING JOPLIN ===
|
||||
JOPLIN_PING_URL="http://127.0.0.1:22300/api/ping"
|
||||
JOPLIN_HOST_HEADER="joplin.server.me"
|
||||
JOPLIN_ORIGIN_HEADER="https://joplin.server.me"
|
||||
JOPLIN_X_FORWARDED_PROTO="https"
|
||||
|
||||
# === CONFIG JOPLIN DB (PostgreSQL) ===
|
||||
ENABLE_JOPLIN_DB_STATS=1
|
||||
|
||||
JOPLIN_DB_HOST="127.0.0.1"
|
||||
JOPLIN_DB_PORT="5432"
|
||||
JOPLIN_DB_NAME="joplin"
|
||||
JOPLIN_DB_USER="joplin"
|
||||
JOPLIN_DB_PASSWORD="PASSWORDxxxXXX1233764"
|
||||
|
||||
########################################
|
||||
# PRÉREQUIS
|
||||
########################################
|
||||
|
||||
# jq est un prérequis systématique pour Discord
|
||||
if ! command -v jq >/dev/null 2>&1; then
|
||||
echo "ERREUR: jq n'est pas installé sur ce serveur."
|
||||
echo "Installe-le avant d'utiliser ce script :"
|
||||
echo " apt update -y && apt install -y jq"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
########################################
|
||||
# Variables globales pour le résumé
|
||||
########################################
|
||||
|
||||
API_STATUS="inconnu"
|
||||
ROOT_USAGE="n/a"
|
||||
LOAD_AVG="n/a"
|
||||
MEM_LINE="n/a"
|
||||
JOPLIN_USERS_SUMMARY=""
|
||||
|
||||
########################################
|
||||
# Utils
|
||||
########################################
|
||||
|
||||
log() {
|
||||
# log dans le fichier avec timestamp
|
||||
printf '[%s] %s\n' "$(date +'%Y-%m-%dT%H:%M:%S%z')" "$*" >> "${LOG_FILE}"
|
||||
}
|
||||
|
||||
human_bytes() {
|
||||
local bytes="$1"
|
||||
local units=(B KB MB GB TB PB)
|
||||
local i=0
|
||||
|
||||
if ! [[ "$bytes" =~ ^[0-9]+$ ]]; then
|
||||
echo "-"
|
||||
return
|
||||
fi
|
||||
|
||||
while [ "$bytes" -ge 1024 ] && [ "$i" -lt $(( ${#units[@]} - 1 )) ]; do
|
||||
bytes=$(( (bytes + 512) / 1024 ))
|
||||
i=$((i + 1))
|
||||
done
|
||||
|
||||
echo "${bytes}${units[$i]}"
|
||||
}
|
||||
|
||||
########################################
|
||||
# 1) Ping Joplin
|
||||
########################################
|
||||
|
||||
check_joplin() {
|
||||
log "===== Vérification Joplin Server (/api/ping) ====="
|
||||
|
||||
local response http_code status message json_body
|
||||
|
||||
response="$(curl -sS -i \
|
||||
-H "Host: ${JOPLIN_HOST_HEADER}" \
|
||||
-H "Origin: ${JOPLIN_ORIGIN_HEADER}" \
|
||||
-H "X-Forwarded-Proto: ${JOPLIN_X_FORWARDED_PROTO}" \
|
||||
"${JOPLIN_PING_URL}" || true)"
|
||||
|
||||
http_code="$(printf '%s\n' "${response}" | awk 'NR==1 {print $2}')"
|
||||
json_body="$(printf '%s\n' "${response}" | awk '/^\{/{print}')"
|
||||
status="$(printf '%s\n' "${json_body}" | jq -r '.status // empty' 2>/dev/null)"
|
||||
message="$(printf '%s\n' "${json_body}" | jq -r '.message // empty' 2>/dev/null)"
|
||||
|
||||
if [ "${http_code}" = "200" ] && [ "${status}" = "ok" ]; then
|
||||
API_STATUS="OK (${http_code}, ${message})"
|
||||
log "Joplin Server OK (HTTP ${http_code}) - ${message}"
|
||||
else
|
||||
API_STATUS="KO (${http_code:-N/A})"
|
||||
log "Joplin Server PROBLÈME (HTTP ${http_code:-N/A})"
|
||||
log "Réponse brute :"
|
||||
printf '%s\n' "${response}" | sed 's/^/ /' >> "${LOG_FILE}"
|
||||
fi
|
||||
|
||||
log ""
|
||||
}
|
||||
|
||||
########################################
|
||||
# 2) Espace disque global
|
||||
########################################
|
||||
|
||||
disk_global() {
|
||||
log "===== Espace disque global (df -hT) ====="
|
||||
df -hT >> "${LOG_FILE}" 2>&1
|
||||
log ""
|
||||
|
||||
ROOT_USAGE="$(df -h / 2>/dev/null | awk 'NR==2 {print $5 " used on " $6}')"
|
||||
[ -z "${ROOT_USAGE}" ] && ROOT_USAGE="n/a"
|
||||
}
|
||||
|
||||
########################################
|
||||
# 3) Espace disque par utilisateur Linux (/home)
|
||||
########################################
|
||||
|
||||
disk_per_linux_user() {
|
||||
log "===== Espace disque par utilisateur Linux (/home) ====="
|
||||
|
||||
if [ ! -d /home ]; then
|
||||
log "/home n'existe pas, section ignorée."
|
||||
log ""
|
||||
return
|
||||
fi
|
||||
|
||||
for dir in /home/*; do
|
||||
[ -d "${dir}" ] || continue
|
||||
user="$(basename "${dir}")"
|
||||
bytes="$(du -sb "${dir}" 2>/dev/null | awk '{print $1}')"
|
||||
human="$(human_bytes "${bytes}")"
|
||||
log "User Linux: ${user} -> ${human} (~ ${bytes:-0} B) [${dir}]"
|
||||
done
|
||||
|
||||
log ""
|
||||
}
|
||||
|
||||
########################################
|
||||
# 4) Ressources système
|
||||
########################################
|
||||
|
||||
system_resources() {
|
||||
log "===== Ressources système ====="
|
||||
|
||||
log "-- Uptime et charge --"
|
||||
uptime 2>/dev/null >> "${LOG_FILE}" 2>&1 || log "uptime indisponible"
|
||||
log ""
|
||||
|
||||
LOAD_AVG="$(awk '{print $1","$2","$3}' /proc/loadavg 2>/dev/null)"
|
||||
[ -z "${LOAD_AVG}" ] && LOAD_AVG="n/a"
|
||||
|
||||
log "-- Mémoire (free -h) --"
|
||||
free -h 2>/dev/null >> "${LOG_FILE}" || log "free indisponible"
|
||||
log ""
|
||||
|
||||
MEM_LINE="$(free -h 2>/dev/null | awk '/Mem:/ {print $3 " / " $2 " used"}')"
|
||||
[ -z "${MEM_LINE}" ] && MEM_LINE="n/a"
|
||||
|
||||
log "-- Top CPU (top 5) --"
|
||||
if command -v ps >/dev/null 2>&1; then
|
||||
ps -eo pid,user,pcpu,pmem,comm --sort=-pcpu | head -n 6 >> "${LOG_FILE}"
|
||||
else
|
||||
log "ps indisponible."
|
||||
fi
|
||||
log ""
|
||||
|
||||
log "-- Top RAM (top 5) --"
|
||||
if command -v ps >/dev/null 2>&1; then
|
||||
ps -eo pid,user,pcpu,pmem,comm --sort=-pmem | head -n 6 >> "${LOG_FILE}"
|
||||
else
|
||||
log "ps indisponible."
|
||||
fi
|
||||
log ""
|
||||
}
|
||||
|
||||
########################################
|
||||
# 5) Logs système (24h, priorité 0..3)
|
||||
########################################
|
||||
|
||||
major_events_24h() {
|
||||
log "===== Événements système majeurs (24h, journalctl -p 0..3) ====="
|
||||
|
||||
if ! command -v journalctl >/dev/null 2>&1; then
|
||||
log "journalctl non disponible, section ignorée."
|
||||
log ""
|
||||
return
|
||||
fi
|
||||
|
||||
journalctl -p 0..3 --since "24 hours ago" --no-pager 2>/dev/null | tail -n 300 >> "${LOG_FILE}"
|
||||
log ""
|
||||
}
|
||||
|
||||
########################################
|
||||
# 6) Espace disque par utilisateur Joplin
|
||||
########################################
|
||||
|
||||
joplin_per_user() {
|
||||
log "===== Espace disque par utilisateur Joplin (total_item_size) ====="
|
||||
|
||||
if [ "${ENABLE_JOPLIN_DB_STATS}" -ne 1 ]; then
|
||||
log "Section désactivée (ENABLE_JOPLIN_DB_STATS != 1)."
|
||||
log ""
|
||||
return
|
||||
fi
|
||||
|
||||
if ! command -v psql >/dev/null 2>&1; then
|
||||
log "psql introuvable, impossible de lire la base Joplin."
|
||||
log ""
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -z "${JOPLIN_DB_NAME}" ] || [ -z "${JOPLIN_DB_USER}" ]; then
|
||||
log "Config DB Joplin incomplète (nom ou user manquant)."
|
||||
log ""
|
||||
return
|
||||
fi
|
||||
|
||||
export PGPASSWORD="${JOPLIN_DB_PASSWORD}"
|
||||
|
||||
local query
|
||||
query="SELECT email, full_name, COALESCE(total_item_size,0) AS total_item_size
|
||||
FROM users
|
||||
ORDER BY total_item_size DESC;"
|
||||
|
||||
local lines
|
||||
lines="$(
|
||||
psql \
|
||||
-h "${JOPLIN_DB_HOST}" \
|
||||
-p "${JOPLIN_DB_PORT}" \
|
||||
-U "${JOPLIN_DB_USER}" \
|
||||
-d "${JOPLIN_DB_NAME}" \
|
||||
-t -A -F '|' \
|
||||
-c "${query}" 2>&1
|
||||
)"
|
||||
|
||||
if printf '%s\n' "${lines}" | grep -qi "ERROR"; then
|
||||
log "Erreur lors de la requête PostgreSQL :"
|
||||
printf '%s\n' "${lines}" | sed 's/^/ /' >> "${LOG_FILE}"
|
||||
log ""
|
||||
return
|
||||
fi
|
||||
|
||||
while IFS='|' read -r email full_name total_bytes; do
|
||||
[ -z "${email}" ] && continue
|
||||
human_size="$(human_bytes "${total_bytes}")"
|
||||
|
||||
if [ -n "${full_name}" ]; then
|
||||
line="Joplin user: ${email} (${full_name}) -> ${human_size} (~ ${total_bytes} B)"
|
||||
else
|
||||
line="Joplin user: ${email} -> ${human_size} (~ ${total_bytes} B)"
|
||||
fi
|
||||
|
||||
# Log complet
|
||||
log "${line}"
|
||||
# Résumé pour Discord
|
||||
JOPLIN_USERS_SUMMARY+="${line}"$'\n'
|
||||
|
||||
done <<< "${lines}"
|
||||
|
||||
log ""
|
||||
}
|
||||
|
||||
########################################
|
||||
# 7) Envoi sur Discord
|
||||
########################################
|
||||
|
||||
send_discord() {
|
||||
log "===== Envoi du rapport sur Discord ====="
|
||||
|
||||
# Si aucune donnée Joplin collectée
|
||||
if [ -z "${JOPLIN_USERS_SUMMARY}" ]; then
|
||||
JOPLIN_USERS_SUMMARY="(Aucune donnée Joplin ou stats désactivées)"
|
||||
fi
|
||||
|
||||
SUMMARY="🧾 Rapport Joplin serveur
|
||||
|
||||
Host : ${HOSTNAME}
|
||||
Date : $(date '+%Y-%m-%d %H:%M:%S')
|
||||
|
||||
API Joplin : ${API_STATUS}
|
||||
Disque racine : ${ROOT_USAGE}
|
||||
Charge (1/5/15min): ${LOAD_AVG}
|
||||
Mémoire : ${MEM_LINE}
|
||||
|
||||
Users:
|
||||
${JOPLIN_USERS_SUMMARY}
|
||||
|
||||
Détails complets (logs, stats Joplin & users) dans le fichier joint.
|
||||
"
|
||||
|
||||
# Sécurité limite Discord (<2000 chars)
|
||||
SUMMARY_TRIMMED="$(printf '%s\n' "${SUMMARY}" | cut -c1-1900)"
|
||||
|
||||
# Encodage JSON safe via jq -Rs
|
||||
JSON_PAYLOAD="$(printf '%s' "${SUMMARY_TRIMMED}" | jq -Rs '{content: .}')"
|
||||
|
||||
curl -sS -X POST \
|
||||
-F "payload_json=${JSON_PAYLOAD}" \
|
||||
-F "file=@${LOG_FILE};type=text/plain" \
|
||||
"${WEBHOOK}" >/dev/null || {
|
||||
echo "ERREUR: échec de l'envoi à Discord." >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
log "Rapport envoyé sur Discord (résumé + pièce jointe)."
|
||||
}
|
||||
|
||||
|
||||
########################################
|
||||
# MAIN
|
||||
########################################
|
||||
|
||||
log "===== DIAGNOSTIC QUOTIDIEN SERVEUR JOPLIN ====="
|
||||
log "Date : $(date '+%Y-%m-%d %H:%M:%S %z')"
|
||||
log ""
|
||||
|
||||
check_joplin
|
||||
disk_global
|
||||
disk_per_linux_user
|
||||
system_resources
|
||||
major_events_24h
|
||||
joplin_per_user
|
||||
send_discord
|
||||
|
||||
log "===== FIN DIAGNOSTIC ====="
|
||||
|
||||
exit 0
|
||||
Reference in New Issue
Block a user