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