Syslog: White Paper FAQ Examples JavaDoc

Protomatter Syslog

Whitepaper

Nate Sammons - November, 2001
Covers Release 1.1.6

Introduction

Syslog was developed to fill the need for a simple and robust logging system that is not tied to any specific application server or to the concept of an application server in general. Since then, it has grown considerably and encompases many features that are not particularly simple. However, it is still very simple to use and can be used in various stages of complication.

Syslog provides the following features:

The general idea is that Syslog lets the programmer log messages easily through a clean API and then not worry about what happens to those messages. During development and testing, the messages may be simply sent to the console where the application is running or to a single log file. When the system is moved into production, log messages can be split up by severity (very severe messages may result in someone being paged, for instance) and log files may be rotated every night and archived. These kinds of configuration changes don't require changes to the code and can even be made while the system is running.

Syslog is licensed under the GNU Library General Public License Version 2 and is free for commercial and non-commercial use.

 

Syslog For Programmers

Simple Usage

Anytime a programmer wants to issue a message to Syslog, they simply call a static method on the com.protomatter.syslog.Syslog class. There's no need to carry around a reference to an instance of Syslog to make calls. This simplifies usage greatly -- there's no need for setup in a class that wants to use Syslog: you can just start calling log methods and that's it.

There are forty-eight methods on the Syslog class that can be used for issuing messages to the logging system. Having said that, it's unlikely in the extreme that you will use all of them. All those methods are pass-throughs to one method which takes six arguments, so the other forty-seven methods are all convenience methods for issuing messages. Don't get freaked out by how many methods you have to choose from: Syslog is a bit like a Swiss Army knife in that respect -- it probably has more blades than you'll ever need, but they're there just in case.

The simplest way programmers usually mark up their code with messages is to pepper the code with calls to "System.out.println()" -- and then invariably they have to go back and comment them out before the system goes to production. Some calls are missed and then operations people will start to ask why the application prints "I'm in here" continuously while it's running.

One way to start getting accustomed to using Syslog is to replace code like this:

With code like this:

It's not much more complicated than calling "System.out.println()" and the output is a whole lot nicer. Instead of getting output like this:

You should see something like this:

And if you have Syslog set to log the thread name and channel for each message, you'll get something like this:

Pretty fancy, eh? Later, when the system goes into production, messages at the "debug" severity can just be sent off into space and nobody will wonder why the system is printing "I'm in here" constantly.

There are log shortcuts for handling exceptions, too. If you call "Syslog.log(this, x)" where x is an java.lang.Throwable, then you'll see output like this in the log:

The output of the getMessage() method is printed as the short description, and a stack trace is printed as the detail of the message, and the whole thing is logged at the ERROR level. This is much better than spreading calls to x.printStackTrace() all over your code. As you'll see later, you can choose to route these kinds of messages to a separate log or do any number of other things with them.

Log Message Severity Levels

Syslog messages each have an associated "severity level" to show roughly how important each message is. The levels are:

DEBUG
As you might expect, these are debugging messages. Generally referred to as breadcrumbs -- good for letting the programmer leave little hints here and there during the initial coding and debugging process.
INFO
Useful informational messages about what's happening. Notable events such as user login and logout, etc.
WARNING
Something bad has happened, but the system will attempt to recover from it. These messages are usually used by programmers to show that something is starting to go wrong.
ERROR
Something bad has happened, but it's not bad enough to cause the system to fail in general. A specific task may fail and some user may get an error, but things will keep going. Exceptions are generally logged at this level.
FATAL
Something really, really bad has happened. The system is probably now in a state where it's not going to be very useful to anyone. Someone should probably be paged.

It's really important to actually use the different severity levels where they are appropriate. If every message in the system is logged at the "debug" level, the operations team can't tune things out without tuning everything out.

Log Methods

Before we go much further, let's look at the logging methods that are available on the Syslog class. The fall into three categories:

log(...)
They have the following forms:

log(Object logger, Throwable t)
log(Object logger, Throwable t, int level)
log(Object logger, Object msg, Object detail, int level)
log(Object logger, Object chan, Object msg, Object detail, int level)
log(InetAddress host, Object logger, Throwable t)
log(InetAddress host, Object logger, Throwable t, int level)
log(InetAddress host, Object logger, Object msg, Object detail, int level)
log(InetAddress host, Object logger, Object chan, Object msg, Object detail, int level)

xxx(...)
Where "xxx" is "debug", "info", "warning", "error", or "fatal" These are shortcuts to the log(...) method for each log level. They have the following forms:

xxx(Object logger, Object msg)
xxx(Object logger, Object msg, Object detail)
xxx(InetAddress host, Object logger, Object msg)
xxx(InetAddress host, Object logger, Object msg, Object detail)

xxxToChannel(...)
Where "xxx" is "debug", "info", "warning", "error", or "fatal" These are shortcuts to the log(...) method for each log level, and to a specific channel. They have the following forms:

xxxToChannel(Object logger, Object chan, Object msg)
xxxToChannel(Object logger, Object chan, Object msg, Object detail)
xxxToChannel(InetAddress host, Object logger, Object chan, Object msg)
xxxToChannel(InetAddress host, Object logger, Object chan, Object msg, Object detail)

It's fairly safe to assume that you'll never use any of the methods that include the InetAddress argument. These are used internally by Syslog, and an generally of no concern to the programmer. The rest of the arguments to the methods are:

Object logger
This is the object making the log request. Generally, the logger argument is simple "this" -- like in the example above. If there's no "this" reference where you want to do some logging (in a static method, for instance), simply pass the current class object in (if you're in a static method in the "MyClass" class, simply pass in "MyClass.class" instead of "this").

Throwable t
The methods above that explicitly take a Throwable as an argument are convenience methods. The toString() method on the Throwable is called, and it's result is passed in as the msg argument. In the case of the method that takes a Throwable and doe not take a level argument, the level is set to "error". The Throwable itself is passed on as the detail argument.

Object msg
This is intended to be a short (one-liner) description of the message. The toString() method of whatever is passed in will be called.

Object detail
If included (this argument can be null), this is treated as a longer explanation of the message. If the object passed as this argument extends Throwable then a stack trace is generated and used here.

int level
This is the severity level of the message. There are constants defined on the Syslog class for these: Syslog.DEBUG, Syslog.INFO, Syslog.WARNING, Syslog.ERROR and Syslog.FATAL.

Object channel
This is the channel name for this message. This can be one of two things: A String or an array of Strings (in which case the message is dispatched to every channel specified in the array). The default value is Syslog.ALL_CHANNEL.

Note: Exact formatting of the arguments above is actually dependent on what log formatting module is used by the logger handling the request. The above explanations of formatting assume that you are using the default log formatting module and not one of your own design.

Don't Freak Out: Yes, there's a bunch of methods there. You'll probably never, ever use all of them. If you really must have a smaller API, take a look at the Channel object. It provides a simplified logging API.

Log Message Channels

A more advanced feature of Syslog is it's support for multiple log channels, defined on-the-fly. The basic idea is that one instance of an application server (such as BEA WebLogic Server) may host multiple projects who each want to have their logs dealt with separately. From the programmer's perspective, message are just sent into channels and someone else deals with them. What happens to these messages (what files they end up in, etc) is something that can be configured at runtime. There is a default channel (whose name is the constant Syslog.DEFAULT_CHANNEL on the Syslog class) that messages go to by default, and there is also a channel named Syslog.ALL_CHANNEL that can be used to broadcast messages to every channel.

Let's say that you're running two projects ("BigBank" and "SomeOtherBigBank") on the same instance of WebLogic Server. You might want all log messages from the BigBank project to go to the "BigBankChannel" channel, and all log messages from the SomeOtherBigBank project to go to the "SomeOtherBigBankChannel" channel. There are two ways to accomplish this:

The first way is to call versions of the log(...) methods above that take a channel argument and specify the channel everywhere. This will quickly become very annoying and you'll end up either misspelling the channel name somewhere. One way to mitigate this is to have some interface in your project that defines a public static constant like this:

Then have every class specific to the BigBank project implement that interface or use it when calling log(...) methods, like this:

Programmers will quickly tire of this, though, and invariably there will be messages leaking out going to other channels, etc.

Because the above method of sending message to channels is annoying, the SyslogChannelAware interface was written. It looks like this:

Not too complicated. The idea is that any object passed in as the logger argument to one of the log(...) methods (usually "this") that implements this interface is asked what channels it wants the message to go to. If the call to Syslog included a channel (i.e. was one of the "xxxToChannel(...)" methods, etc.) then the class is not asked what channels it wants the message to go to.

Why is this good? Most of the classes in modern classes are built on top of more generic classes -- baseclasses from frameworks, etc. If each of the baseclasses used in your system implements this interface, the programmers writing subclasses never have to bother with channel names, etc. The baseclass can read a list of channels to use out of a configuration file or from some other source. This works particularly well in the case of EJBs since you could specify channels to use in the deployment descriptor for the bean. This kind of flexibility means that when a system is moved into production, different subsystems can be configured to write messages to different log channels without needing to change any code. Programmers just keep making calls to "Syslog.debug(...)" and other methods, and the messages are magically routed to the correct channel dynamically.

Simplified Channel Logging API

The Channel class provides a greatly-simplified API for making log calls. Use it like this:

One criticism of Syslog over other logging APIs, particularly Log4J, is that Log4J includes its named logger API. This channel API for Syslog is analogous to this feature in Log4J. It's not the same, but it's similar. I find this new channel API very easy to use (compared with the "regular" Syslog API). It's small and clean.

Code Examples

Here's a simple example of how to write messages at different severities:

Here's an example of how to handle exceptions. This code will produce a stack trace in the log if a SQLException is encountered.

These examples should be good enough to get you through 95% of what you'll need to do with Syslog. If you're curious, play around with all the other methods that can be used to write log messages.

JDK 1.4 Logging API Integration

Standard Is Better Than Good. Like it or not, a standard logging API is available as part of the JDK, starting with JDK 1.4. This new package, java.util.logging provides a common logging API.

Syslog is fully compatible with this new logging API. With a very simple properties file and a couple of command-line arguments to the JVM, you can transparently route all JDK-based logging calls straight into Syslog where they will be handled appropriately.

Given the following file (call it "logging.properties" for this example):

That file will instruct the JDK's logging framework to route all messages to the Syslog handler (an adapter from the JDK 1.4 logging framework to Syslog).

Next, run your program, including a couple of special options:

These extra options tell the JDK 1.4 logging framework where to read the config file from, and it also tells the Syslog adapter where a config file is. If you're using multiple configuration files, or doing something fancy, you can omit the SyslogHandler.xml option and configure Syslog yourself (JDK logging calls will still be routed to Syslog).

Given code like the following (note that there are no Syslog calls, and no references to Syslog):

You should see the following output:

Note the method name and line numbers in the output. Through a new API in JDK 1.4, Syslog is able to determine the class name, method name and source file line number where the original call to either the JDK 1.4 logging API or a Syslog API.

 

Syslog Internals

Architecture

The Syslog class itself is a singleton -- that is, there is only one instance of it per VM (or at least per classloader if you want to get picky). It contains all configuration information related to where messages are routed, who is listening for those messages, etc.

Abbreviated Syslog Architecture Diagram

Syslog maintains a list of loggers -- objects that want to listen to log messages being submitted. These logger implement the Syslogger interface -- mainly the log(SyslogMessage message) method which is called every time a message is sent to Syslog.

Once the log() method is called on the Syslogger it should (very quickly) decide if the message being logged is one that it cares about. If the message is relevant, then the logger writes the message to a file or does whatever it wants with it.

Default Implementations

The default implementation of the Syslogger interface is the BasicLogger abstract class. This is the baseclass for all the loggers that are included with Syslog.

The BasicLogger delegates the decision about paying attention to a given message to an implementation of the LogPolicy interface. The default implementation of the LogPolicy interface is the SimpleLogPolicy class. This policy knows about log message severity levels and about log channels -- it can be configured to only pay attention to messages at a certain level (or set of levels) and to only pay attention to messages arriving on a certain channel (or set of channels). This policy could easily be extended to take into account any other inputs desired (you could, for instance, have a policy that only paid attention to messages coming from objects of a certain class, etc).

The BasicLogger also delegates it's message formatting duties to an implementation of the SyslogTextFormatter interface. The default implementation of this interface is the SimpleSyslogTextFormatter class which can be configured to format log messages in a number of ways.

During initialization (in the configure(...) method) the BasicLogger passes it's initialization properties along to the configure(...) method on the log policy module and text formatting module that have been specified. Because of this, any policy or formatter module can be configured easily (this becomes particularly important when working inside an application server such as BEA WebLogic Server).

If, for some reason, you want to plug in your own LogPolicy implementation or your own SyslogTextFormatter implementation it's very simple to do with any logger that extends from BasicLogger.

 

Syslog For Operations

Included Loggers

There are several loggers included with the Syslog distribution that cover most of the bases as far as log functionality is concerned. They are:

PrintWriterLog
A logger that is attached to an instance of java.io.PrintWriter. This logger is generally attached to either System.out or System.err at runtime.

TimeRolloverLog
A logger that writes to a file that is rotated every minute, hour, day or month.

LengthRolloverLog
A logger that writes to a file that is rotated before it reaches a certain length.

FileLog
A logger that simply writes to a file.

OpenFileLog
A logger that writes to a file. The file is opened before and closed after each message is written. This is a very slow logger and should not be used unless there's some odd reason that justifies its use.

DatabaseLog
A logger that writes messages to a table in a database. This is very useful when you have multiple machines involved in a project and you want to have a unified view of everything happening on all the machines.

MailLog
A logger that connects directly to an SMTP server to send out email. It can either send plain text messages, or messages formatter in HTML.

JMSLog
A logger that publishes messages onto a JMS topic, and obeys any JTS transaction context present. This logger is designed as the mechanism to send messages to a remote log server.

RemoteLog
A logger that sends messages to objects bound under the "com.protomatter.syslog.remote" location in JNDI that implement the RemoteLogReceiver interface. This can be used as a non-transactional transport for messages to remote log servers.

Each of the above loggers extends BasicLogger and so supports pluggable log policies. All of them except for the DatabaseLog support pluggable text formatting modules.

Syslog and BEA WebLogic Server

A startup class for BEA WebLogic Server is provided with the Syslog distribution. It allows Syslog to be initialized when WebLogic boots.

To configure weblogic to initialize Syslog when it starts, add the following line to your weblogic.properties file:

You can either set the "Syslog.config.xml" system property by specifying it in the weblogic.properties file (as shown above), or by adding "-DSyslog.config.xml=ConfigFilePath" as a command-line argument to the Java VM in the startup script for WebLogic.

The SyslogT3Startup class implements the weblogic.common.T3StartupDef interface required for startup classes in WebLogic Server. That class also implements the weblogic.common.T3ShutdownDef interface, and will wait for all loggers to finish writing log entries and gracefully close all logs when WebLogic shuts down. To configure this behavior, add the following line to your weblogic.properties file:

If, for some reason, you have a startup class of your own that needs to ensure that Syslog has been configured before it starts, you can include the following code in the startup(...) method of your T3StartupDef implementation:

Syslog and Servlet Engines (including most App Servers)

Using the SyslogInitServlet servlet in a Servlet 2.2 or higher Servlet container, you can initialize Syslog automatically when a WebApp goes "live". Simply configure your web.xml for the App and configure that servlet (see the JavaDoc for more info).

Syslog and J2EE Application Servers

Using the JMSLog or RemoteLog loggers and the com.protomatter.syslog.SyslogServer command-line application, it is possible to route messages to a remote log server for processing. If the JMSLog logger is used, the logging of those messages obey J2EE transactions inside the application server.

This is a complicated matter. With that complexity, however, comes a great deal of flexability. Consider this: A cluster of application servers wants to relay transactionally correct usage information to a remote log server, which will separate messages into different log files and roll them over every hour. However, each machine in the cluster wants to log all errors and send email out to administrators when certain (very bad) conditions occur. Syslog can do this... here's how:

Application Server(s)
Syslog is configured to start when the application server boots. Its configuration includes the following loggers:

TimeRolloverLog
Configured to write all messages at or above the WARNING level out to a file on the local filesystem.

PrintWriterLog
Configured to write all messages at or above the WARNING level out to the console (System.out).

JMSLog
Configured to forward all messages at or above the INFO level to a JMS topic for further processing on another machine.

MailLog
Configured to send email to an email alias for the on-call operations staff pager when a message at or above the ERROR level is logged.

Log Server
Runs the com.protomatter.syslog.SyslogServer standalone log server, and connects to the JMS topic hosted by the application server cluster. Syslog's configuration includes the following loggers:

TimeRolloverLog
Several instances of this logger, each listening to a different log channel (one for each hosted application) and configured to write all messages at or above the WARNING level out to a file on the local filesystem.

TimeRolloverLog
Several instances of this logger, each listening to a different log channel (one for each hosted application) and configured to write all messages at the INFO level out to site usage logs on the local filesystem.

PrintWriterLog
Configured to write all messages at or above the WARNING level out to the console (System.out).

Also note that Syslog uses a JMS topic (rather than a queue). Because of this, multiple log servers could be configured to handle different sets of messages (or to redundantly handle the same messages). Splitting up the messages can either be done by specifying log policies on each server that select the messages or by using a JMS message selector to selectively process messages.

Keep in mind that all this configuration can be done without changing a single line of source code in the system (and thus changes can be made without the need to recompile anything). It could even be modified after the system has been running. If a given component is having problems, start logging all messages coming from that component to a separate log file (using the FileLog logger and the PerClassPolicy or PerChannelPolicy log policy to select messages).

If the messages do not need to obey J2EE transaction contexts in the application server (or they must not obey them), then simply replace the JMSLog with the RemoteLog in the application server, and modify the configuration of the log server accordingly. Messages will be sent via RMI instead of being carried across a JMS topic. Again, multiple servers can be used to receive those messages.

Syslog and other systems

If Syslog needs to be configured from inside another server or application, the Syslog.configure() method can be used. It will configure syslog from an XML file.

Syslog can also be configured programatically. Loggers can be added, removed and configured while things are running using methods on the Syslog class.

Syslog can also be used to log messages coming from other systems that take a PrintWriter or Writer to write log messages to. Using the SyslogWriter it is possible to create a PrintWriter that, when written to, issues messages to Syslog on a given channel at a given severity level.

Configuring Loggers

A basic Syslog configuration file looks like this:

The <Syslog> element in the configuration file can either be the root element of the document, or can also be a direct child of the root element of the document. This makes it possible to integrate the configuration of syslog with other XML-configured system in the same document.

Syslog will produce the default configuration and write it out to the console if the com.protomatter.syslog.xml.SyslogXML class is invoked from the command-line, like this:

Syslog will also parse and validate any configuration file passed in as the first command-line argument. Default values are also filled in, and the resulting configuration in printed to the console. Invoke it like this:

The <Syslog> tag has the following attributes:

Attribute Required? Description
defaultMask no Must be "DEBUG", "INFO", "WARNING", "ERROR" or "FATAL". The log mask is set to accept messages at or above the given level. If this parameter is omitted, the log mask is set to WARNING.
hostname no The hostname or IP address that Syslog believes to be the local host. This is set to whatever is returned by InetAddress.getLocalHost() if not specified.

Each logger is specified using a <Logger> tag inside the <Syslog> tag. It specifies a name for each logger (which does not have to be unique, but probably should be) and a Syslogger implementation to use. After the class is loaded, it's default constructor is called. After that, it is named and the <Logger> tag is passed to the configure() method so that the logger can configure itself. The attributes for the <Logger> tag are:

Attribute Required? Description
name yes The symbolic name of the logger.
class yes The full class name of the com.protomatter.syslog.Syslogger implementation to configure and use. The class must have a no-argument constructor.

Here is a definitive list of the parameters that are understood by the loggers included with Syslog:

BasicLogger (superclass for other loggers)
This is the superclass for all the other loggers. It provides basic functionality like delegating to log policies, configuring the text formatter, etc.

Element Required? Description
<Policy> no The log policy class and configuration to use. If not specified, the SimpleLogPolicy class will be used. The <Policy> element must have a class attribute set which specifies the policy implementation. The <Policy> element will be passed to the configure() method on the policy. The class specified must implement the LogPolicy interface and have a no-argument constructor.
<Format> no The log message formatting class and configuration to use. If not specified, the SimpleSyslogTextFormatter class will be used. The <Format> element must have a class attribute set which specifies the message formatter implementation. The <Format> element will be passed to the configure() method on the formatter. The class specified must implement the SyslogTextFormatter interface and have a no-argument constructor.

SimpleSyslogTextFormatter (default log formatter)
These parameters can be included in the <Format> element in the configuration for a logger since the BasicLogger passes that element into the log formatter when it is configured.

Element Required? Description
<dateFormat> no The format to use for the log entry date. This string must conform to the date formatting specifications used by the java.text.SimpleDateFormat class. The default value is "MM/dd/yyyy HH:mm:ss".
<dateFormatTimeZone> no The name of the timezone to use for the date formatter. The default is whatever TimeZone.getDefault() returns (the local timezone).
<dateFormatCacheTime> no The number of milliseconds to cache a formatted date string. This is a performance improvement since the SimpleDateFormat class is not incredibly fast at formatting dates. The default is 1000 (1 second).
<showChannel> no "true" or "false" -- determines if the channel name will be printed in the output. Default is false.
<showThreadName> no "true" or "false" -- determines if the thread name will be printed in the output. Default is false.
<showHostName> no "true" or "false" -- determines if the host name will be printed in the output. Default is false.
<hostWidth> no The size in characters of the host name portion of the format. Default is 15.
<classWidth> no The size in characters of the class name portion of the format. Default is 20.
<channelWidth> no The size in characters of the channel name portion of the format. Default is 15.
<threadWidth> no The size in characters of the thread name portion of the format. Default is 15.

JDK14SyslogTextFormatter (extends SimpleSyslogTextFormatter)
These parameters can be included in the <Format> element in the configuration for a logger since the BasicLogger passes that element into the log formatter when it is configured.

This class is the default when BasicLogger initializes itself under JDK 1.4. You will have to explicitly specify this format class in XML configuration files.

This class is able to accurately determine the class name, method name and source file line number where the programmer called a logging method. It uses the new StackTraceElement feature from java.lang.Throwable. This feature works transparently with the JDK 1.4 logging API also (java.util.logging.*). It's pretty cool.

Element Required? Description
<overrideClass> no "true" or "false". Should this format override whatever was passed in as the logger class argument? The default value is "true".
<includeMethod> no "true" or "false". Only used when overrideClass is set to "true". Should this format include the method name where the log call was made in the class information? The default value is "true".
<includeLineNumber> no "true" or "false". Only used when includeMethod is set to "true". Should this format include the line number where the log call was made in the class information? The default value is "true".

HTMLSyslogTextFormatter (extends SimpleSyslogTextFormatter)
These parameters can be included in the <Format> element in the configuration for a logger since the BasicLogger passes that element into the log formatter when it is configured.

Element Required? Description
<stylesheet> no The default value is "syslog-stylesheet.css".

SimpleLogPolicy (default log policy)
These parameters can be included in the <Policy> element in the configuration for a logger since the BasicLogger passes that element into the policy when it is configured.

Element Required? Description
<channels> no A comma and/or space separated list of channel names to listen to. The symbolic names DEFAULT_CHANNEL and ALL_CHANNEL are also allowed. The default is ALL_CHANNEL.
<logMask> no Must be "DEBUG", "INFO", "WARNING", "ERROR", "FATAL", "INHERIT_MASK" or a list of distict levels with the "=" character in front of each (such as "=INFO,=WARNING"). The log mask is set to accept messages at or above the given level. If this parameter is omitted or set to INHERIT_MASK, the log mask is set to inherit whatever the default log mask for Syslog as a whole is (set using the Syslog.setLogMask(...) method).

PerChannelPolicy (extends SimpleLogPolicy)
These parameters can be included in the <Policy> element in the configuration for a logger since the BasicLogger passes that element into the policy when it is configured.

This policy allows a very fine-grain of control on which messages from which channels are logged. The policy has a default log mask and channel list which behaves like the SimpleLogPolicy, but also contains a list of policy groups. Each policy group has it's own log mask and channel list and a list of Perl5 regular expressions to match against the name of the channel that issued a given log message. If one of the patterns matches and the log mask permits the message to be logged, it is logged. If none of the policy groups match, then the policy's default log mask and channel list are applied to decide if the message should be logged.

This allows you to, for instance, log all messages on the OPERATIONS_CHANNEL channel that are at or above the INFO level and come from any class in or under the "com.protomatter.jdbc.pool" package or whose name matches the "*InfoProducer*EJB" pattern, etc. It can be as simple or as complicated as you want.

Element Required? Description
<PolicyGroup> no All configuration elements from the SimpleLogPolicy policy, and a collection of <channelPattern> and/or <channelName> tags specifying a set of Perl5 regular expression patters (and explict class names) to match against the class names of log message issuers.

Each <PolicyGroup> tag can contain the following tags:

Element Required? Description
<channels> no A comma and/or space separated list of channel names to listen to. The symbolic names DEFAULT_CHANNEL and ALL_CHANNEL are also allowed. The default is ALL_CHANNEL. You should keep it at ALL_CHANNEL so that the later declarations for <channelName> and <channelPattern> elements later. This is because the channel passes if the channels listed here and one of the <PolicyGroup> definitions matches.
<logMask> no Must be "DEBUG", "INFO", "WARNING", "ERROR", "FATAL", "INHERIT_MASK" or a list of distict levels with the "=" character in front of each (such as "=INFO,=WARNING"). The log mask is set to accept messages at or above the given level. If this parameter is omitted or set to INHERIT_MASK, the log mask is set to inherit whatever the default log mask for Syslog as a whole is (set using the Syslog.setLogMask(...) method).
<channelName> no There can be as many of these tags as needed. Each is an exact, full channel name used to match against the name of the channel making a log request. If you just want to match a few channels, it's more efficient to explicitly enumerate their names than to use a regular expression.
<channelPattern> no There can be as many of these tags as needed. Each is a Perl5 regular expression used to match against the name of the channel making a log request. The set of these patterns for each policy group are converted to a single expression of the form "Expression-1|Expression-2|...|Expression-N" (the logical or of the set) for faster matching.

PerClassPolicy (extends SimpleLogPolicy)
These parameters can be included in the <Policy> element in the configuration for a logger since the BasicLogger passes that element into the policy when it is configured.

This policy allows a very fine-grain of control on which messages from which objects are logged. The policy has a default log mask and channel list which behaves like the SimpleLogPolicy, but also contains a list of policy groups. Each policy group has it's own log mask and channel list and a list of Perl5 regular expressions to match against the name of the class that issued a given log message. If one of the patterns matches and the log mask and channel list permit the message to be logged, it is logged. If none of the policy groups match, then the policy's default log mask and channel list are applied to decide if the message should be logged.

This allows you to, for instance, log all messages on the OPERATIONS_CHANNEL channel that are at or above the INFO level and come from any class in or under the "com.protomatter.jdbc.pool" package or whose name matches the "*InfoProducer*EJB" pattern, etc. It can be as simple or as complicated as you want.

Element Required? Description
<PolicyGroup> no All configuration elements from the SimpleLogPolicy policy, and a collection of <classPattern> and/or <className> tags specifying a set of Perl5 regular expression patters (and explict class names) to match against the class names of log message issuers.

Each <PolicyGroup> tag can contain the following tags:

Element Required? Description
<channels> no A comma and/or space separated list of channel names to listen to. The symbolic names DEFAULT_CHANNEL and ALL_CHANNEL are also allowed. The default is ALL_CHANNEL.
<logMask> no Must be "DEBUG", "INFO", "WARNING", "ERROR", "FATAL", "INHERIT_MASK" or a list of distict levels with the "=" character in front of each (such as "=INFO,=WARNING"). The log mask is set to accept messages at or above the given level. If this parameter is omitted or set to INHERIT_MASK, the log mask is set to inherit whatever the default log mask for Syslog as a whole is (set using the Syslog.setLogMask(...) method).
<className> no There can be as many of these tags as needed. Each is an exact, full class name used to match against the name of the class making a log request. If you just want to match a few classes, it's more efficient to explicitly enumerate their names than to use a regular expression.
<classPattern> no There can be as many of these tags as needed. Each is a Perl5 regular expression used to match against the name of the class making a log request. The set of these patterns for each policy group are converted to a single expression of the form "Expression-1|Expression-2|...|Expression-N" (the logical or of the set) for faster matching.

TimeRolloverLog (extends BasicLogger)
This log writes to a file and rotates it on the minute, hour, day or month change.

Element Required? Description
<baseName> yes The base filename of the log files that will be created.
<nameFormat> no A date format that is appended to the baseName when a new file is going to be written. This string must conform to the specification for date formats used by the java.text.SimpleDateFormat class. The default value is "yyyy.MM.dd-HH.mm.ss".
<extension> no The filename extension of the files that will be created. The default is nothing.
<append> no "true" or "false" -- If a file that's about to be written to already exists, should we append to it or overwrite it? Default is true.
<autoFlush> no "true" or "false" -- Output to the file is buffered to increate speed. If this option is set to false then buffering occurrs. If it is set to true (the default), then the output stream is flushed each time a log entry is written.
<roll> yes Must be "ROLL_MINUTELY", "ROLL_HOURLY", "ROLL_DAILY", or "ROLL_MONTHLY". Determines how frequently the log file will be rotated.

LengthRolloverLog (extends BasicLogger)
This log writes to a file and rotates it before it gets to be a certain size.

Element Required? Description
<baseName> yes The base filename of the log files that will be created.
<extension> no The filename extension of the files that will be created. The default is nothing.
<append> no "true" or "false" -- If a file that's about to be written to already exists, should we append to it or overwrite it? Default is true.
<autoFlush> no "true" or "false" -- Output to the file is buffered to increate speed. If this option is set to false then buffering occurrs. If it is set to true (the default), then the output stream is flushed each time a log entry is written.
<rollSize> no The maximum size (in bytes) of the log file. Default is 1MB.

FileLog (extends BasicLogger)
Simply writes messages to a file.

Element Required? Description
<fileName> yes The filename of the log file that will be created.
<append> no "true" or "false" -- If a file that's about to be written to already exists, should we append to it or overwrite it? Default is true.
<autoFlush> no "true" or "false" -- Output to the file is buffered to increate speed. If this option is set to false then buffering occurrs. If it is set to true (the default), then the output stream is flushed each time a log entry is written.

OpenFileLog (extends BasicLogger)
Element Required? Description
<fileName> yes The filename of the log file that will be created.
<append> no "true" or "false" -- If a file that's about to be written to already exists, should we append to it or overwrite it? Default is true.

PrintWriterLog (extends BasicLogger)
Writes messages to a printwriter (such as System.out or System.err).

Element Required? Description
<stream> yes The name of the stream to attach to. Must be either "System.out" or "System.err".

DatabaseLog (extends BasicLogger)
Writes messages to a database via JDBC. This logger maintains a connection to a database where log entries will be written. It truncates data to pre-defined lengths before attempting to write to the database.

Element Required? Description
<driver> yes The JDBC driver class to use when connecting to the database.
<url> yes The JDBC URL to use when connecting to the database.
<numRetries> no The number of times to attempt writing each message to the database. After the first error, the JDBC connection is re-initialized. If the message cannot be written after the given number of tries, the message and an explanation of what went wrong writing to the database is printed to System.err. The default is 3.
<tablePrefix> no The name prefix for tables. See the JavaDoc for this logger for information about the necessary table structure. Default is nothing.
<messageWidth> no The width of the column that is used to write the short message. Default is 255.
<detailWidth> no The width of the column that is used to write the message detail. Default is 4000.
<statementAdapter> no The name of a class which implements the DatabaseLogStatementAdapter interface. Since different database drivers work differently with data types, this abstracts the code that sets the PreparedStatement variable for the message detail column. There are several implementations of this which are included with Syslog: setString(), setAsciiStream(), and setCharacterStream(). If you have to write a custom one for some driver, please let me know so it can get included with the standard distribution.
<ConnectionProperties> no Contains a set of <property> elements, each containing a <name> and <value> element defining the connection properties.

JMSLog (extends BasicLogger)
Publishes log messages onto a JMS topic. This effectively provides a way to manage Syslog messages inside JTA transactions when operating inside a J2EE application server, such as BEA WebLogic. Messages can be pulled off the JMS topic remotely for further processing on a log server. See the javadoc for this logger, and for the com.protomatter.syslog.SyslogServer class for more information.

Element Required? Description
<topicName> yes The JNDI location of a JMS topic to publish messages to.
<factoryName> yes The JNDI location of a JMS connection factory to use to attach to the JMS system.
<connectionUser> no The username to use while creating a JMS connection. This is not related to JNDI credentials.
<connectionPass> no The password to use while creating a JMS connection. This is not related to JNDI credentials.
<persistent> no Should the JMS messages be persistent. Default is false.
<ttl> no The JMS message time to live, in milliseconds. Default is 30 minutes.
<priority> no The JMS message priority. Default is 5.

RemoteLog (extends BasicLogger)
Writes messages to (possibly) remote objects bound into the local JNDI tree. Messages can be received remotely for further processing on a log server. See the javadoc for this logger, and for the com.protomatter.syslog.SyslogServer class for more information. It has no configuration parameters of its own.

MailLog (extends BasicLogger)
Sends email by connecting directly to an SMTP server. The message can either be plain text or can be HTML formatted.

Element Required? Description
<SubjectFormat> no The mail message subject formatting class and configuration to use. If not specified, the SimpleSyslogMailSubjectFormatter class will be used. The <SubjectFormat> element must have a class attribute set which specifies the message subject formatter implementation. The <SubjectFormat> element will be passed to the configure() method on the formatter. The class specified must implement the SyslogMailSubjectFormatter interface and have a no-argument constructor.

Element Required? Description
<server> yes The SMTP server hostname or IP address.
<port> no The port number on the SMTP server to connect to. The default value is 25.
<workQueue> yes The symbolic name of a work queue to use. If left blank, the default work queue will be used.
<html> no Should the message be sent as a MIME message? true or false. If this is set to true, it is expected that the message formatter will actually produce HTML.
<to> yes A comma-separated list of email addresses to send messages to.
<cc> no A comma-separated list of email addresses to include in the CC (carbon-copy) list.
<bcc> no A comma-separated list of email addresses to include in the BCC (blind carbon-copy) list.
<from> yes The email address that the mail should appear to be from.
<fromName> no The name (not address) that the mail should appear to be from.

SimpleSyslogMailSubjectFormatter (default mail subject formatter)
These parameters can be included in the <SubjectFormat> element in the configuration for a MailLog logger since the MailLog passes that element into the subject formatter when it is configured.

Element Required? Description
<dateFormat> no The format to use for the log entry date. This string must conform to the date formatting specifications used by the java.text.SimpleDateFormat class. The default value is "HH:mm:ss MM/dd".
<dateFormatTimeZone> no The name of the timezone to use for the date formatter. The default is whatever TimeZone.getDefault() returns (the local timezone).
<dateFormatCacheTime> no The number of milliseconds to cache a formatted date string. This is a performance improvement since the SimpleDateFormat class is not incredibly fast at formatting dates. The default is 1000 (1 second).
<showChannel> no "true" or "false" -- determines if the channel name will be printed in the output. Default is false.
<showThreadName> no "true" or "false" -- determines if the thread name will be printed in the output. Default is false.
<showHostName> no "true" or "false" -- determines if the host name will be printed in the output. Default is false.

 

Miscellaneous

Online Resources

http://protomatter.sourceforge.net -- the protomatter software site hosted by SourceForge.net. The latest version of these classes (and this whitepaper) are always available there.

Future Direction

There are really two things that I'd like to add to Syslog at this point:

JMX Management
This is really my Holy Grail at this point. The idea is to add a series of JMX beans to allow Syslog to be configured from a JMX console. This could prove to be much better than using a text editor to play with configurations.
XML Schema Support
I think it would be nice to have the XML configurations checked by an XML schema. Right now, there's no DTD, and there's no schema, so all the data is checked programatically. This works really well, though, especially since it's possible to add entirely new configuration information by subclassing existing objects. Getting this kind of thing to work with a DTD or an XML schema could be tricky. In any case, it's something to look into.