dracut/dracut-logger

294 lines
8.8 KiB
Bash
Executable File

#!/bin/sh
# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
# ex: ts=8 sw=4 et filetype=sh
#
# logging faciality module for dracut both at build- and boot-time
#
# Copyright 2010 Amadeusz Żołnowski <aidecoe@aidecoe.name>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
__DRACUT_LOGGER__=1
## @brief Logging facility module for Dracut both at build- and boot-time.
#
# @section intro Introduction
#
# The logger takes a bit from Log4j philosophy. There are defined 6 logging
# levels:
# - TRACE (6)
# The TRACE Level designates finer-grained informational events than the
# DEBUG.
# - DEBUG (5)
# The DEBUG Level designates fine-grained informational events that are most
# useful to debug an application.
# - INFO (4)
# The INFO level designates informational messages that highlight the
# progress of the application at coarse-grained level.
# - WARN (3)
# The WARN level designates potentially harmful situations.
# - ERROR (2)
# The ERROR level designates error events that might still allow the
# application to continue running.
# - FATAL (1)
# The FATAL level designates very severe error events that will presumably
# lead the application to abort.
# Descriptions are borrowed from Log4j documentation:
# http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/Level.html
#
# @section usage Usage
#
# First of all you have to start with dlog_init() function which initializes
# required variables. Don't call any other logging function before that one!
# If you're ready with this, you can use following functions which corresponds
# clearly to levels listed in @ref intro Introduction. Here they are:
# - dtrace()
# - ddebug()
# - dinfo()
# - dwarn()
# - derror()
# - dfatal()
# They take all arguments given as a single message to be logged. See dlog()
# function for details how it works. Note that you shouldn't use dlog() by
# yourself. It's wrapped with above functions.
#
# @see dlog_init() dlog()
#
# @section conf Configuration
#
# Logging is controlled by following global variables:
# - @var stdloglvl - logging level to standard error (console output)
# - @var sysloglvl - logging level to syslog (by logger command)
# - @var fileloglvl - logging level to file
# - @var kmsgloglvl - logging level to /dev/kmsg (only for boot-time)
# - @var logfile - log file which is used when @var fileloglvl is higher
# than 0
# and one global internal variable @var _maxloglvl which <b>must not</b> be
# overwritten. @_maxloglvl is set by dlog_init() and holds maximum logging level
# of those three and indicates that dlog_init() was run.
#
# Logging level set by the variable means that messages from this logging level
# and above (FATAL is the highest) will be shown. Logging levels may be set
# independently for each destination (stderr, syslog, file, kmsg).
#
# @see dlog_init()
## @brief Initializes Dracut Logger.
#
# @retval 1 if something has gone wrong
# @retval 0 on success.
#
# @note This function need to be called before any other from this file.
#
# If any of the variables is not set, this function set it to default:
# - @var stdloglvl = 4 (info)
# - @var sysloglvl = 0 (no logging)
# - @var fileloglvl is set to 4 when @var logfile is set too, otherwise it's
# - @var kmsgloglvl = 0 (no logging)
# set to 0
#
# @warning Function sets global variable @var _maxloglvl for internal use. Don't
# overwrite it.
dlog_init() {
# Skip initialization if it's already done.
[ -n "$_maxloglvl" ] && return 0
local ret=0; local errmsg
[ -z "$stdloglvl" ] && stdloglvl=4
[ -z "$sysloglvl" ] && sysloglvl=0
[ -z "$kmsgloglvl" ] && kmsgloglvl=0
if [ -z "$fileloglvl" ]; then
[ -w "$logfile" ] && fileloglvl=4 || fileloglvl=0
elif [ $fileloglvl -gt 0 ]; then
! [ -e "$logfile" ] && >"$logfile"
if [ -w "$logfile" -a -f "$logfile" ]; then
# Mark new run in the log file
echo >>"$logfile"
if command -v date >/dev/null; then
echo "=== $(date) ===" >>"$logfile"
else
echo "===============================================" >>"$logfile"
fi
echo >>"$logfile"
else
# We cannot log to file, so turn this facility off.
fileloglvl=0
ret=1
errmsg="'$logfile' is not a writable file"
fi
fi
if [ $sysloglvl -gt 0 ]; then
if ! [ -c /dev/log -a -w /dev/log ] || ! command -v logger >/dev/null
then
# We cannot log to syslog, so turn this facility off.
sysloglvl=0
ret=1
errmsg="No '/dev/log' or 'logger' not included for syslog logging"
fi
fi
local lvl
_maxloglvl=0
for lvl in $stdloglvl $sysloglvl $fileloglvl; do
[ $lvl -gt $_maxloglvl ] && _maxloglvl=$lvl
done
[ -n "$errmsg" ] && derror "$errmsg"
return $ret
}
## @brief Converts numeric logging level to the first letter of level name.
#
# @param lvl Numeric logging level in range from 1 to 6.
# @retval 1 if @a lvl is out of range.
# @retval 0 if @a lvl is correct.
# @result Echoes first letter of level name.
_lvl2char() {
case "$1" in
1) echo F;;
2) echo E;;
3) echo W;;
4) echo I;;
5) echo D;;
6) echo T;;
*) return 1;;
esac
}
## @brief Converts numeric level to logger priority defined by POSIX.2.
#
# @param lvl Numeric logging level in range from 1 to 6.
# @retval 1 if @a lvl is out of range.
# @retval 0 if @a lvl is correct.
# @result Echoes logger priority.
_lvl2syslogpri() {
case "$1" in
1) echo crit;;
2) echo error;;
3) echo warning;;
4) echo info;;
5) echo debug;;
6) echo debug;;
*) return 1;;
esac
}
## @brief Prints to stderr and/or writes to file, to syslog and/or /dev/kmsg
# given message with given level (priority).
#
# @param lvl Numeric logging level.
# @param msg Message.
# @retval 0 It's always returned, even if logging failed.
#
# @note This function is not supposed to be called manually. Please use
# dtrace(), ddebug(), or others instead which wrap this one.
#
# This is core logging function which logs given message to standard error, file
# and/or syslog (with POSIX shell command <tt>logger</tt>) and/or to /dev/kmsg.
# The format is following:
#
# <tt>X: some message</tt>
#
# where @c X is the first letter of logging level. See module description for
# details on that.
#
# Message to syslog is sent with tag @c dracut. Priorities are mapped as
# following:
# - @c FATAL to @c crit
# - @c ERROR to @c error
# - @c WARN to @c warning
# - @c INFO to @c info
# - @c DEBUG and @c TRACE both to @c debug
dlog() {
[ -z "$_maxloglvl" ] && return 0
local lvl="$1"; shift
local lvlc=$(_lvl2char "$lvl") || return 0
[ $lvl -le $_maxloglvl ] || return 0
local msg="$lvlc: $*"
[ $lvl -le $stdloglvl ] && echo "$msg" >&2
if [ $lvl -le $sysloglvl ]; then
logger -t "dracut[$$]" -p $(_lvl2syslogpri $lvl) "$msg"
fi
if [ $lvl -le $fileloglvl -a -w "$logfile" -a -f "$logfile" ]; then
echo "$msg" >>"$logfile"
fi
[ $lvl -le $kmsgloglvl ] && echo "[dracut[$$]] $msg" >/dev/kmsg
}
## @brief Logs message at TRACE level (6)
#
# @param msg Message.
# @retval 0 It's always returned, even if logging failed.
dtrace() {
dlog 6 "$*"
}
## @brief Logs message at DEBUG level (5)
#
# @param msg Message.
# @retval 0 It's always returned, even if logging failed.
ddebug() {
dlog 5 "$*"
}
## @brief Logs message at INFO level (4)
#
# @param msg Message.
# @retval 0 It's always returned, even if logging failed.
dinfo() {
dlog 4 "$*"
}
## @brief Logs message at WARN level (3)
#
# @param msg Message.
# @retval 0 It's always returned, even if logging failed.
dwarn() {
dlog 3 "$*"
}
## @brief It's an alias to dwarn() function.
#
# @param msg Message.
# @retval 0 It's always returned, even if logging failed.
dwarning() {
dwarn "$*"
}
## @brief Logs message at ERROR level (2)
#
# @param msg Message.
# @retval 0 It's always returned, even if logging failed.
derror() {
dlog 2 "$*"
}
## @brief Logs message at FATAL level (1)
#
# @param msg Message.
# @retval 0 It's always returned, even if logging failed.
dfatal() {
dlog 1 "$*"
}