Files
dotfiles/local/dfm/lib/common.sh

237 lines
6.0 KiB
Bash
Executable File

#!/usr/bin/env bash
# dfm common functions for logging and error handling, etc.
# Source this file to use the functions in your scripts.
#
# @author Ismo Vuorinen <https://github.com/ivuorinen>
# @license MIT
set -euo pipefail
declare -A ERROR_CODES=(
[SUCCESS]=0
[INVALID_ARGUMENT]=1
[COMMAND_NOT_FOUND]=2
[FUNCTION_NOT_FOUND]=3
[EXECUTION_FAILED]=4
)
declare -A LOG_LEVELS=(
[DEBUG]=0
[INFO]=1
[WARN]=2
[ERROR]=3
)
LOG_LEVEL="${LOG_LEVEL:-INFO}"
# Simple logging function
#
# @example
# lib::log "Hello, world!"
#
# @description Log a message to the console
# @param $* Message to log
# @return void
lib::log()
{
printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*"
}
# Simple error logging function
#
# @example
# lib::error "Something went wrong"
#
# @description Log an error message to the console
# @param $* Error message
# @return void
lib::error()
{
printf '[%s] ERROR: %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" >&2
}
# Handle an error by logging an error message to the console
# and exiting with an error code based on the error type.
#
# @example
# lib::error::handle $LINENO $0
#
# @description Handle an error
# @param $1 Line number
# @param $2 Command
# @return void
lib::error::handle()
{
local exit_code=$?
local line_no=$1
local command=$2
case $exit_code in
${ERROR_CODES[INVALID_ARGUMENT]})
lib::error "Invalid argument at line $line_no in command '$command'"
;;
${ERROR_CODES[COMMAND_NOT_FOUND]})
lib::error "Command not found at line $line_no"
;;
${ERROR_CODES[FUNCTION_NOT_FOUND]})
lib::error "Function not found at line $line_no in command '$command'"
;;
${ERROR_CODES[EXECUTION_FAILED]})
lib::error "Execution failed at line $line_no in command '$command'"
;;
*)
lib::error "Unknown error ($exit_code) at line $line_no in command '$command'"
;;
esac
return $exit_code
}
# Throw an error by logging an error message to the console and exiting
# with an error code based on the error type. The error code name is used
# to determine the error code from the ERROR_CODES associative array.
# The error message is passed as arguments to the function.
#
# @example
# lib::error::throw INVALID_ARGUMENT "Invalid argument"
# lib::error::throw COMMAND_NOT_FOUND "Command not found"
# lib::error::throw FUNCTION_NOT_FOUND "Function not found"
# lib::error::throw EXECUTION_FAILED "Execution failed"
#
# @description Throw an error
# @param $1 Error code name
# @param $* Error message
# @return void
lib::error::throw()
{
local code_name=$1
shift
local message=$*
lib::error "$message"
return "${ERROR_CODES[$code_name]}"
}
# Logs a message to the console if the current log level is set so that the
# message is displayed. The log level is compared to the log level of the
# message and if the message log level is greater than or equal to the current
# log level, the message is displayed.
# The log levels are defined in the LOG_LEVELS associative array.
#
# @example
# logger::log "INFO" "This is an info message"
# logger::log "DEBUG" "This is a debug message"
# logger::log "WARN" "This is a warning message"
# logger::log "ERROR" "This is an error message"
#
# @description Log a message to the console based on the log level setting.
# @param $1 Log level
# @param $2 Message
# @return void
logger::log()
{
local level=$1
shift
local msg=$1
if [[ ${LOG_LEVELS[$level]} -ge ${LOG_LEVELS[$LOG_LEVEL]} ]]; then
printf '[%s] [%s]: %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$level" "$msg" >&2
fi
}
# Logs a debug message to the console, if the current log level is set to DEBUG or greater.
# The message is passed as arguments to the function.
# The function is defined above.
#
# @example
# logger::debug "This is a debug message"
#
# @description Log a debug message to the console
# @param $* Message
# @return void
logger::debug()
{
logger::log "DEBUG" "$@"
}
# Logs an info message to the console, if the current log level is set to INFO or greater.
# The message is passed as arguments to the function.
# The function is defined above.
#
# @example
# logger::info "This is an info message"
#
# @description Log an info message to the console
# @param $* Message
# @return void
logger::info()
{
logger::log "INFO" "$@"
}
# Logs a warning message to the console, if the current log level is set to WARN or greater.
# The message is passed as arguments to the function.
# The function is defined above.
#
# @example
# logger::warn "This is a warning message"
#
# @description Log a warning message to the console
# @param $* Message
# @return void
logger::warn()
{
logger::log "WARN" "$@"
}
# Logs an error message to the console, if the current log level is set to ERROR or greater.
# The message is passed as arguments to the function.
# The function is defined above.
#
# @example
# logger::error "This is an error message"
#
# @description Log an error message to the console
# @param $* Message
# @return void
logger::error()
{
logger::log "ERROR" "$@"
}
# Cleanup function to remove temporary files and directories
# when the script exits or is interrupted by a signal (e.g. Ctrl+C).
# The function is registered with the `EXIT` trap.
#
# @description Remove temporary files and directories
# @return void
cleanup()
{
local exit_code=$?
[ -d "$TEMP_DIR" ] && rm -rf "$TEMP_DIR"
exit $exit_code
}
# Register the cleanup function to run on EXIT signal.
#
# This will ensure that temporary files and directories are removed
# when the script exits or is interrupted by a signal (e.g. Ctrl+C).
# The cleanup function is defined above.
trap cleanup EXIT
# Handle errors by logging an error message to the console.
#
# The function is registered with the `ERR` trap.
# The line number where the error occurred is passed as an argument to the function.
# The function is defined above.
#
# @description Handle an error
# @param $1 Line number
# @return void
handle_error()
{
local exit_code=$?
local line_no=$1
logger::error "Failed at line ${line_no} with exit code ${exit_code}"
}
trap 'handle_error ${LINENO}' ERR