#!/usr/bin/env bash # ============================================ # Core # ============================================ LOG_LEVEL=${LOG_LEVEL:-INFO} # ============================================ # Internal # ============================================ function internal::get_log_priority() { case "$1" in DEBUG) echo 0 ;; INFO) echo 1 ;; SUCCESS) echo 1 ;; OK) echo 1 ;; WARN) echo 2 ;; ERROR) echo 3 ;; *) echo 1 ;; esac } function internal::log() { local level="$1" shift # Quiet mode — suppress INFO and SUCCESS if core::is_quiet; then case "$level" in INFO|SUCCESS) return 0 ;; esac fi local current_priority local message_priority current_priority=$(internal::get_log_priority "$LOG_LEVEL") message_priority=$(internal::get_log_priority "$level") if (( message_priority < current_priority )); then return 0 fi local color case "$level" in DEBUG) color="\033[0;36m" ;; INFO) color="\033[1;34m" ;; WARN) color="\033[1;33m" ;; ERROR) color="\033[1;31m" ;; SUCCESS) color="\033[1;32m" ;; OK) color="\033[1;32m" ;; esac echo -e "${color}=> ${level}:\033[0m $*" } function internal::icon() { local context="$1" local action="$2" case "$context:$action" in docker:log) echo "🐳 " ;; docker:start) echo "🟢 🐳 " ;; docker:stop) echo "🔴 🐳 " ;; docker:success) echo "✅ 🐳 " ;; docker:warning) echo "⚠️ 🐳 " ;; docker:error) echo "❌ 🐳 " ;; docker:logs) echo "📜 🐳 " ;; docker:list) echo "🔍 🐳 " ;; docker:build) echo "📦 🐳 " ;; build:log) echo "🏗️ " ;; build:start) echo "🟢 🏗️ " ;; build:stop) echo "🔴 🏗️ " ;; build:success) echo "✅ 🏗️ " ;; build:warning) echo "⚠️ 🏗️ " ;; build:error) echo "❌ 🏗️ " ;; network:log) echo "🌐 " ;; network:setup) echo "⚙️ 🌐 " ;; network:stop) echo "🔴 🌐 " ;; network:success) echo "✅ 🌐 " ;; network:warning) echo "⚠️ 🌐 " ;; network:error) echo "❌ 🌐 " ;; auth:log) echo "🔑 " ;; auth:setup) echo "⚙️ 🔑 " ;; auth:login) echo "🔐 🔑 " ;; auth:success) echo "✅ 🔑 " ;; auth:warning) echo "⚠️ 🔑 " ;; auth:error) echo "❌ 🔑 " ;; env:log) echo "⚙️ " ;; env:load) echo "📥 ⚙️ " ;; env:success) echo "✅ ⚙️ " ;; env:warning) echo "⚠️ ⚙️ " ;; env:error) echo "❌ ⚙️ " ;; fs:log) echo "📁 " ;; fs:read) echo "📥 📁 " ;; fs:write) echo "📤 📁 " ;; fs:success) echo "✅ 📁 " ;; fs:warning) echo "⚠️ 📁 " ;; fs:error) echo "❌ 📁 " ;; db:log) echo "🗄️ " ;; db:start) echo "🟢 🗄️ " ;; db:migrate) echo "📜 🗄️ " ;; db:success) echo "✅ 🗄️ " ;; db:warning) echo "⚠️ 🗄️ " ;; db:error) echo "❌ 🗄️ " ;; wg:log) echo "🔒 " ;; wg:start) echo "🟢 🔒 " ;; wg:stop) echo "🔴 🔒 " ;; wg:add) echo "➕ 🔒 " ;; wg:remove) echo "➖ 🔒 " ;; wg:block) echo "🚫 🔒 " ;; wg:unblock) echo "🔓 🔒 " ;; wg:key) echo "🔑 🔒 " ;; wg:success) echo "✅ 🔒 " ;; wg:warning) echo "⚠️ 🔒 " ;; wg:error) echo "❌ 🔒 " ;; wg:list) echo "🔍 🔒 " ;; wg:qr) echo "📱 🔒 " ;; wg:preset) echo "📋 🔒 " ;; log:info) echo "🔹 " ;; log:warn) echo "⚠️ " ;; log:error) echo "❌ " ;; log:success) echo "✅ " ;; log:debug) echo "🔍 " ;; *) echo "🔹" ;; esac } function internal::get_context_icon() { case "$1" in docker) echo "🐳" ;; build) echo "🏗️" ;; network) echo "🌐" ;; auth) echo "🔑" ;; env) echo "⚙️" ;; fs) echo "📁" ;; db) echo "🗄️" ;; wg) echo "🔒" ;; log) echo "🔹" ;; *) echo "🔹" ;; esac } # ============================================ # Profiler # ============================================ declare -gi _PROFILE_T0=0 function log::profile_start() { _PROFILE_T0=$(date +%s%3N) } function log::profile() { [[ "${LOG_LEVEL:-2}" -gt 0 ]] && return 0 local label="${1:-checkpoint}" local now now=$(date +%s%3N) printf " \033[2m[profile] %s: %dms\033[0m\n" \ "$label" "$(( now - _PROFILE_T0 ))" >&2 _PROFILE_T0=$now # reset for next checkpoint } # ============================================ # Loggers # ============================================ function internal::log::info() { internal::log INFO "$*"; } function internal::log::warn() { internal::log WARN "$*"; } function internal::log::error() { internal::log ERROR "$*"; } function internal::log::success() { internal::log OK "$*"; } function internal::log::debug() { internal::log DEBUG "$*"; } # ============================================ # Context Loggers # ============================================ function log::context() { local context="$1" action="$2" shift 2 internal::log::info "$(internal::icon "$context" "$action") $*" } function log::warn_context() { local context="$1" action="$2" shift 2 internal::log::warn "$(internal::icon "$context" "$action") $*" } function log::error_context() { local context="$1" action="$2" shift 2 internal::log::error "$(internal::icon "$context" "$action") $*" } function log::success_context() { local context="$1" action="$2" shift 2 internal::log::success "$(internal::icon "$context" "$action") $*" } function log::debug_context() { local context="$1" action="$2" shift 2 internal::log::debug "$(internal::icon "$context" "$action") $*" } # ============================================ # Logger Helpers # ============================================ function log::info() { log::context log info "$@"; } function log::warn() { log::warn_context log warn "$@"; } function log::error() { log::error_context log error "$@"; } function log::ok() { internal::log OK "$@"; } function log::success() { log::ok "$@"; } function log::debug() { log::debug_context log debug "$@"; } function log::section() { core::is_quiet && return 0 local label="$1" local width=48 local line line=$(printf '─%.0s' $(seq 1 $width)) echo -e "\n\033[1;34m${line}\033[0m" echo -e "\033[1;34m $label\033[0m" echo -e "\033[1;34m${line}\033[0m" } # ============================================ # Docker # ============================================ function log::docker() { log::context docker log "$@"; } function log::docker_start() { log::context docker start "$@"; } function log::docker_stop() { log::context docker stop "$@"; } function log::docker_success() { log::success_context docker success "$@"; } function log::docker_logs() { log::context docker logs "$@"; } function log::docker_list() { log::context docker list "$@"; } function log::docker_build() { log::context docker build "$@"; } function log::docker_warning() { log::warn_context docker warning "$@"; } function log::docker_error() { log::error_context docker error "$@"; } # ============================================ # Build # ============================================ function log::build() { log::context build log "$@"; } function log::build_start() { log::context build start "$@"; } function log::build_stop() { log::context build stop "$@"; } function log::build_success() { log::success_context build success "$@"; } function log::build_warning() { log::warn_context build warning "$@"; } function log::build_error() { log::error_context build error "$@"; } # ============================================ # Network # ============================================ function log::network() { log::context network log "$@"; } function log::network_setup() { log::context network setup "$@"; } function log::network_stop() { log::context network stop "$@"; } function log::network_success() { log::success_context network success "$@"; } function log::network_warning() { log::warn_context network warning "$@"; } function log::network_error() { log::error_context network error "$@"; } # ============================================ # Auth # ============================================ function log::auth() { log::context auth log "$@"; } function log::auth_setup() { log::context auth setup "$@"; } function log::auth_login() { log::context auth login "$@"; } function log::auth_success() { log::success_context auth success "$@"; } function log::auth_warning() { log::warn_context auth warning "$@"; } function log::auth_error() { log::error_context auth error "$@"; } # ============================================ # Env # ============================================ function log::env() { log::context env log "$@"; } function log::env_load() { log::context env load "$@"; } function log::env_success() { log::success_context env success "$@"; } function log::env_warning() { log::warn_context env warning "$@"; } function log::env_error() { log::error_context env error "$@"; } # ============================================ # Filesystem # ============================================ function log::fs() { log::context fs log "$@"; } function log::fs_read() { log::context fs read "$@"; } function log::fs_write() { log::context fs write "$@"; } function log::fs_success() { log::success_context fs success "$@"; } function log::fs_warning() { log::warn_context fs warning "$@"; } function log::fs_error() { log::error_context fs error "$@"; } # ============================================ # Database # ============================================ function log::db() { log::context db log "$@"; } function log::db_start() { log::context db start "$@"; } function log::db_migrate() { log::context db migrate "$@"; } function log::db_success() { log::success_context db success "$@"; } function log::db_warning() { log::warn_context db warning "$@"; } function log::db_error() { log::error_context db error "$@"; } # ============================================ # WireGuard # ============================================ function log::wg() { log::context wg log "$@"; } function log::wg_start() { log::context wg start "$@"; } function log::wg_stop() { log::context wg stop "$@"; } function log::wg_add() { log::context wg add "$@"; } function log::wg_remove() { log::context wg remove "$@"; } function log::wg_key() { log::context wg key "$@"; } function log::wg_list() { log::context wg list "$@"; } function log::wg_qr() { log::context wg qr "$@"; } function log::wg_preset() { log::context wg preset "$@"; } function log::wg_success() { log::success_context wg success "$@"; } function log::wg_warning() { log::warn_context wg warning "$@"; } function log::wg_error() { log::error_context wg error "$@"; } function log::wg_block() { log::context wg block "$@" } function log::wg_unblock() { log::context wg unblock "$@" } # ============================================ # Run Step # ============================================ function log::run_step() { local context="$1" local mode="strict" local description shift if [[ "$1" == "soft" || "$1" == "strict" || "$1" == "info" ]]; then mode="$1" shift fi description="$1" shift local icon icon=$(internal::get_context_icon "$context") if [[ "$mode" == "info" ]]; then internal::log::info "$icon $description" else internal::log::info "🔄 $icon $description" fi "$@" local status=$? if [[ $status -eq 0 ]]; then [[ "$mode" == "info" ]] && return 0 internal::log::success "✅ $icon $description" return 0 fi if [[ "$mode" == "soft" || "$mode" == "info" ]]; then internal::log::warn "⚠️ $icon $description → skipped" return 0 fi internal::log::error "❌ $icon $description → failed" return $status }