#!/usr/bin/env bash # Centralized logging utilities for Proxmox helper scripts # Provides log_* functions, stdout/stderr capture, and robust error handling. # Prevent multiple sourcing [[ -n "${_LOGGER_FUNC_LOADED:-}" ]] && return _LOGGER_FUNC_LOADED=1 # ------------------------------------------------------------------------------ # Shell options – fail fast and propagate ERR through subshells # ------------------------------------------------------------------------------ set -o errexit -o nounset -o pipefail -o errtrace # ------------------------------------------------------------------------------ # Logfile preparation # ------------------------------------------------------------------------------ LOGDIR=${LOGDIR:-/var/log/proxmoxve} mkdir -p "$LOGDIR" 2>/dev/null || true SCRIPT_NAME="${SCRIPT_NAME:-$(basename "$0")}"; RUN_ID="${RUN_ID:-$(date +%Y%m%d_%H%M%S)_$$}"; LOGFILE="${LOGFILE:-$LOGDIR/${SCRIPT_NAME%.sh}_$RUN_ID.log}" LOG_LEVEL="${LOG_LEVEL:-INFO}" declare -A LEVELS=([DEBUG]=0 [INFO]=1 [WARN]=2 [ERROR]=3) # Preserve original stdout/stderr for terminal output exec 3>&1 4>&2 log_msg() { local level="$1"; shift local msg="$*" local ts ts="$(date '+%Y-%m-%d %H:%M:%S')" echo "[$ts] [$SCRIPT_NAME] [$level] $msg" >>"$LOGFILE" if (( ${LEVELS[$level]} >= ${LEVELS[$LOG_LEVEL]} )); then case "$level" in DEBUG) [[ "${var_full_verbose:-0}" -eq 1 ]] && echo -e "\033[36m[DEBUG]\033[0m $msg" >&3 ;; INFO) echo -e "\033[34m[INFO]\033[0m $msg" >&3 ;; WARN) echo -e "\033[33m[WARN]\033[0m $msg" >&3 ;; ERROR) echo -e "\033[31m[ERROR]\033[0m $msg" >&4 ;; esac fi } log_debug() { log_msg DEBUG "$*"; } log_info() { log_msg INFO "$*"; } log_warn() { log_msg WARN "$*"; } log_error() { log_msg ERROR "$*"; } # Backward compatible wrappers msg_info() { log_info "ℹ️ $*"; } msg_ok() { log_info "✅ $*"; } msg_warn() { log_warn "⚠️ $*"; } msg_error() { log_error "❌ $*"; } msg_debug() { log_debug "$*"; } # ------------------------------------------------------------------------------ # Capture arbitrary stdout/stderr (including from subshells) # ------------------------------------------------------------------------------ log_stream() { local level="$1" while IFS= read -r line; do log_msg "$level" "$line" done } # Redirect script output through logger exec > >(log_stream INFO) 2> >(log_stream ERROR) # ------------------------------------------------------------------------------ # Error handler – logs failing command, line, and exits # ------------------------------------------------------------------------------ error_handler() { local code="$?" local cmd="${BASH_COMMAND:-unknown}" local line="${BASH_LINENO[0]:-unknown}" local file="${BASH_SOURCE[1]:-unknown}" log_error "command '$cmd' failed in $file:$line with exit code $code" exit "$code" } trap error_handler ERR