log4sh

2004-12-31

Revision History
Revision 1.2.42004-12-28kwa
Initial DocBook conversion.

Abstract

log4sh is a logging framework for shell scripts that works similar to the other wonderful logging products available from the Apache Software Foundataion (eg. log4j, log4perl). Although not as powerful as the others, it can make the task of adding advanced logging to shell scripts easier. It has much more power than just using simple "echo" commands throughout. In addition, it can be configured from a properties file so that scripts in a production environment do not need to be altered to change the amount of logging they produce.


Table of Contents

1. Introduction
1.1. Credits / Contributors
1.2. Feedback
2. Quickstart
3. Usage Guide
3.1. Preconfigure log4sh
3.2. Source log4sh
3.3. Configure log4sh in code
3.4. Logging with log4sh
4. Properties File Configuration
4.1. Root Logger
4.2. Levels
4.3. Appenders
5. Function Reference
5.1. Root Logger
5.2. Appenders
5.3. Logging
6. Miscellaneous Info

1. Introduction

Log4sh has been developed under the Bourne Again Shell (bash) on Linux, but great care has been taken to make sure it works under the default Bourne Shell of Solaris (sh) as this happens to be the primary platform used by myself.

Tested Operating Systems

  • Linux

  • Solaris 8, 9, 10

Tested Shells

  • Bourne Shell (sh)

  • Bourne Again Shell (bash)

1.1. Credits / Contributors

In this document, I have the pleasure of acknowledging:

  • Nobody in particular

1.2. Feedback

Feedback is most certainly welcome for this document. Send your additions, comments and criticisms to the following email address: .

2. Quickstart

To get started quickly with log4sh, take a look at the test-log4sh sample script in the src/test directory of the distribution. You will need to copy the log4sh script itself from the src/shell directory into the test directory before running the test. This test script is designed to configure log4sh via code. Later on, we will configure log4sh with a properties file, very similar to how log4j is configured.

By default, log4sh is configured with a ConsoleAppender which logs to STDOUT using a SimpleLayout and a logging level of ERROR. If no configuration file is found, a warning message will be given letting the user know that no configuration file was found. This warning can be supressed by setting the LOG4SH_CONFIGURATION environment variable to none.

Run the first test.

Example 1. Test #1

$ ./test-log4sh

After a first run you will see quite a bit of output to the display, and as well two log files will be created (log4sh-pattern.log and log4sh-simple.log). The display contains a mix of output to STDOUT and STDERR, and the files contain various versions of the same data, but with output that changes as various layouts and patterns are tested. To clean up the display a bit, you could send all of the output of the STDERR appender off to /dev/null.

Run the test again, but redirecting STDERR to /dev/null.

Example 2. Test #2

$ ./test-log4sh 2>/dev/null

Go ahead a take a look at the test script to get a feel of what the script is trying to accomplish. Hopefully, you can see just how simple log4sh is to use and control.

For our next test, we will configure log4sh with a properties file. This test is incredibly simple as it is designed to show the power of the properties file. Copy first example properties file log4sh.properties.ex1 from the src/examples directory into the test directory, and give it the name log4sh.properties.

Run the second test.

Example 3. Test #3

$ ./test-properties

This test is designed to look very much like one of the log4j examples. The properties file is taken almost verbatum from the log4j short manual, with only small changes required to make it work for log4sh. Log4sh is configured with a ConsoleAppender that has a PatternLayout. One limitation of log4sh is that it does not have access to a timer with millisecond accuracy, so it logs only with an accuracy of one second. For most situations, this should be sufficient.

Copy the second example properties file (log4sh.properties.ex2) as log4sh.properties, and rerun the test. This second properties file is only slightly different from the first in that it adds the filename to the output, and removes the %x pattern directive as that directive is not supported by log4sh.

The next example shows a typical situation where an administrator wants to run a script via a cron job, wants a log of the scripts actions, but only wants an email if the job failed.

Copy the third example properies file (log4sh.properties.ex3) over, and rerun the test. This time, the output will be sent to two separate locations; STDERR and a file called example.log. The output to STDERR is set to the ERROR level, and output sent to the file is at the INFO level. More output is written to the logfile (as expected) when the test is run.

In the situation of being run from a cron job, the logfile will always be written, but an email comes only when output from the script came at the ERROR or FATAL level. An administrator can even configure the log4sh.properties file to a DEBUG level so that more output is logged for testing or debugging purposes, and this change can happen without making any code changes to the script. Something very useful in a production environment!

3. Usage Guide

The usage of log4sh is simple. There are only a few simple steps required to setup and use log4sh in your application.

  1. preconfigure log4sh (properties file)

  2. source the log4sh script code

  3. configure log4sh in code (optional)

  4. call logging statements

3.1. Preconfigure log4sh

To preconfigure log4sh, create a properties file (see the Properties File Configuration later in this document). Optionally set the LOG4SH_CONFIGURATION environment variable to point log4sh to the configuration file.

3.2. Source log4sh

To source the code into your script (also known as including), one uses the sourcing ability of shell to source one script into another. See the following quick example for how easy this is done.

Example 4. Sourcing external shell code into current program

#! /bin/sh

# source log4sh from current directory
. ./log4sh

Here is some sample code that looks for log4sh in the same directory as the script is located, as well as the current directory. If log4sh could not be found, it exits with an error. If log4sh is found, it is loaded, along with the log4sh.properties file in the current directory (see the following example). It then logs a message at the INFO level to STDOUT.

Example 5. Hello, world (using properties)

#! /bin/sh
#
# log4sh example: Hello, world
#
myDir=`dirname $0`

# find and source log4sh
if [ -r "$myDir/log4sh" ]; then
  dir=$myDir
elif [ -r "./log4sh" ]; then
  dir=.
else
  echo "fatal: could not find log4sh" >&2
  exit 1
fi
. $dir/log4sh

# say Hello to the world
logger_info "Hello, world"

Here is the log4sh.properties file for the previous example. Save it in the same directory you are running the above script from.

Example 6. Hello, world; properties file

#
# log4sh example: Hello, world properties file
#

# Set root logger level to DEBUG and its only appender to A1
log4sh.rootLogger=INFO, A1

# A1 is set to be a ConsoleAppender.
log4sh.appender.A1=ConsoleAppender

# A1 uses a PatternLayout.
log4sh.appender.A1.layout=PatternLayout
log4sh.appender.A1.layout.ConversionPattern=%r [%t] %p %c %x - %m%n

3.3. Configure log4sh in code

To configure log4sh in code, simply call the appropriate functions in your code. The following code sample loads log4sh from the current directory, configures it for STDERR output, and the logs a message at the INFO level.

Example 7. Hello, world (configured in code)

#! /bin/sh
#
# log4sh example: Hello, world
#

# source log4sh (disabling properties file warning)
LOG4SH_CONFIGURATION="none" . ./log4sh

# configure log4sh defaults
logger_setLevel INFO

# configure appenders
appender_setAppend stdout false
logger_addAppender stderr
appender_setAppenderType stderr FileAppender
appender_setAppenderFile stderr STDERR

# say Hello to the world
logger_info "Hello, world"

3.4. Logging with log4sh

Once log4sh is loaded, logging is as simple as calling the appropriate logging function with a message to be logged. Take a look at the above examples to see just how easy it was to log the statement "Hello, world" at an INFO level.

4. Properties File Configuration

Log4sh can be configured with a properties file that is separate from the actual script where the logging takes place. By default, log4sh looks for its properties file called log4sh.properties in the current directory. If the file is located elsewhere or with a different name, log4sh can be configured by setting the LOG4SH_CONFIGURATION environment variable (eg. LOG4SH_CONFIGURATION="/etc/log4sh.conf").

A log4sh.properties file that is completly empty is sufficient to configure log4sh. There will be absolutely no output however (which might just be what is desired). Usually though, some output is desired, so there is at least a recommended minimum configuration file. An explaination of the file follows the example.

Example 8. Recommended minimum log4sh.properties file

log4sh.rootLogger=INFO, stdout
log4sh.appender.stdout=ConsoleAppender

In the first line, the root logger is configured by setting the default logging level, and defining the name of an appender. In the second line, the stdout appender is defined as a ConsoleAppender.

4.1. Root Logger

(future)

4.2. Levels

Table 1. Logging Levels (from most output to least)

LevelDefinition
ALLThe ALL level has the lowest possible rank and is intended to turn on all logging.
DEBUGThe DEBUG level designates fine-grained informational events that are most useful to debug an application.
INFOThe INFO level designates informational messages that highlight the progress of the application at coarse-grained level.
WARNThe WARN level designates potentially harmful situations.
ERRORThe ERROR level designates error events that might still allow the application to continue running.
FATALThe FATAL level designates very severe error events that will presumably lead the application to abort.
OFFThe OFF level has the highest possible rank and is intended to turn off logging.

4.3. Appenders

An appender name can be any alpha-numeric string containing no spaces.

Example 9. Sample appender names

myAppender - good

4.3.1. Types

An appender can be set to one of several different types.

Example 10. Setting an appender type

  log4sh.appender.A1=FileAppender
  

Table 2. Appender Types

TypeDefinitionSupported?
ConsoleAppenderoutput sent to console (STDOUT)yes
FileAppenderoutput sent to a fileyes
DailyRollingFileAppenderoutput sent to a file that rolls over dailypartial
RollingFileAppenderoutput sent to a file that rolls over by sizepartial

4.3.2. Options

An appender can take several different options.

Example 11. Setting an appender option

  log4sh.appender.A1.File=output.log
  

Table 3. Appender Options

OptionDefinitionSupported?
DatePatternconfigure a pattern for the output filenameno (ignored)
Fileoutput filename (special filename of STDERR used for logging to STDERR)yes
MaxBackupIndexnumber of old logfiles to keepno (ignored)
MaxFileSizemaximum size of old logfilesno (ignored)
Thresholdlogging level of the appenderyes

4.3.3. Layouts

An appender can be configured with various Layouts to customize how the output looks.

Example 12. Setting an appender's layout

  log4sh.appender.A1.layout=PatternLayout
  

Table 4. Layouts

LayoutDefinitionSupported?
HTMLLayoutlayout using HTMLno (same as SimpleLayout)
SimpleLayouta simple default layout ('%p - %m')yes
PatternLayouta patterned layout (default: '%d %p - %m%n')yes

An layout has many different options to configure how it appears. These are known as patterns.

Example 13. Setting an appender's layout pattern

  log4sh.appender.A1.layout.ConversionPattern=%d [%p] %c - %m%n
  

Table 5. Pattern Options

OptionDefinitionSupported?
%ccurrent class (not applicable in shell; always returns 'shell')yes
%dcurrent date (see *NIX date man page; '%Y-%m-%d %H:%M:%S')yes
%Fcurrent script filename (default: `basename $0`)yes
%Lcurrent line number in scriptno (ignored)
%mlogging messageyes
%nOS specific line endingno (ignored)
%plogging level (aka priority)yes
%rnumber of seconds since script was startedpartial (bash)
%tcurrent executing thread (default: 'main'; code changable)yes
%xunknownno (ignored)

5. Function Reference

5.1. Root Logger

Table 6. Configuring the root logger

FunctionDefinitionExample
logger_addAppenderadd an appenderlogger_addAppender stdout
logger_addAppenderWithPatternshortcut for adding an appender with a specific pattern layoutlogger_addAppenderWithLayout myPattern '%d [%p] %m'
logger_setFilenameset the script filename for the %F pattern optionlogger_setFilename "myFilename"
logger_getLevelget the current root logger priority levellevel=`logger_getLevel`
logger_setLevelset the root logger priority levellogger_setLevel INFO
logger_setThreadNameset the current thread name for the %t pattern optionlogger_setThreadName "myThread"

5.2. Appenders

Table 7. Configuring appenders

FunctionDefinitionExample
appender_closeclose an appenderappender_close myAppender
appender_setAppenderFileset the output filename for the named appenderappender_setAppenderFile myAppender "output.log"
appender_setAppenderTypeset the type of appender for the named appenderappender_setAppenderType myAppender FileAppender
appender_getLayoutget an appender's layout typelayout=`appender_getLayout myAppender`
appender_setLayoutset the layout type for the named appenderappender_setLayout myAppender PatternLayout
appender_getLevelget an appender's logging prioritylevel=`appender_getLevel myAppender`
appender_setLevelset the logging priority for the named appenderappender_setLevel myAppender DEBUG
appender_setPatternset the output pattern for named appender (appender must be set to a PatternLayout)appender_setPattern myAppender '%d %p - %m%n'

5.3. Logging

Table 8. Logging statements

FunctionDefinitionExample
loglog a message at a specific levellog DEBUG "Hello, world"
logger_debuglog a message at the DEBUG levellogger_debug "This is a test"
logger_infolog a message at the INFO levellogger_info "Did you get it?"
logger_errorlog a message at the ERROR levellogger_error "I sure hope you did"
logger_warnlog a message at the WARN levellogger_warn "If not, you might be in trouble"
logger_fatallog a message at the FATAL levellogger_fatal "The end of the world is here!!!"

6. Miscellaneous Info

Log4sh has been completly developed from scratch by myself, Kate Ward. I use it in production environments where logging from shell scripts is critical, and where I need more than just a simple "Hello, I worked" type of logging message. If you like what you see, or have any suggestions on improvements, please feel free to drop me an email at . If there is enough interest in the project, I will develop it further.

Log4sh is licensed under the GNU Lesser Public License. The contents and copyright of this site and all provided source code are owned by Kate Ward.