Logging library for Unix Shell
Logging library for Unix Shell
This library is similar to Log library for Python or Java. Here its code:
#!/bin/sh # Simple logging facility for Unix /bin/sh # ======================================== # # Configuration # ------------- # # _LOGGING_DATEFMT, _LOGGING_FMT variables are used for format of datetime # and log record # # * _LOGGING_DATEFMT : uses the same format as date(1) and Python Lib # # * _LOGGING_FMT : uses format similar to Python logging Lib # # Available fields for _LOGGING_FMT are: # asctime, filename, levelname, levelno, message, name, pathname, # process, processName, user # # Example # ------- # # getLogger prg1 # getLogger prg2 # # addLogHandler prg1 FileHandler /dev/stderr # addLogHandler prg2 ConsoleHandler # addLogHandler prg2 FileHandler /var/log/somefile # addLogHandler prg2 FileHandler /var/log/somefile_copy # # setLogLevel prg1 DEBUG # # prg1_debug DebugMessage # prg1_error ErrorMessage # echo InfoMessage|prg2_info # # will produces on STDERR console: # ... # 2014-07-18T17:09:52+0300 prg1 DEBUG DebugMessage # ... # # will produces on console: # ... # 2014-07-18T17:09:52+0300 prg1 ERROR ErrorMessage # 2014-07-18T17:09:52+0300 prg2 INFO InfoMessage # ... # # and in /var/log/somefile: # ... # 2014-07-18T17:09:52+0300 prg2 INFO InfoMessage # ... # # and in /var/log/somefile_copy: # ... # 2014-07-18T17:09:52+0300 prg2 INFO InfoMessage # ... # TODO: log levels per handlers ############################## Settings ##################################### # Global log record format and date format: _LOGGING_DATEFMT="%Y-%m-%dT%H:%M:%S%z" _LOGGING_FMT="%asctime %levelname %message" ################################### Code ##################################### _log_SCRIPT=`readlink -f $0` _log_getLogAttr() { name=$1; attr=${1}_$2 eval echo $`echo $attr` } ################################### Handlers ################################# # SYNOPSIS: ... # # Nothing to do, all args are ignored _log_NullHandler() { : } # SYNOPSIS: $name $level $msg # # Logs $msg with $level via logger(1) utility _log_SyslogHandler() { local name level msg syslog_level name="$1"; level="$2"; msg="$3" syslog_level=`_log_syslogLevel $level` logger -p "local0.${syslog_level}" -t $name "$msg" } # SYNOPSIS: $name $level $msg # # Logs message $msg on console _log_ConsoleHandler() { local name level msg name="$1"; level="$2"; msg="$3" echo "$msg" } # SYNOPSIS: $subject $address $msg # # If mail(1) exists, call it to send $msg via EMail _log_MailHandler() { command -v mail >/dev/null 2>&1 || return 1 local subj addr name level msg subj="$1"; addr="$2"; name="$3"; level="$4"; msg="$5" echo "$msg"|mail -s "${subj}${level}: $name" $addr } # SYNOPSIS: $filename $msg # # Append message $msg to file $filename _log_FileHandler() { local filename name level msg filename="$1"; name="$2"; level="$3"; msg="$4" touch "$filename" echo "$msg" >> "$filename" } _log_syslogLevel() { case $1 in CRITICAL) echo crit;; FATAL) echo panic;; ERROR) echo error;; WARNING) echo warning;; INFO) echo info;; DEBUG) echo debug;; *) echo notice;; esac } _log_levelNo() { case $1 in CRITICAL|FATAL) echo 50;; ERROR) echo 40;; WARNING) echo 30;; INFO) echo 20;; DEBUG) echo 10;; *) echo 0;; esac } _log() { local name level msg handlers h closure_args skip no_closure_args levelno enabled_levelno name="$1"; level="$2"; msg="$3" levelno=`_log_levelNo $level` enabled_levelno=`_log_getLogAttr $name level` [ $levelno -lt $enabled_levelno ] && return handlers=`_log_getLogAttr $name handlers` handlers=`echo "$handlers"|sed 's/__COMMA__/\\ /g'` for h in $handlers; do echo $skip|grep $h >/dev/null && continue closure_args=`_log_getLogAttr $name ${h}_handler_args` closure_args=`echo "$closure_args"|sed 's/__COMMA__/\\ /g'` no_closure_args=1 for ca in $closure_args; do eval "$h $ca $name $level \"$msg\"" no_closure_args=0 done [ $no_closure_args ] && eval "$h $name $level \"$msg\"" skip="$h $skip" done } # SYNOPSIS: $name $h [$args...] # # Adds handler $h for logger $name with possible arguments # (see handlers' implementations for concrete args) addLogHandler() { local name handler oldhandlers exthandler args oldargs name=$1; exthandler="$2"; handler=_log_"$exthandler"; shift 2; args="$*" oldhandlers=`_log_getLogAttr $name handlers` oldargs=`_log_getLogAttr $name ${handler}_handler_args` # __COMMA__ is used to separate items in lists eval "${name}_handlers=${handler}__COMMA__${oldhandlers:-_log_NullHandler}" eval "${name}_${handler}_handler_args=\"$args\"__COMMA__$oldargs" } # SYNOPSIS: $name | $name $longname # # No return and no output but setups logger for this $name. In 2nd form $longname # is used in message substitution getLogger() { local asctime filename levelname levelno message name pathname process processName _lv user longname asctime=$_LOGGING_DATEFMT filename=`getScriptName` message='${1:-`tee`}' name="$1" longname=${2:-$name} pathname=`echo "$_log_SCRIPT"|sed 's/\\//\\\\\//g'` process='$$' processName=`ps -A -opid,comm | awk -v PID=$$ '$1 == PID { print $2 }'` processName=`echo "$processName"|sed 's/\\//\\\\\//g'` user="$USER" for _lv in debug info warning error fatal critical; do levelname=`echo -n $_lv|tr '[:lower:]' '[:upper:]'` levelno=`_log_levelNo $levelname` fmt=`echo $_LOGGING_FMT | \ sed 's/%asctime/\`date +$_LOGGING_DATEFMT\`/g' | \ sed "s/%filename/$filename/g" | \ sed "s/%levelname/$levelname/g" | \ sed "s/%levelno/$levelno/g" | \ sed "s/%message/$message/g" | \ sed "s/%pathname/$pathname/g" | \ sed "s/%processName/$processName/g" | \ sed "s/%process/$process/g" | \ sed "s/%user/$user/g" | \ sed "s//$longname/g"` eval "${name}_${_lv} () { _log $name $levelname \"$fmt\"; }" done setLogLevel $name INFO } # SYNOPSIS: $name $level # # Sets the threshold for $name logger to $level (INFO, ERROR, etc.). Logging # messages which are less severe than $level will be ignored. # Default is INFO setLogLevel() { local name level levelno name="$1"; level=`echo -n $2|tr '[:lower:]' '[:upper:]'` levelno=`_log_levelNo $level` eval "${name}_level=$levelno" } # SYNOPSIS: # # Echos name of script getScriptName() { echo `basename "$_log_SCRIPT"` }
Example of usage:
#!/bin/sh . ./logging.sh getLogger prg1 `getScriptName` addLogHandler prg1 ConsoleHandler addLogHandler prg1 FileHandler ./lll1.log addLogHandler prg1 FileHandler ./lll2.log setLogLevel prg1 DEBUG prg1_debug Debugggg prg1_error Errrrror echo 'Message-INFO!!!! 1111 2222'|prg1_info