714 lines
24 KiB
Bash
714 lines
24 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
# ==============================================================================
|
|
# NDD Log4B -- A simple logger library for Bash.
|
|
#
|
|
# Copyright 2020 David DIDIER - All Rights Reserved
|
|
# Released under the MIT license (https://opensource.org/licenses/MIT)
|
|
#
|
|
# Author - David DIDIER
|
|
# Repository - https://gitlab.com/ddidier/bash-ndd-log4b
|
|
# Version - 0.3.0
|
|
# ------------------------------------------------------------------------------
|
|
#
|
|
# See https://gitlab.com/ddidier/bash-ndd-log4b for more details.
|
|
#
|
|
# ==============================================================================
|
|
|
|
set -o pipefail # trace ERR through pipes
|
|
set -o errtrace # trace ERR through 'time command' and other functions
|
|
set -o nounset # set -u : exit the script if you try to use an uninitialised variable
|
|
set -o errexit # set -e : exit the script if any statement returns a non-true return value
|
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Avoid sourcing this library more than one time
|
|
if [[ -n "${NDD_LOG4B_SOURCED+x}" ]] && [[ ${NDD_LOG4B_SOURCED} ]]; then
|
|
return 0
|
|
fi
|
|
|
|
NDD_LOG4B_SOURCED=true
|
|
|
|
|
|
|
|
|
|
|
|
# =============================================================== settings =====
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# The color palette
|
|
#
|
|
_NDD_LOG4B_COLOR_RED=255,0,0
|
|
_NDD_LOG4B_COLOR_ORANGE=255,127,0
|
|
_NDD_LOG4B_COLOR_YELLOW=255,255,0
|
|
_NDD_LOG4B_COLOR_GREEN=0,255,0
|
|
_NDD_LOG4B_COLOR_BLUE=0,128,255
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# The ordered logger levels.
|
|
declare -a NDD_LOG4B_LEVEL_NAMES
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# The logger levels display names.
|
|
declare -A NDD_LOG4B_LEVEL_DISPLAY_NAMES
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# The logger levels synonyms.
|
|
declare -A NDD_LOG4B_LEVEL_SYNONYMS
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# The logger levels priorities (note that DISABLED = -1).
|
|
declare -A NDD_LOG4B_LEVEL_VALUES
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# The logger levels look and feels as 'ansi' arguments.
|
|
declare -A NDD_LOG4B_LEVEL_ANSI_ARGS
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# The settings of the stdout logger.
|
|
|
|
# The default level of the stdout appender
|
|
NDD_LOG4B_STDOUT_DEFAULT_LEVEL="WARNING"
|
|
# The default date format of the stdout appender ('date' command format)
|
|
NDD_LOG4B_STDOUT_DEFAULT_DATE_FORMAT="+%F %T"
|
|
# The message format of the stdout appender ('printf' command format)
|
|
# The accepted arguments are: date-time (%s), level (%s), message (%s)
|
|
NDD_LOG4B_STDOUT_DEFAULT_LOG_FORMAT="%s [%-5s] %s"
|
|
|
|
# The level of the stdout appender.
|
|
# This is a private variable. Use ndd::logger::set_stdout_level instead.
|
|
_NDD_LOG4B_STDOUT_LEVEL="${NDD_LOG4B_STDOUT_DEFAULT_LEVEL}"
|
|
# The date format of the stdout appender ('date' command format).
|
|
# This is a private variable. Use ndd::logger::set_stdout_date_format instead.
|
|
_NDD_LOG4B_STDOUT_DATE_FORMAT="${NDD_LOG4B_STDOUT_DEFAULT_DATE_FORMAT}"
|
|
# The message format of the stdout appender ('printf' command format).
|
|
# This is a private variable. Use ndd::logger::set_stdout_log_format instead.
|
|
_NDD_LOG4B_STDOUT_LOG_FORMAT="${NDD_LOG4B_STDOUT_DEFAULT_LOG_FORMAT}"
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# The settings of the file logger.
|
|
|
|
# The default level of the stdout appender
|
|
NDD_LOG4B_FILE_DEFAULT_LEVEL="DISABLED"
|
|
# The default date format of the stdout appender ('date' command format)
|
|
NDD_LOG4B_FILE_DEFAULT_DATE_FORMAT="+%F %T"
|
|
# The default message format of the file appender ('printf' command format)
|
|
# The accepted arguments are: date-time (%s), level (%s), message (%s)
|
|
NDD_LOG4B_FILE_DEFAULT_LOG_FORMAT="%s [%-5s] %s"
|
|
|
|
# The level of the file appender.
|
|
# This is a private variable. Use ndd::logger::set_file_level instead.
|
|
_NDD_LOG4B_FILE_LEVEL="${NDD_LOG4B_FILE_DEFAULT_LEVEL}"
|
|
# The date format of the file appender ('date' command format).
|
|
# This is a private variable. Use ndd::logger::set_file_date_format instead.
|
|
_NDD_LOG4B_FILE_DATE_FORMAT="${NDD_LOG4B_FILE_DEFAULT_DATE_FORMAT}"
|
|
# The message format of the file appender ('printf' command format).
|
|
# The accepted arguments are: date-time (%s), level (%s), message (%s).
|
|
# This is a private variable. Use ndd::logger::set_file_log_format instead.
|
|
_NDD_LOG4B_FILE_LOG_FORMAT="${NDD_LOG4B_FILE_DEFAULT_LOG_FORMAT}"
|
|
# The file path of the file appender.
|
|
# This is a private variable. Use ndd::logger::set_file_path instead.
|
|
_NDD_LOG4B_FILE_PATH=
|
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# A profile supporting RFC 5424:
|
|
#
|
|
# 0 - Emergency - system is unusable
|
|
# 1 - Alert - action must be taken immediately
|
|
# 2 - Critical - critical conditions
|
|
# 3 - Error - error conditions
|
|
# 4 - Warning - warning conditions
|
|
# 5 - Notice - normal but significant condition
|
|
# 6 - Informational - informational messages
|
|
# 7 - Debug - debug-level messages
|
|
#
|
|
function ndd::logger::profiles::use_rfc_5424() {
|
|
|
|
ndd::logger::profiles::_reset_levels
|
|
|
|
# The ordered logger levels.
|
|
NDD_LOG4B_LEVEL_NAMES[0]=EMERGENCY
|
|
NDD_LOG4B_LEVEL_NAMES[1]=ALERT
|
|
NDD_LOG4B_LEVEL_NAMES[2]=CRITICAL
|
|
NDD_LOG4B_LEVEL_NAMES[3]=ERROR
|
|
NDD_LOG4B_LEVEL_NAMES[4]=WARNING
|
|
NDD_LOG4B_LEVEL_NAMES[5]=NOTICE
|
|
NDD_LOG4B_LEVEL_NAMES[6]=INFORMATION
|
|
NDD_LOG4B_LEVEL_NAMES[7]=DEBUG
|
|
|
|
# The logger levels display names.
|
|
NDD_LOG4B_LEVEL_DISPLAY_NAMES["EMERGENCY"]="EMERG"
|
|
NDD_LOG4B_LEVEL_DISPLAY_NAMES["ALERT"]="ALERT"
|
|
NDD_LOG4B_LEVEL_DISPLAY_NAMES["CRITICAL"]="CRIT"
|
|
NDD_LOG4B_LEVEL_DISPLAY_NAMES["ERROR"]="ERROR"
|
|
NDD_LOG4B_LEVEL_DISPLAY_NAMES["WARNING"]="WARN"
|
|
NDD_LOG4B_LEVEL_DISPLAY_NAMES["NOTICE"]="NOTIC"
|
|
NDD_LOG4B_LEVEL_DISPLAY_NAMES["INFORMATION"]="INFO"
|
|
NDD_LOG4B_LEVEL_DISPLAY_NAMES["DEBUG"]="DEBUG"
|
|
|
|
# The logger levels synonyms.
|
|
NDD_LOG4B_LEVEL_SYNONYMS["EMERG"]="EMERGENCY"
|
|
NDD_LOG4B_LEVEL_SYNONYMS["CRIT"]="CRITICAL"
|
|
NDD_LOG4B_LEVEL_SYNONYMS["WARN"]="WARNING"
|
|
NDD_LOG4B_LEVEL_SYNONYMS["INFO"]="INFORMATION"
|
|
|
|
# The logger levels priorities (note that DISABLED = -1).
|
|
NDD_LOG4B_LEVEL_VALUES["DISABLED"]=-1
|
|
NDD_LOG4B_LEVEL_VALUES["EMERGENCY"]=0
|
|
NDD_LOG4B_LEVEL_VALUES["ALERT"]=1
|
|
NDD_LOG4B_LEVEL_VALUES["CRITICAL"]=2
|
|
NDD_LOG4B_LEVEL_VALUES["ERROR"]=3
|
|
NDD_LOG4B_LEVEL_VALUES["WARNING"]=4
|
|
NDD_LOG4B_LEVEL_VALUES["NOTICE"]=5
|
|
NDD_LOG4B_LEVEL_VALUES["INFORMATION"]=6
|
|
NDD_LOG4B_LEVEL_VALUES["DEBUG"]=7
|
|
|
|
# The logger levels look and feels as ansi arguments.
|
|
NDD_LOG4B_LEVEL_ANSI_ARGS["EMERGENCY"]=" --black --bg-rgb=${_NDD_LOG4B_COLOR_RED} --bold"
|
|
NDD_LOG4B_LEVEL_ANSI_ARGS["ALERT"]=" --black --bg-rgb=${_NDD_LOG4B_COLOR_ORANGE} --bold"
|
|
NDD_LOG4B_LEVEL_ANSI_ARGS["CRITICAL"]=" --black --bg-rgb=${_NDD_LOG4B_COLOR_YELLOW} --bold"
|
|
NDD_LOG4B_LEVEL_ANSI_ARGS["ERROR"]=" --rgb=${_NDD_LOG4B_COLOR_RED}"
|
|
NDD_LOG4B_LEVEL_ANSI_ARGS["WARNING"]=" --rgb=${_NDD_LOG4B_COLOR_ORANGE}"
|
|
NDD_LOG4B_LEVEL_ANSI_ARGS["NOTICE"]=" --rgb=${_NDD_LOG4B_COLOR_YELLOW}"
|
|
NDD_LOG4B_LEVEL_ANSI_ARGS["INFORMATION"]="--rgb=${_NDD_LOG4B_COLOR_GREEN}"
|
|
NDD_LOG4B_LEVEL_ANSI_ARGS["DEBUG"]=" --rgb=${_NDD_LOG4B_COLOR_BLUE}"
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# A profile supporting Log4J levels:
|
|
#
|
|
# - Fatal
|
|
# - Error
|
|
# - Warning
|
|
# - Information
|
|
# - Debug
|
|
# - Trace
|
|
#
|
|
function ndd::logger::profiles::use_log4j() {
|
|
|
|
ndd::logger::profiles::_reset_levels
|
|
|
|
# The ordered logger levels.
|
|
NDD_LOG4B_LEVEL_NAMES[0]=FATAL
|
|
NDD_LOG4B_LEVEL_NAMES[1]=ERROR
|
|
NDD_LOG4B_LEVEL_NAMES[2]=WARNING
|
|
NDD_LOG4B_LEVEL_NAMES[3]=INFORMATION
|
|
NDD_LOG4B_LEVEL_NAMES[4]=DEBUG
|
|
NDD_LOG4B_LEVEL_NAMES[5]=TRACE
|
|
|
|
# The logger levels display names.
|
|
NDD_LOG4B_LEVEL_DISPLAY_NAMES["FATAL"]="FATAL"
|
|
NDD_LOG4B_LEVEL_DISPLAY_NAMES["ERROR"]="ERROR"
|
|
NDD_LOG4B_LEVEL_DISPLAY_NAMES["WARNING"]="WARN"
|
|
NDD_LOG4B_LEVEL_DISPLAY_NAMES["INFORMATION"]="INFO"
|
|
NDD_LOG4B_LEVEL_DISPLAY_NAMES["DEBUG"]="DEBUG"
|
|
NDD_LOG4B_LEVEL_DISPLAY_NAMES["TRACE"]="TRACE"
|
|
|
|
# The logger levels synonyms.
|
|
NDD_LOG4B_LEVEL_SYNONYMS["WARN"]="WARNING"
|
|
NDD_LOG4B_LEVEL_SYNONYMS["INFO"]="INFORMATION"
|
|
|
|
# The logger levels priorities (note that DISABLED = -1).
|
|
NDD_LOG4B_LEVEL_VALUES["DISABLED"]=-1
|
|
NDD_LOG4B_LEVEL_VALUES["FATAL"]=0
|
|
NDD_LOG4B_LEVEL_VALUES["ERROR"]=1
|
|
NDD_LOG4B_LEVEL_VALUES["WARNING"]=2
|
|
NDD_LOG4B_LEVEL_VALUES["INFORMATION"]=3
|
|
NDD_LOG4B_LEVEL_VALUES["DEBUG"]=4
|
|
NDD_LOG4B_LEVEL_VALUES["TRACE"]=5
|
|
|
|
# The logger levels look and feels as ansi arguments.
|
|
NDD_LOG4B_LEVEL_ANSI_ARGS["FATAL"]=" --black --bold --bg-red"
|
|
NDD_LOG4B_LEVEL_ANSI_ARGS["ERROR"]=" --red --bold"
|
|
NDD_LOG4B_LEVEL_ANSI_ARGS["WARNING"]=" --yellow --bold"
|
|
NDD_LOG4B_LEVEL_ANSI_ARGS["INFORMATION"]="--white-intense --bold"
|
|
NDD_LOG4B_LEVEL_ANSI_ARGS["DEBUG"]=""
|
|
NDD_LOG4B_LEVEL_ANSI_ARGS["TRACE"]=""
|
|
# The old look and feel with too many colors:
|
|
# NDD_LOG4B_LEVEL_ANSI_ARGS["FATAL"]=" --black --bg-rgb=${_NDD_LOG4B_COLOR_RED} --bold"
|
|
# NDD_LOG4B_LEVEL_ANSI_ARGS["ERROR"]=" --rgb=${_NDD_LOG4B_COLOR_RED}"
|
|
# NDD_LOG4B_LEVEL_ANSI_ARGS["WARNING"]=" --rgb=${_NDD_LOG4B_COLOR_ORANGE}"
|
|
# NDD_LOG4B_LEVEL_ANSI_ARGS["INFORMATION"]="--rgb=${_NDD_LOG4B_COLOR_YELLOW}"
|
|
# NDD_LOG4B_LEVEL_ANSI_ARGS["DEBUG"]=" --rgb=${_NDD_LOG4B_COLOR_GREEN}"
|
|
# NDD_LOG4B_LEVEL_ANSI_ARGS["TRACE"]=" --rgb=${_NDD_LOG4B_COLOR_BLUE}"
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# A profile enabling JSON output on stdout.
|
|
#
|
|
# Globals:
|
|
# _NDD_LOG4B_STDOUT_DATE_FORMAT
|
|
# _NDD_LOG4B_STDOUT_LOG_FORMAT
|
|
#
|
|
function ndd::logger::profile::use_json_for_stdout() {
|
|
_NDD_LOG4B_STDOUT_DATE_FORMAT="+%s"
|
|
_NDD_LOG4B_STDOUT_LOG_FORMAT='{"timestamp":"%s","level":"%s","message":"%s"}'
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# A profile enabling JSON output to the file.
|
|
#
|
|
# Globals:
|
|
# _NDD_LOG4B_FILE_DATE_FORMAT
|
|
# _NDD_LOG4B_FILE_LOG_FORMAT
|
|
#
|
|
function ndd::logger::profile::use_json_for_file() {
|
|
_NDD_LOG4B_FILE_DATE_FORMAT="+%s"
|
|
_NDD_LOG4B_FILE_LOG_FORMAT='{"timestamp":"%s","level":"%s","message":"%s"}'
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Reset the current profile.
|
|
# Must be called before redefining the levels.
|
|
#
|
|
function ndd::logger::profiles::_reset_levels() {
|
|
|
|
for i in "${!NDD_LOG4B_LEVEL_NAMES[@]}"; do
|
|
unset NDD_LOG4B_LEVEL_NAMES["$i"]
|
|
done
|
|
|
|
for i in "${!NDD_LOG4B_LEVEL_DISPLAY_NAMES[@]}"; do
|
|
unset NDD_LOG4B_LEVEL_DISPLAY_NAMES["$i"]
|
|
done
|
|
|
|
for i in "${!NDD_LOG4B_LEVEL_SYNONYMS[@]}"; do
|
|
unset NDD_LOG4B_LEVEL_SYNONYMS["$i"]
|
|
done
|
|
|
|
for i in "${!NDD_LOG4B_LEVEL_VALUES[@]}"; do
|
|
unset NDD_LOG4B_LEVEL_VALUES["$i"]
|
|
done
|
|
|
|
for i in "${!NDD_LOG4B_LEVEL_ANSI_ARGS[@]}"; do
|
|
unset NDD_LOG4B_LEVEL_ANSI_ARGS["$i"]
|
|
done
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# This is the default profile
|
|
ndd::logger::profiles::use_log4j
|
|
|
|
|
|
|
|
|
|
|
|
# ======================================================= public functions =====
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Log the given message at the given level if active.
|
|
# See ndd::logger::log()
|
|
#
|
|
function log() {
|
|
ndd::logger::log "${@}"
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Log the given message at the given level if active.
|
|
#
|
|
# Globals:
|
|
# NDD_LOG4B_LEVEL_VALUES
|
|
#
|
|
# Arguments:
|
|
# @level_name - the logger level to use
|
|
# @varargs... - the format and arguments in the 'printf' style
|
|
#
|
|
# Example:
|
|
# log error "This is a %-11s log message" "ERROR"
|
|
#
|
|
function ndd::logger::log() {
|
|
|
|
local level_name="${1}"
|
|
level_name="$(ndd::logger::_normalize_level "${level_name}")"
|
|
level_value=${NDD_LOG4B_LEVEL_VALUES[$level_name]}
|
|
|
|
ndd::logger::_log_to_stdout "${level_name}" ${level_value} "${@:2}"
|
|
ndd::logger::_log_to_file "${level_name}" ${level_value} "${@:2}"
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Conveniently print all the logging levels with their look and feel.
|
|
#
|
|
# Globals:
|
|
# NDD_LOG4B_LEVEL_NAMES
|
|
# NDD_LOG4B_LEVEL_VALUES
|
|
#
|
|
# Arguments:
|
|
# None
|
|
#
|
|
# Outputs:
|
|
# Print all the logging levels with their look and feel to stdout
|
|
#
|
|
function ndd::logger::print_levels() {
|
|
|
|
if ! command -v ansi::isAnsiSupported > /dev/null; then
|
|
echo "Source the 'ansi' library (https://github.com/fidian/ansi/) to add colors!"
|
|
fi
|
|
|
|
for level_name in "${NDD_LOG4B_LEVEL_NAMES[@]}"; do
|
|
local level_value="${NDD_LOG4B_LEVEL_VALUES[$level_name]}"
|
|
local message
|
|
|
|
message="$(ndd::logger::_colorize_for_level "${level_name}" " Some text as example ")"
|
|
|
|
printf "%s %-11s %s\n" "${level_value}" "${level_name}" "${message}"
|
|
done
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Set the date format of the file appender.
|
|
#
|
|
# Globals:
|
|
# _NDD_LOG4B_FILE_DATE_FORMAT
|
|
#
|
|
# Arguments:
|
|
# @date_format - the date format to set
|
|
#
|
|
function ndd::logger::set_file_date_format() {
|
|
local date_format="${1}"
|
|
_NDD_LOG4B_FILE_DATE_FORMAT="${date_format}"
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Set the level of the file appender. The level name is normalized.
|
|
#
|
|
# Globals:
|
|
# _NDD_LOG4B_FILE_LEVEL
|
|
#
|
|
# Arguments:
|
|
# @level_name - the logger level to set
|
|
#
|
|
function ndd::logger::set_file_level() {
|
|
local level_name="${1}"
|
|
_NDD_LOG4B_FILE_LEVEL="$(ndd::logger::_normalize_level "${level_name}")"
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Set the level of the file appender.
|
|
#
|
|
# Globals:
|
|
# _NDD_LOG4B_FILE_LOG_FORMAT
|
|
#
|
|
# Arguments:
|
|
# @log_format - the log format to set
|
|
#
|
|
function ndd::logger::set_file_log_format() {
|
|
local log_format="${1}"
|
|
_NDD_LOG4B_FILE_LOG_FORMAT="${log_format}"
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Set the path of the file appender.
|
|
#
|
|
# Globals:
|
|
# _NDD_LOG4B_FILE_PATH
|
|
#
|
|
# Arguments:
|
|
# @log_format - the log format to set
|
|
#
|
|
function ndd::logger::set_file_path() {
|
|
local file_path="${1}"
|
|
_NDD_LOG4B_FILE_PATH="${file_path}"
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Set the date format of the stdout appender.
|
|
#
|
|
# Globals:
|
|
# _NDD_LOG4B_STDOUT_DATE_FORMAT
|
|
#
|
|
# Arguments:
|
|
# @date_format - the date format to set
|
|
#
|
|
function ndd::logger::set_stdout_date_format() {
|
|
local date_format="${1}"
|
|
_NDD_LOG4B_STDOUT_DATE_FORMAT="${date_format}"
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Set the level of the stdout appender. The level name is normalized.
|
|
#
|
|
# Globals:
|
|
# _NDD_LOG4B_STDOUT_LEVEL
|
|
#
|
|
# Arguments:
|
|
# @level_name - the logger level to set
|
|
#
|
|
function ndd::logger::set_stdout_level() {
|
|
local level_name="${1}"
|
|
_NDD_LOG4B_STDOUT_LEVEL="$(ndd::logger::_normalize_level "${level_name}")"
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Set the level of the stdout appender. The level name is normalized.
|
|
#
|
|
# Globals:
|
|
# _NDD_LOG4B_STDOUT_LOG_FORMAT
|
|
#
|
|
# Arguments:
|
|
# @log_format - the log format to set
|
|
#
|
|
function ndd::logger::set_stdout_log_format() {
|
|
local log_format="${1}"
|
|
_NDD_LOG4B_STDOUT_LOG_FORMAT="${log_format}"
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# ====================================================== private functions =====
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Colorize the given message according to the given level configuration.
|
|
# This is a private function.
|
|
#
|
|
# Globals:
|
|
# NDD_LOG4B_LEVEL_ANSI_ARGS
|
|
#
|
|
# Arguments:
|
|
# @level_name - the logger level to use (see NDD_LOG4B_LEVEL_NAMES)
|
|
# @message - the message to colorize
|
|
#
|
|
# Outputs:
|
|
# Print the colorized (or not) message to stdout
|
|
#
|
|
function ndd::logger::_colorize_for_level() {
|
|
local level_name="${1}"
|
|
local message="${2}"
|
|
|
|
local ansi_args="${NDD_LOG4B_LEVEL_ANSI_ARGS[$level_name]}"
|
|
|
|
ndd::logger::_colorize_with_ansi "${ansi_args}" "${message}"
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Colorize the given message according to the given 'ansi' arguments if 'ansi"
|
|
# is present and supported.
|
|
# This is a private function.
|
|
#
|
|
# Arguments:
|
|
# @ansi_args - the ansi arguments to apply
|
|
# @message - the message to colorize
|
|
#
|
|
# Outputs:
|
|
# Print the colorized (or not) message to stdout
|
|
#
|
|
function ndd::logger::_colorize_with_ansi() {
|
|
local ansi_args="${1}"
|
|
local message="${2}"
|
|
|
|
# check if 'ansi' is present and if this is a TTY
|
|
if command -v ansi::isAnsiSupported > /dev/null && ansi::isAnsiSupported; then
|
|
# shellcheck disable=2086
|
|
ansi ${ansi_args} "${message}"
|
|
else
|
|
echo "${message}"
|
|
fi
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Log the given message to a text file at the given level if active.
|
|
# This is a private function.
|
|
#
|
|
# Globals:
|
|
# NDD_LOG4B_LEVEL_VALUES
|
|
# _NDD_LOG4B_FILE_DATE_FORMAT
|
|
# _NDD_LOG4B_FILE_LEVEL
|
|
# _NDD_LOG4B_FILE_PATH
|
|
#
|
|
# Arguments:
|
|
# @level_name - the logger level to use
|
|
# @level_value - the logger level to use
|
|
# @varargs... - the format and arguments in the 'printf' style
|
|
#
|
|
# Example:
|
|
# log error "This is a %-11s log message" "ERROR"
|
|
#
|
|
function ndd::logger::_log_to_file() {
|
|
|
|
local level_name="${1}"
|
|
local level_value="${2}"
|
|
|
|
local maximum_level_value=${NDD_LOG4B_LEVEL_VALUES[$_NDD_LOG4B_FILE_LEVEL]}
|
|
|
|
if [[ "${level_value}" -le ${maximum_level_value} ]]; then
|
|
|
|
if [[ -z "${_NDD_LOG4B_FILE_PATH}" ]]; then
|
|
ndd::logger::_print_error "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
ndd::logger::_print_error "┃ The output text file is undefined (please set 'NDD_LOG4B_FILE_PATH')"
|
|
ndd::logger::_print_error "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
return 1
|
|
fi
|
|
|
|
local log_date
|
|
local log_level_name
|
|
local log_message
|
|
local log_line
|
|
|
|
log_date="$(date "${_NDD_LOG4B_FILE_DATE_FORMAT}")"
|
|
log_level_name="${NDD_LOG4B_LEVEL_DISPLAY_NAMES[$level_name]}"
|
|
|
|
# printf chokes on special characters like '-' which is rather annoying
|
|
# so we explicitly make the distinction between 'printf' and 'echo' using the number of arguments
|
|
if [[ "${#}" -ge 4 ]]; then
|
|
# shellcheck disable=2059
|
|
log_message="$(printf "${@:3}")"
|
|
else
|
|
log_message="${*:3}"
|
|
fi
|
|
|
|
# shellcheck disable=2059
|
|
log_line="$(printf "${_NDD_LOG4B_FILE_LOG_FORMAT}" "${log_date}" "${log_level_name}" "${log_message}")"
|
|
|
|
echo -e "${log_line}" >> "${_NDD_LOG4B_FILE_PATH}"
|
|
fi
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Log the given message to stdout at the given level if active.
|
|
# This is a private function.
|
|
#
|
|
# Globals:
|
|
# NDD_LOG4B_LEVEL_VALUES
|
|
# _NDD_LOG4B_STDOUT_DATE_FORMAT
|
|
# _NDD_LOG4B_STDOUT_LEVEL
|
|
#
|
|
# Arguments:
|
|
# @level_name - the logger level to use
|
|
# @level_value - the logger level to use
|
|
# @varargs... - the format and arguments in the 'printf' style
|
|
#
|
|
# Example:
|
|
# log error "This is a %-11s log message" "ERROR"
|
|
#
|
|
function ndd::logger::_log_to_stdout() {
|
|
local level_name="${1}"
|
|
local level_value="${2}"
|
|
|
|
local maximum_level_value=${NDD_LOG4B_LEVEL_VALUES[$_NDD_LOG4B_STDOUT_LEVEL]}
|
|
|
|
if [[ "${level_value}" -le ${maximum_level_value} ]]; then
|
|
|
|
local log_date
|
|
local log_level_name
|
|
local log_message
|
|
local log_line
|
|
|
|
log_date="$(date "${_NDD_LOG4B_STDOUT_DATE_FORMAT}")"
|
|
log_level_name="${NDD_LOG4B_LEVEL_DISPLAY_NAMES[$level_name]}"
|
|
|
|
# printf chokes on special characters like '-' which is rather annoying
|
|
# so we explicitly make the distinction between 'printf' and 'echo' using the number of arguments
|
|
if [[ "${#}" -ge 4 ]]; then
|
|
# shellcheck disable=2059
|
|
log_message="$(printf "${@:3}")"
|
|
else
|
|
log_message="${*:3}"
|
|
fi
|
|
|
|
# shellcheck disable=2059
|
|
log_line="$(printf "${_NDD_LOG4B_STDOUT_LOG_FORMAT}" "${log_date}" "${log_level_name}" "${log_message}")"
|
|
|
|
ndd::logger::_colorize_for_level "${level_name}" "${log_line}"
|
|
fi
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Normalize the given logger level name, taking the synonyms into account.
|
|
# Print an error message and exit with 1 if the log level cannot be normalized.
|
|
# This is a private function.
|
|
#
|
|
# Globals:
|
|
# NDD_LOG4B_LEVEL_SYNONYMS
|
|
# NDD_LOG4B_LEVEL_NAMES
|
|
#
|
|
# Arguments:
|
|
# @level_name - the logger level name to use (see NDD_LOG4B_LEVEL_NAMES)
|
|
#
|
|
# Outputs:
|
|
# Print the normalized logger level to stdout
|
|
#
|
|
function ndd::logger::_normalize_level() {
|
|
local level_name="${1}"
|
|
level_name="$(ndd::logger::_to_upper "${level_name}")"
|
|
|
|
# search for a level synonym
|
|
for level_synonym in "${!NDD_LOG4B_LEVEL_SYNONYMS[@]}"; do
|
|
if [[ "${level_name}" == "${level_synonym}" ]]; then
|
|
level_name="${NDD_LOG4B_LEVEL_SYNONYMS[$level_synonym]}"
|
|
fi
|
|
done
|
|
|
|
# print DISABLED and return if disabled (because DISABLED is not in NDD_LOG4B_LEVEL_NAMES)
|
|
if [[ "${level_name}" == "DISABLED" ]]; then
|
|
echo "${level_name}"
|
|
return 0
|
|
fi
|
|
|
|
# print the logger level name and return if valid
|
|
for valid_level_name in "${NDD_LOG4B_LEVEL_NAMES[@]}"; do
|
|
if [[ "${level_name}" == "${valid_level_name}" ]]; then
|
|
echo "${level_name}"
|
|
return 0
|
|
fi
|
|
done
|
|
|
|
# print an error message then exit with 1
|
|
ndd::logger::_print_error "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
ndd::logger::_print_error "┃ Invalid log level: ${level_name}"
|
|
ndd::logger::_print_error "┃ Stacktrace:"
|
|
|
|
local first_trace=0
|
|
local stack_depth=${#FUNCNAME[@]}
|
|
|
|
for ((i=first_trace; i<stack_depth; i++)); do
|
|
local function_name="${FUNCNAME[$i]}"
|
|
local line_number="${BASH_LINENO[$((i - 1))]}"
|
|
local file_path="${BASH_SOURCE[$((i))]}"
|
|
|
|
ndd::logger::_print_error "┃ in ${function_name} (${file_path}:${line_number})"
|
|
done
|
|
|
|
ndd::logger::_print_error "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
|
|
return 1
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Print the given message to stderr, in red if 'ansi' if present.
|
|
# This is a private function.
|
|
#
|
|
# Arguments:
|
|
# @message - the message to print
|
|
#
|
|
# Outputs:
|
|
# Print the colorized (or not) message to stderr
|
|
#
|
|
function ndd::logger::_print_error() {
|
|
local message="${1}"
|
|
|
|
if command -v ansi::isAnsiSupported > /dev/null && ansi::isAnsiSupported; then
|
|
# shellcheck disable=2086
|
|
echo -e "$(ansi --bold --red "${message}")" >&2
|
|
else
|
|
echo -e "${message}" >&2
|
|
fi
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Convert the given string to uppercase.
|
|
# This is a private function.
|
|
#
|
|
# Arguments:
|
|
# @string - the string to upper case
|
|
#
|
|
# Outputs:
|
|
# Print the uppercase string to stdout
|
|
#
|
|
function ndd::logger::_to_upper() {
|
|
local string="${1}"
|
|
echo "${string}" | awk '{print toupper($0)}'
|
|
}
|