GreyLog Logging Framework

1 - Overview

GreyLog is a fully configurable, high performance logging framework, which contains particular optimisations to support 8-bit charsets (ie. the vast majority) and single-threaded mode.
It consists of the com.grey.logging Java package.

GreyLog differs from Log4j12, JUL (java.util.logging) and other logging frameworks, in that its loggers really are logfile streams, and not merely formatting handlers that cascade into a single actual logger. This means that care has to be taken when instantiating GreyLog loggers via external interfaces such as SLF4J or JCL (Apache Commons Logging).
SLF4J and JCL are biased towards Log4j12 and JUL, and developers typically expect to call org.slf4j.LoggerFactory.getLogger() or org.apache.commons.logging.LogFactory.getLog() in every module, using a different name each time, without actually creating multiple I/O streams.
In the case of GreyLog, this would result in multiple logfile streams which is probably not what you intended, so the required loggers need to be created in one place and then made available (as is the case with the Dispatcher.logger field provided by NAF).

GreyLog is part of the NAF suite, but it has no dependency on NAF's reactor core and is suitable for use by non-NAF applications, whether invoked directly or via facades like SLF4J or JCL.


2 - Configuration

GreyLog loggers are created by the com.grey.logging.Factory class, which provides a number of getLogger() factory methods.
All of them are based on a config file which is generically termed the logging.xml file (though it's not necessarily called that) and contains named entries, each of which specifies and defines a particular logger.
If you call a getLogger() variant that doesn't specify a config file, then the global default logging.xml file is used.
If you call a getLogger() variant that doesn't specify a named logger (or you specify a blank or null name), then a special logging.xml entry called the default logger is used. The default entry need not exist (though it is recommended that you do define it) and if it doesn't GreyLog will create a logger with default settings, which can be influenced by system properties (see the default constructor in the com.grey.logging.Parameters source code), but is typically the standard-output stream.
If you specify a named logger other than default, and it doesn't exist in the logging.xml file, then a SinkLogger instance is returned, which silently discards all messages written to it.

The first time the GreyLog framework tries to access the default logging.xml config file, it looks for it on the following search path, stopping on the first match:
• If the grey.logger.configfile system property is set, then it specifies the pathname.
./logging.xml (ie. look in current directory)
./conf/logging.xml
$HOME/logging.xml
• Look for it on the classpath as ./logging.xml.
If still not found, then getLogger() calls will treat all requested loggers as non-existent, so as described above, any logger other than default will get mapped to the SinkLogger.

The example below illustrates the structure of the logging.xml config file, and the logger name specified in the getLogger() call is used to select the matching logger block.

<loggers>
    <logger name="default">
        <file class="com.grey.logging.MTLatinLogger">%stdout%</file>
    </logger>
    <logger name="mylogger1">
        <file level="trc" rot="daily">%DIRLOG%/app.log</file>
    </logger>
    <logger name="mylogger2">
        <file maxfile="10M">app2.log</file>
    </logger>
</loggers>

The value of the file element specifies the pathname of the output file, which is actually a template name in which the timestamp gets embedded. It can also take the special values %stdout% and %stderr%, which will direct logging output to the process's standard-output or standard-error instead.
If it contains the special token %DIRLOG%, that will be replaced by the value of the grey.logger.dir system property.
If it contains the special token %DIRTMP%, that will be replaced by the value of com.grey.base.config.SysProps.TMPDIR.
If it contains the special token %TID%, that will be replaced by the Java thread ID (Thread.currentThread().getId()).

The attributes of the file elements are shown below.
The default values for all these config attributes are determined via system properties. See the com.grey.logging.Parameters source code.

If the system property grey.logger.diagnostics is set to Yes, then progress messages on the search for the logging.xml file and the process of creating a logger will be printed to the process's standard-output.

If the system property grey.logger.sinkstdio is set to Yes, then instead of missing loggers (ie. specified name not found in logging.xml file) being mapped to the SinkLogger, they will be mapped to a logger with default settings, ie. the same type of logger that would be created for a missing default logger (which as explained above, is typically on stdout).
This can be useful if you don't want to lose any logging output regardless of your logging.xml config.


3 - Foreign Mappings

This section describes how GreyLog instances can be redirected to external facades, such as SLF4J, JCL and JUL.

Redirection is based on the logging.xml class attribute described above:
class="com.grey.logging.adapters.AdapterSLF4J": Creates an SLF4J logger with the same name as the GreyLog logger.
class="com.grey.logging.adapters.AdapterJCL": Creates a JCL logger with the same name as the GreyLog logger.

The net effect is that the calling code will still have a GreyLog logger instance (ie. of type com.grey.logging.Logger) but all log messages will be forwarded to the external logger.
If you already manage and configure all your logging via another framework, this allows GreyLog users to tap into that without changing any Java code. Simply modify the logging.xml and the GreyLog logger joins the external logging framework.


4 - Foreign Bindings

This section is the reverse of the above, and describes how external facades such as SLF4J, JCL and JUL can be redirected to GreyLog.
As such, this is not relevant to NAF, which invokes the GreyLog framework directly, but it allows GreyLog to be transparently plugged into non-NAF code, or any code which doesn't have static (compile-time) bindings to GreyLog.

While the GreyLog framework itself has nothing to do with SLF4J, it includes an adapter library (see the greylog-slf4j Maven project) which enables it to act as underlying logger for SLF4J.
Simply put the greylog-slf4j JAR on your classpath ahead of any other SLF4J bindings, and all instantiations of SLF4J loggers will be redirected to the GreyLog framework.
That is, calls to org.slf4j.LoggerFactory.getLogger(name) will get mapped to com.grey.logging.Factory.getLogger(name) and as explained above, that will load the default logging.xml file.

Applications based on Commons Logging (JCL) can bind to the GreyLog framework by including the jcl-over-slf4j and slf4j-api JARs on their classpath, in addition to the greylog-slf4j JAR.

Applications based on the JDK's built-in JUL (java.util.logging) framework can bind to the GreyLog framework by including the jul-to-slf4j and slf4j-api JARs on their classpath, in addition to the greylog-slf4j JAR.