From dece4203b4a0fd5e69bc8872d5a994917b6762e8 Mon Sep 17 00:00:00 2001 From: Nick Chambers Date: Sun, 4 Jul 2021 06:25:08 -0500 Subject: [PATCH] Add a logging interface --- rowbot | 306 +++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 186 insertions(+), 120 deletions(-) diff --git a/rowbot b/rowbot index 314d260..b49394f 100755 --- a/rowbot +++ b/rowbot @@ -6,111 +6,6 @@ shopt -s dotglob extglob lastpipe nullglob -### -# configure rowbot -### - -# default config - -declare -A config=( - # connection settings - [server]=irc.libera.chat [port]="" [tls]=no [client-cert]="" - # irc registration settings - [nick]=rowbot-dev [ident]=rowbot [realname]=rowbot [chan]="" - # bot control settings - [owner]="${USER:-uplime}" [trigger]=\` [dev]=yes - # log settings - [log]="" [overwrite]=no [log-level]=info -) - -# parse command line arguments - -declare -A opts -# This code is not used yet, but will be later. -# shellcheck disable=SC2034 -cmd_line=( "${@:0}" ) - -while (( $# )); do - case $1 in - --*=*) - key=${1#--} key=${key%%=*} - opts[$key]=${1#--*=} - ;; - --no-*) - key=${1#--no-} - opts[$key]=no - ;; - --) - shift - break - ;; - --*) - key=${1#--} - opts[$key]=yes - ;; - *) - break - esac - - shift -done - -# apply custom configuration files - -for file do - if [[ -f $file ]]; then - # These files (if any) are provided dynamically at run-time. - # shellcheck disable=SC1090 - . "$file" # ha, dot file - else - die "could not locate config file %s" "$file" - fi -done - -for setting in "${!config[@]}"; do - if [[ -v ${setting//-/_} ]]; then - declare -n setting_var=${setting//-/_} - config[$setting]=$setting_var - fi -done - -# apply command line arguments - -for setting in "${!config[@]}"; do - # This is a false positive. - # shellcheck disable=SC2102 - if [[ -v opts[$setting] ]]; then - config[$setting]=${opts[$setting]} - fi -done - -# apply default port if one isn't provided - -if [[ -z ${config[port]} ]]; then - if [[ ${config[tls]} = yes ]]; then - config[port]=6697 - else - config[port]=6667 - fi -fi - -# apply any reloaded values - -for setting in "${!config[@]}"; do - env_name=${setting//-/_} env_name=${env_name^^} - declare -n env_var=$env_name - - if [[ -v $env_name ]]; then - # This variable is only used for assignment. - # shellcheck disable=SC2034 - config[$setting]=$env_var - fi -done - -# cleanup - -unset key file setting setting_var env_name env_var - ### # utility and helper functions ### @@ -126,7 +21,12 @@ any_file() { } die() { - # error "$@" + local fmt=$1 + shift + # This is a wrapper around printf so the format string isn't known ahead of + # time. + # shellcheck disable=SC2059 + printf "$fmt\n" "$@" >&2 exit "${STATUS:-42}" } @@ -135,15 +35,17 @@ get_option() { return 1 fi - local option_name=${1//-/_} - declare -n option_var=$option_name + local var_name=${1//-/_} + local env_var=${var_name^^} - if [[ -v opts[$1] ]]; then - option_var=${opts[log-level]} - elif [[ ! -v $option_name ]]; then - # This variable is only used for assignment. - # shellcheck disable=SC2034 - option_var=$2 + if [[ -v $env_var ]]; then + config[$1]=${!env_var} + elif [[ -v opts[$1] ]]; then + config[$1]=${opts[$1]} + elif [[ -v $var_name ]]; then + config[$1]=${!var_name} + else + config[$1]=$2 fi } @@ -183,25 +85,187 @@ run_callbacks() { return 0 } +### +# configure rowbot's environment +### + +# parse command line arguments + +declare -A opts +cmd_line=( "${@:0}" ) + +while (( $# )); do + case $1 in + --*=*) + key=${1#--} key=${key%%=*} + opts[$key]=${1#--*=} + ;; + --no-*) + key=${1#--no-} + opts[$key]=no + ;; + --) + shift + break + ;; + --*) + key=${1#--} + opts[$key]=yes + ;; + *) + break + esac + + shift +done + +# load custom configuration files + +for file do + if [[ -f $file ]]; then + # These files (if any) are provided dynamically at run-time. + # shellcheck disable=SC1090 + . "$file" # ha, dot file + else + die "could not locate config file %s" "$file" + fi +done + +# cleanup + +unset key file + +### +# load default config +### + +declare -A config + +# connection settings + +get_option server irc.libera.chat +get_option tls no + +if [[ ${config[tls]} = no ]]; then + get_option port 6667 +else + get_option client-cert "" + get_option port 6697 +fi + +# irc registration settings + +get_option nick rowbot-dev +get_option ident rowbot +get_option realname rowbot +get_option chan "" + +# bot control settings + +get_option owner "${USER:-uplime}" +get_option trigger \` +get_option dev yes + +### +# logger +### + +log() { + if [[ -v LOG_LEVEL ]] && (( log_levels[$log_level] <= log_levels[$LOG_LEVEL] )); then + printf "%s: $1\n" "${LOG_LEVEL^^}" "${@:2}" >&"$log_fd" + fi +} + +log_debug() { + LOG_LEVEL=debug log "$@" +} + +log_info() { + LOG_LEVEL=info log "$@" +} + +log_warn() { + LOG_LEVEL=warn log "$@" +} + +log_error() { + LOG_LEVEL=error log "$@" +} + +log_has_level() { + local level + + for level in "${!log_levels[@]}"; do + if [[ ${1,,} = "$level" ]]; then + return 0 + fi + done + + return 1 +} + +on_init_001_log() { + declare -gA log_levels=( [debug]=1 [info]=2 [warn]=3 [error]=4 ) + get_option log-level info + + if ! log_has_level "${config[log-level]}"; then + die "%s is not a valid logging level" "${config[log-level]}" + fi + + get_option log "" + get_option overwrite no + log_level=${config[log-level]} + + if [[ ${config[log]} ]]; then + if [[ ${config[overwrite]} = yes ]]; then + exec {log_fd}>"${config[log]}" + else + exec {log_fd}>>"${config[log]}" + fi + else + log_fd=1 + fi +} + +on_exit_log() { + if [[ -v log_fd ]] && (( log_fd != 1 )); then + exec {log_fd}>&- + fi +} + +### +# cleanup +### + +cleanup() { + run_callbacks on_exit_ +} + +trap cleanup EXIT + ### # live code reloader ### reload() { - run_callbacks on_before_reload_ + local setting setting_name + run_callbacks on_before_ + + for setting in "${!config[@]}"; do + setting_name=${setting//-/_} + export "${setting_name^^}"="${config[$setting]}" + done + exec "${cmd_line[@]}" } hup_reload() { + log_info "received reload signal (HUP)" reload } trap hup_reload HUP -on_init_debug() { - declare -p config -} - ### # initialization sequence ### @@ -209,7 +273,9 @@ on_init_debug() { run_callbacks on_init_ if is_reloaded; then - run_callbacks on_after_reload_ + run_callbacks on_after_ else run_callbacks on_first_ fi + +declare -p config