Skip to content

Instantly share code, notes, and snippets.

@ttscoff
Last active April 16, 2022 23:59
Show Gist options
  • Star 22 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save ttscoff/6708b082e151ed4910e85f3fde35e9ad to your computer and use it in GitHub Desktop.
Save ttscoff/6708b082e151ed4910e85f3fde35e9ad to your computer and use it in GitHub Desktop.
Bash logging utility that simplifies use of logger command
#!/bin/bash
# Logging utility that simplifies user of bash logger command
# # First source the script
# source ~/scripts/logr.bash
# # Start the logger, generates log name from scripts filename
# logr start
# # or define your own
# logr start LOG_NAME
#
# logr [log|notice|info|debug|warn|error] MESSAGE
# # or default to "user.info" facility
# logr MESSAGE
__logr_DEFAULT_LOG_DIR="${HOME}/logs"
__logr_DEFAULT_LOG="scripts"
unset __logr_LOG_NAME
unset __logr_SCRIPT_LOG
unset __logr_VERBOSE
logr() {
[[ -z $__logr_LOG_DIR ]] && __logr_LOG_DIR=$__logr_DEFAULT_LOG_DIR
# default to "user" facility, can be set to local[0-9], etc.
[[ -z $__logr_FACILITY ]] && __logr_FACILITY=user
# default to quiet, no output to STDERR
[[ -z $__logr_VERBOSE ]] && __logr_VERBOSE=false
# default log tag and filename to "scripts", changed via logr start command
[[ -z "${__logr_LOG_NAME}" ]] && __logr_LOG_NAME=$__logr_DEFAULT_LOG
[[ -z "${__logr_SCRIPT_LOG}" ]] && __logr_SCRIPT_LOG="${__logr_LOG_DIR%/}/${__logr_LOG_NAME}.log"
local function_name="${FUNCNAME[1]}"
local log_type=$1
# start must be called first, initializes logging, sets global log file
# param 1: (string, optional) [verbose|quiet], verbose echos to STDERR, defaults to quiet
# param 2: (string, optional) name of log source, defaults to "scripts" (.log will be appended)
if [[ $log_type == "start" ]]; then
local should_clean=false
mkdir -p "${HOME}/logs/"
if [[ $2 =~ (^-v$|^verbose$) ]]; then
__logr_VERBOSE=true
shift
elif [[ $2 =~ (^-q$|^quiet$) ]]; then
__logr_VERBOSE=false
shift
else
__logr_VERBOSE=false
fi
if [[ $2 =~ clea[nr] ]]; then
should_clean=true
shift
fi
if [[ -n "$2" ]]; then
__logr_LOG_NAME=$2
fi
__logr_SCRIPT_LOG="${HOME}/logs/${__logr_LOG_NAME}.log"
touch $__logr_SCRIPT_LOG
$should_clean && logr clear
__logr_exec info $__logr_LOG_NAME "====> BEGIN LOGGING"
# logr quiet => disables STDERR output
elif [[ $log_type == "quiet" ]]; then
__logr_VERBOSE=false
# logr verbose => enables STDERR output
elif [[ $log_type == "verbose" ]]; then
__logr_VERBOSE=true
# logr clear => clears the log (unless it's the default log)
elif [[ $log_type == "clear" && $__logr_LOG_NAME != $__logr_DEFAULT_LOG ]]; then
[[ -n $__logr_SCRIPT_LOG && -f $__logr_SCRIPT_LOG ]] && echo -n > $__logr_SCRIPT_LOG
# debug type shows full function stack
elif [[ $log_type == "debug" ]]; then
function_name=$(IFS="\\"; echo "${FUNCNAME[*]:1}")
__logr_exec debug "${__logr_LOG_NAME}:${function_name}" "${*:2}"
# log, notice, info, warn, error set logging level
# warn and error go to /var/log/system.log as well as logfile
elif [[ $log_type =~ ^(notice|log|info|warn(ing)?|err(or)?|emerg) ]]; then
local level
case $log_type in
notice|log) level="notice" ;;
info) level="info" ;;
warn*) level="warning" ;;
err*) level="err" ;;
emerg) level="emerg" ;;
*) level="info" ;;
esac
__logr_exec $level "${__logr_LOG_NAME}:${function_name}" "${*:2}"
# if no type is given, assumes info level
else
__logr_exec info "${__logr_LOG_NAME}:${function_name}" "${*:1}"
fi
}
# execute the logger command
# param 1: (string) [log|notice|info|debug|warn|error] log level
# param 2: (string) Tag
# param 3: (string) Message
__logr_exec() {
local cmd
if [[ $__logr_VERBOSE == true ]]; then
logger -p ${__logr_FACILITY}.$1 -t $2 -s $3 2>&1 | tee -a ${__logr_SCRIPT_LOG} 1>&2
else
logger -p ${__logr_FACILITY}.$1 -t $2 -s $3 2>> ${__logr_SCRIPT_LOG}
fi
}
#!/bin/bash
# Source the script file
source ~/scripts/logr.bash
script_func() {
logr warn "$*"
nested_func
}
nested_func() {
logr debug "debug shows function stack separated by /"
# Oct 26 08:47:17 logger_test:nested_func\script_func\main[28953] <Debug>: debug shows function stack separated by /
}
logr start verbose logger_test
# This sets the global $__logr_LOG_NAME to "logger_test"
# Which in turn sets the $__logr_SCRIPT_LOG, in this case "~/logs/logger_test.log"
# can include "quiet" or "verbose" to toggle STDERR output, and/or "clean" to clear the log on start
# logr clear
## clear will empty the specified log in ~/logs
logr info "Just some info (does not go to system.log)"
# Oct 26 08:47:17 logger_test:main[28942] <Info>: Just some info (does not go to system.log)
logr "No level assumes info"
logr info It also works without quoting, if special characters are quoted
logr info Special characters include \", \`, \', \$, \?, \&, \!, \$, \[\\\], etc.
# Oct 26 08:47:17 logger_test:main[28943] <Info>: No level assumes info
# Oct 26 08:47:17 logger_test:main[28944] <Info>: It also works without quoting, if special characters are quoted
# Oct 26 08:47:17 logger_test:main[28945] <Info>: Special characters include ", `, ', $, ?, &, !, $, [\], etc.
logr quiet
# Nothing after logr quiet will go to STDERR, but still goes to script log and system.log
logr debug A debug message does not go to system.log
# Oct 26 08:47:17 logger_test:main[28947] <Debug>: A debug message does not go to system.log
logr notice "notice goes to both system log and script log"
# Oct 26 08:47:17 logger_test:main[28948] <Notice>: notice goes to both system log and script log
logr warn "A WARNING: Everything higher than notice goes to syslog"
# Oct 26 08:47:17 logger_test:main[28949] <Warning>: A WARNING: Everything higher than notice goes to syslog
logr error "Uh oh, an error... that definitely goes to syslog"
# Oct 26 08:47:17 logger_test:main[28950] <Error>: Uh oh, an error... that definitely goes to syslog
logr emerg "Emergency logs to all logs, and broadcasts to all users"
# Even scripts running in the background under another user will cause a message to be shown to any user with a terminal open
script_func "This message comes from inside a function, note the :script_func tag instead of :main"
# Oct 26 08:47:17 logger_test:script_func[28951] <Warning>: This message comes from inside a function, note the :script_func tag instead of :main
@fl-max
Copy link

fl-max commented Apr 23, 2019

I believe line #40, mkdir -p "${HOME}/logs/", should be mkdir -p "${__logr_LOG_DIR}"

And Line #60 should be removed.

Also, for variables with defaults, you can use the built-in. ie:
__logr_LOG_DIR="${__logr_LOG_DIR:-${HOME}/logs}"

Nice script!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment