Send runtime messages to one or more output destinations.

# Logging Service

- Overview
- Using the Logging Service
- Features of the Logging Service
- Guidelines for Logging Service messages
- Examples

## Overview

The Logging Service is used to send runtime messages to one or more output destinations. There are various types of output destinations for log messages, such as the console, a file, or a socket connection. The format of information sent to each of these destinations can be independently configured and controlled. Configuration is achieved through static configuration files and also by invoking runtime methods that control logging output. Remote ( cross-JVM ) logging is supported, as is the ability to log both per user session and per JVM. For details, see the section on Remote Logging.

## Using the Logging Service

There are several aspects to using the Logging Service, and these can be outlined as follows:

- Configuring the Logging Service
- Obtaining a Logger from the Logging Service
- Writing log messages from your code
- Controlling log output at runtime

These will be discussed separately below.

### Configuring the Logging Service

Logging Service configuration, like the configuration for other services, is specified within a deployment configuration supplied to the Discovery Service. See the section on Discovering A Service in the Discovery Service documentation for details on the discovery process. Within the deployment configuration there is an xml Document fragment that specifies Logging Service configuration information. The possible elements in that configuration are described below. A sample configuration is also included in this document.

It is also possible to specify a logging configuration file that over-rides the settings present in the OMR-based Services deployment configuration. This is motivated by the need to be able to easily change the logging settings at runtime, without having to wade through the Services metadata configuration file or employ the SAS Management Console. The OMR-based configuration can be viewed as the "base" or "production" configuration, while the alternate logging config file would be for temporary or debugging purposes. Note that the settings from the alternate configuration file completely replace the setting from the deployment configuration.

The alternate configuration file ( URL ) is specified via an environment variable, which can be set on the Java command line that starts the application. Here is an example of the option:

    -Dcom.sas.services.logging.configurationURL=file:C:\sample\LoggingConfig.xml

The format of the file needs to be as described below, and as seen in the sample configuration included in this document.

#### Configuration Elements

The Document fragment that makes up the Logging Service configuration contains these elements:

- LoggingService - The LoggingService element is the top-level element in the Logging Service configuration. It can have these attributes:
  - implementation - This attribute names the underlying logging implementation to be used. Currently, only the default value, `"log4j"` is valid. In the future, other implementations may be available.
  - isBasicLogging - This attribute can be set to either `"true"` or `"false"` ( the default value ). If it is set to `"true"`, then the rest of the configuration, other than the `basicLoggingPriority` attribute, will be ignored. Log messages will be sent to the console and formatted in a simple manner. See the sample configurations for an example.
  - basicLoggingPriority - Use this to set logging priority when `isBasicLogging` is `"true"`.
  - isMessageCounting - This attribute can be set to either `"true"` or `"false"` ( the default value ). If it is set to `"true"`, then a count of messages, both those output and suppressed, is maintained for each priority level of message. See the section on Message Counting for more information.

Within the LoggingService element, these sub-elements may be present:

- RootLoggingContext - Specifies the characteristics of the root logging context. Any logging context not otherwise configured will fall into the root context. Attributes of this element include:
  - priority - Specifies the priority of the root logging context. The default value is DEBUG.

  In addition, the RootLoggingContext element can have OutputRef sub-elements that associate this logging context with specific Output elements, defined elsewhere in the configuration. Each OutputRef sub-element has a single attribute, outputID, which names the associated Output element.

- LoggingContext - Specifies the characteristics of a named logging context. Attributes of this element include:
  - priority - Specifies the priority of this logging context. If no priority is specified, then the priority of the next context in this context's hierarchy that defines a priority will be used.
  - name - A required attribute that names this logging context.
  - chained - This attribute can be set to either `"true"` ( the default value ) or `"false"`. It controls whether or not a log message is processed by logging contexts higher in the logging context hierarchy. See the section on chaining elsewhere in this document.

  In addition, the LoggingContext element can have OutputRef sub-elements that associate this logging context with specific Output elements, defined elsewhere in the configuration. Each OutputRef sub-element has a single attribute, outputID, which names the associated Output element.

- Output - Specifies an output destination for logging messages. Attributes of this element include:
  - id - The identifier for this logging destination. The logging contexts will refer to this id via their `OutputRef` sub-elements. This is a required attribute.
  - type - Can be one of `"Console"`, `"File"`, or `"Socket"`. A required attribute that specifies the type of the logging destination.
  - layoutPattern - Indicates how the message will be formatted. See the section on Pattern Layout for more information.
  - async - This attribute can be set to either `"true"` or `"false"` ( the default value ) . It controls whether or not asynchronous logging is activated. See the section on Asynchronous Logging elsewhere in this document.

  In addition, the Output element can have param sub-elements that are specific to that type of output. Each param element has two attributes: name and value. The possible name/value pairs, by output type are:

  For File:

  - File - The value will indicate the file for output.
  - Append - Can be `"true"` ( the default value ) or `"false"`. If true, logging output is appended to existing output in the named file.
  - ImmediateFlush - Can be `"true"` ( the default value ) or `"false"`. If true, output is flushed to the file after each logging statement. Setting this to false may enhance performance, at the cost of potentially losing the output from the last few logging statements.
  - MaxBackupIndex - Indicates the maximum backup index for output files when size-based rollover is active. The default value, when size-based rollover is active, is `"1"`. See the section on Size-based Rollover elsewhere in this document for details.
  - MaxFileSize - Indicates the maximum file size for the output file when size-based rollover is active. The default value, when size-based rollover is active, is `"10MB"`. See the section on Size-based Rollover elsewhere in this document for details.
  - DatePattern - Indicates the date pattern for the output file when frequency-based rollover is active. See the section on Frequency-based Rollover elsewhere in this document for details.

  For Console:

  - Target - The value will indicate the output destination. Can be one of `"System.out"` or `"System.err"`. The default value is `"System.out"`.
  - ImmediateFlush - Can be `"true"` ( the default value ) or `"false"`. If true, output is flushed to the file after each logging statement. Setting this to false may enhance performance, at the cost of potentially losing the output from the last few logging statements.

  For Socket:

  - Port - The value will indicate the socket port number.
  - Host - The value will name the socket host.

- Renderer - Specifies a {@link com.sas.services.logging.RendererInterface RendererInterface} implementation class used to provide custom logging output. Attributes of this element include:
  - renderedClass - Specifies the class to be rendered.
  - renderingClass - The class that will do the rendering.

  See the section on Custom Object Rendering elsewhere in this document for details.

### Obtaining a Logger from the Logging Service

The Logging Service is located through the Discovery Service. The Discovery Service returns a LoggingServiceInterface:

    LoggingServiceInterface loggingService = (LoggingServiceInterface)
        DiscoveryService.defaultInstance().findService(
             new ServiceTemplate(
                new Class[] {com.sas.services.logging.LoggingServiceInterface.class}));

The Discovery Service is also used to obtain a SessionServiceInterface object, and through it a SessionContextInterface:

    SessionServiceInterface sessionService = (SessionServiceInterface)
        DiscoveryService.defaultInstance().findService(
             new ServiceTemplate(
                new Class[] {com.sas.services.session.SessionServiceInterface.class}));

    SessionContextInterface currentSessionContext =
    	sessionService.newSessionContext(null);

The LoggingServiceInterface is then used to get a LoggerInterface. This is accomplished by invoking the getLogger method on the LoggingServiceInterface:

    LoggerInterface myLog =
    	loggingService.getLogger(MyApp.class.getName(), currentSessionContext);

There are several noteworthy points displayed by this example:

- The first parameter of the getLogger method is the logging context. The convention shown here is to use the fully-qualified name of the module ( class ) in which the logging is going to be done. In the example, which is assumed to be from the MyApp application, the getName() method of the Class object is used to get the fully-qualified class name.
- The second parameter is the current SessionContext. This should be the SessionContext of the currently executing session. ( See the documentation for the Session Service. )

### Writing log messages from your code

Once a LoggerInterface is obtained, logging calls can be made on it. There are five levels of priority of log messages. In increasing order of priority they are: DEBUG, INFO, WARN, ERROR, and FATAL. The LoggerInterface contains static integer variables for these levels, and they can be used when invoking the log() method on the LoggerInterface:

    logger.log( LoggerInterface.INFO, "This is an informational message." );

There is also a convenience method for each of the logging levels, so the above informational message would normally be coded as:

    logger.info( "This is an informational message." );

Each LoggerInterface object has a priority associated with it, either set during configuration or by invoking the setPriority method. When a logging call is made, the priority of the message is compared with the priority of the LoggingInterface object. If the message priority is greater than or equal to the priority of the LoggingInterface object, then the logging call is processed. Otherwise, the logging call is not processed, and no message is transmitted. For example, if a LoggerInterface object has priority WARN, then messages of priority WARN, ERROR, and FATAL will be processed, but messages of priority DEBUG and INFO will not be processed.

For enhanced performance, there are methods that check to see if a particular level of logging is enabled. These are of the form isModeEnabled(), where Mode is one of Debug, Info, Warn, Error, or Fatal. Here is an example usage:

    // log a debug message
    if ( logger.isDebugEnabled() )
    	logger.debug(message);

The use of these performance enhancing methods to guard against unnecessary invocation of logging methods becomes more important as the complexity of preparing the log message increases. For example, expensive string concatenations and additional method invocations to obtain localized strings can be avoided by first checking if the desired level of logging is enabled. It is also recommended that all invocations of the methods `debug()` and `info()` be guarded ( surrounded ) by invocations of `isDebugEnabled()` and `isInfoEnabled()` respectively, since these methods would normally not produce any output in a production environment, and would thus negatively impact performance with no added value.

### Controlling log output at runtime

There are methods on the LoggerInterface to control the output of the logging calls. Methods that add a logging destination include addConsoleOutput, addFileOutput, and addSocketOutput. There are also methods to remove logging output destinations: removeConsoleOutput, removeFileOutput, removeSocketOutput, and removeAllOutputs. Each of these methods control logging in the local JVM ( See the section on Remote Logging for an explanation of remote vs. local logging. These methods also only modify the current logging context.

## Features of the Logging Service

The features of the Logging Service include:

- Hierarchical name space of logging contexts
- Output from multiple contexts through Chaining
- Remote Logging
- Asynchronous Logging
- Pattern Layout for easy formatting of output
- Custom Object Rendering
- MessageCounting
- Rollover Output Files

- Size-based Rollover
- Frequency-based Rollover

- Debugging the Logging Service

### Hierarchical name space of logging contexts

When you specify the logging context in the invocation of the getLogger method, or when you specify the logging context on any of the methods of the LoggerInterface that accept a logging context, you are associating the logging calls with a particular logging context. The output of messages from a given logging context is controlled through configuration settings and through calls to the LoggerInterface methods that control output. One feature of the Logging Service is the hierarchical control of these contexts, based on the "dot" notation, as used in fully-qualified class names in the Java language. One possible convention is to use the fully-qualified Java class names for the logging context, as a way of achieving an organized framework of logging contexts. This name can be found by using the `Class.getName()` method. For example, the fully qualified class name of the `MyApp` class can be found by invoking:

    MyApp.class.getName();

As an example of the hierarchical nature of logging contexts, if there is no configuration present for the "com.sas.services.events" logging context, then the configuration of the "com.sas.services" logging context will control logging calls made in the "com.sas.services.events" logging context. If the "com.sas.services" context is not configured, then the "com.sas" context will be used. This hierarchy is followed on up to the "root" or "default" logging context.

In a similar fashion, this hierarchy is also used to determine the priority for logging contexts that do not have a specified priority. For example, if the logging context "com.sas.services.events" is configured but does not have an assigned priority, then the priority for "com.sas.services", ( or possibly a context on up the hierarchy ), will be used.

### Output from multiple contexts through Chaining

When an enabled logging call is made, by default the log message is not only given to the current logging context, but is passed to each logging context in the context hierarchy of the current logging context. This is known as Chaining. Chaining can be controlled by use of the chained attribute of the LoggingContext configuration element. It can also be set programmatically by using the setChained method. When Chained is set to false at a given level in the logging context hierarchy, the log message will not be passed beyond that level in the hierarchy.

### Remote Logging

Remote logging is the ability to send log messages generated in one Java virtual machine (JVM) to another JVM. This is accomplished by setting the SessionContext on the LoggerInterface object, by specifying it as a parameter to the getLogger method of the LoggingServiceInterface. When a LoggerInterface object has an associated SessionContext, and that SessionContext is from a different JVM than the LoggerInterface object, then logging is done in both JVM's. In this way, a log can be created per-server ( per-JVM ) and also per-session. An example of a per-server log might be a system console that tracks all activity on a particular computer. A per-session log would report the activity of a user session, typically the run of a single application, which in a distributed environment might be accessing services running in a number of JVMs, potentially on a number of separate computers. It is also possible to use the LoggerInterface object contained in a SessionContext in order to directly log information to the JVM of the SessionContext. Through the selective specification of SessionContext, and/or the use of the LoggerInterface from a SessionContext, it is possible to log in any combination of local ( per-server ) and remote ( per-session ) logging. See the Examples section for samples of how to achieve the various local and remote logging results.

Remote logging can be disabled by setting the disable remote logging environment variable to true on the Java command line:

    -Dcom.sas.services.logging.disableRemoteLogging=true

### Asynchronous Logging

With asynchronous logging, log messages are queued up within, and delivered from, a separate thread, relieving the main application thread(s) of this chore. As expected, this shows the greatest benefit in applications that involve the most blocking operations, such as I/O, network access, sleeping threads, etc. In these cases, the logging is accomplished partially or completely while the application threads are blocked.

To utilize this functionality, set the async parameter of the Output element of the Logging Service configuration to "true", as in this example:

    <Output id="A1" type="Console" async="true" layoutPattern="%-5p %c - %m%n">

There is some overhead associated with asynchronous logging, so the default value is `"false"`. Use of this feature needs to be determined on a case by case basis, based on the amount of blocking operations expected in the application(s) involved.

### Pattern Layout for easy formatting of output

One of the features of Logging Service is the ability to associate a layout with a logging output such as a file or the console. The layout specifies how the output is formatted before being sent to the output device. The layout is specified as a pattern string similar to the ones used in the C language printf statement. This string can contain plain text plus conversion specifiers ( that start with the percent "%" character ) which are replaced by the specified value when the string is output. For example, %d is replaced by the current date/time, %m is replaced by the message specified in the logging call, etc. Layout strings can be specified in the configuration of the Logging Service, and are also used in versions of the addConsoleOutput, addFileOutput, and addSocketOutput methods of the LoggerInterface.

Following is a some detailed information on pattern strings and a full list of the conversion specifiers. This information was taken from the documentation for the PatternLayout class in the log4j javadoc, and slightly modified. ( The log4j PatternLayout has been used as a model for the Logging Service pattern strings. )

The goal is to format a logging event and return the results as a String. The results depend on the pattern string.

The pattern string is closely related to the conversion pattern of the printf function in C. A pattern string is composed of literal text and format control expressions called conversion specifiers.

You are free to insert any literal text within the pattern string.

Each conversion specifier starts with a percent sign (%) and is followed by optional format modifiers and a conversion character. The conversion character specifies the type of data, e.g. logging context, priority, date, thread name. The format modifiers control such things as field width, padding, left and right justification. The following is a simple example. ( See Obtaining a Logger from the Logging Service for a complete example of obtaining a LoggerInterface object. )

Let the pattern string configured for the MyApp class be "%-5p [%t]: %m%n". Then the statements:

    LoggerInterface myLog =
    		loggingService.getLogger(MyApp.class.getName(), currentSessionContext);
    myLog.debug("Message 1");
    myLog.warn("Message 2");

would yield the output:

    DEBUG [main]: Message 1
    WARN  [main]: Message 2

Note that there is no explicit separator between text and conversion specifiers. The pattern parser knows when it has reached the end of a conversion specifier when it reads a conversion character. In the example above the conversion specifier %-5p means the priority of the logging event should be left justified to a width of five characters. The recognized conversion characters are

Conversion Character | Effect
c | Used to output the logging context. The logging context conversion specifier can be optionally followed by precision specifier, that is a decimal constant in brackets. If a precision specifier is given, then only the corresponding number of right most components of the logging context name will be printed. By default the logging context name is printed in full. For example, for the logging context name "a.b.c" the pattern %c{2} will output "b.c".
d | Used to output the date of the logging event. The date conversion specifier may be followed by a date format specifier enclosed between braces. For example, %d{HH:mm:ss,SSS} or %d{dd MMM yyyy HH:mm:ss,SSS}. If no date format specifier is given then ISO8601 format is assumed. The date format specifier admits the same syntax as the time pattern string of the `SimpleDateFormat`. Although part of the standard JDK, the performance of `SimpleDateFormat` is quite poor. Information specific to a log4j implementation: For better results it is recommended to use the log4j date formatters. These can be specified using one of the strings "ABSOLUTE", "DATE" and "ISO8601" for specifying `AbsoluteTimeDateFormat`, `DateTimeDateFormat` and respectively `ISO8601DateFormat`. For example, %d{ISO8601} or %d{ABSOLUTE}. These dedicated date formatters perform significantly better than `SimpleDateFormat`.
l | Used to output location information of the caller which generated the logging event. The location information depends on the JVM implementation but usually consists of the fully qualified name of the calling method followed by the callers source the file name and line number between parentheses. The location information can be very useful. However, it's generation is extremely slow. It's use should be avoided unless execution speed is not an issue.
m | Used to output the application supplied message associated with the logging event.
n | Outputs the platform dependent line separator character or characters. This conversion character offers practically the same performance as using non-portable line separator strings such as "\n", or "\r\n". Thus, it is the preferred way of specifying a line separator.
p | Used to output the priority of the logging event.
r | Used to output the number of milliseconds elapsed since the start of the application until the creation of the logging event.
s | Used to output the session ID associated with this logging event. The output for this conversion character will be an empty string if the Logger being used does not have an associated SessionContext.
t | Used to output the name of the thread that generated the logging event.
u | Used to output the user name associated with this logging event. The output for this conversion character will be an empty string if the Logger being used does not have an associated SessionContext, or if that SessionContext does not have an associated UserContext.
% | The sequence %% outputs a single percent sign.

The default pattern is "%m%n", which simply outputs the message parameter of the logging call, along with the newline character.

[TBD: Possible support for the %s pattern specifier for session context information.]

By default the relevant information is output as is. However, with the aid of format modifiers it is possible to change the minimum field width, the maximum field width and justification.

The optional format modifier is placed between the percent sign and the conversion character.

The first optional format modifier is the left justification flag which is just the minus (-) character. Then comes the optional minimum field width modifier. This is a decimal constant that represents the minimum number of characters to output. If the data item requires fewer characters, it is padded on either the left or the right until the minimum width is reached. The default is to pad on the left (right justify) but you can specify right padding with the left justification flag. The padding character is space. If the data item is larger than the minimum field width, the field is expanded to accommodate the data. The value is never truncated.

This behavior can be changed using the maximum field width modifier which is designated by a period followed by a decimal constant. If the data item is longer than the maximum field, then the extra characters are removed from the beginning of the data item and not from the end. For example, it the maximum field width is eight and the data item is ten characters long, then the first two characters of the data item are dropped. This behavior deviates from the printf function in C where truncation is done from the end.

Below are various format modifier examples.

Format modifier | left justify | minimum width | maximum width | comment %20c | false | 20 | none | Left pad with spaces if the logging context name is less than 20 characters long.
%-20c | true | 20 | none | Right pad with spaces if the logging context name is less than 20 characters long.
%.30c | NA | none | 30 | Truncate from the beginning if the logging context name is longer than 30 characters.
%20.30c | false | 20 | 30 | Left pad with spaces if the logging context name is shorter than 20 characters. However, if logging context name is longer than 30 characters, then truncate from the beginning.
%-20.30c | true | 20 | 30 | Right pad with spaces if the logging context name is shorter than 20 characters. However, if logging context name is longer than 30 characters, then truncate from the beginning.

Below are some examples of pattern strings.

%r [%t] %-5p %c - %m\n

  This will output the relative time, the thread name inside square brackets, the priority left justified in a 5 character space, the logging context, and the logging message.

%-6r [%15.15t] %-5p %30.30c - %m\n

  Similar to the above layout except that the relative time is right padded if less than 6 digits, thread name is right padded if less than 15 characters and truncated if longer, and the logging context name is left padded if shorter than 30 characters and truncated if longer.

The above text is largely inspired from Peter A. Darnell and Philip E. Margolis' highly recommended book "C -- a Software Engineering Approach", ISBN 0-387-97389-3.

### Custom Object Rendering

It's possible to implement a class to be a renderer class for another class or classes ( or have a class act as its own renderer ). When this is done, the renderer class will be called upon to format the logging output from objects of the rendered class when they are the subject of a logging method. The renderer class needs to implement the {@link com.sas.services.logging.RendererInterface RendererInterface} and its {@link com.sas.services.logging.RendererInterface#doRender(Object) doRender} method. The rendering and rendered classes are specified by a Renderer element in the Logging Service configuration:

    <Renderer renderedClass="com.sas.services.SampleApplication"
              renderingClass="com.sas.services.SampleAppRenderer"/>

Note that when an object is presented to a logging method, and a renderer class has not been specified, then the output will be the result of the toString() method for that object.

### Message Counting

It's possible to configure the Logging Service to maintain a count of messages, both those output and suppressed, for each priority level of message. These counts can then be accessed ( and logged ) by the code using the Logging Service. For example, an application might want to report how many WARNING and ERROR messages were output during application initialization.

Message counting is controlled by various methods of the {@link com.sas.services.logging.LoggerInterface LoggerInterface} and the {@link com.sas.services.logging.MessageCount MessageCount} classes. It can be turned on in one of three ways: by setting the isMessageCounting attribute of the Logging Service configuration element to `true`; by setting the message counting environment variable to true:

    -Dcom.sas.services.logging.messageCounting=true

It is also possible to turn message counting on programmatically by using the {@link com.sas.services.logging.LoggerInterface#setMessageCounting(boolean) setMessageCounting} method, although this technique is discouraged in the general case, since it will over-ride configuration and command line settings.

It's important to note that counting is done across all logging contexts, not just within the current logging context of the {@link com.sas.services.logging.LoggerInterface LoggerInterface} object upon which the message counting methods are invoked.

### Rollover Output Files

Under some circumstances, a log file can grow to an unmanageable size, so the Logging Service allows for log file rollover. With this process, the currently accumulating log file is closed and renamed, and a new file is opened to receive subsequent log data. There are two types of rollover. One is size-based, meaning rollover occurs when the file reaches a specified size. The other is frequency-based, meaning rollover occurs on a specified time table, such as daily, weekly, monthly, etc. These two types of rollover are described below.

#### Size-based Rollover

With size-based rollover, whenever the log file reaches a specified size the currently accumulating log file is closed and renamed, and a new file is opened to receive subsequent log data. Size-based rollover is enabled by setting the MaxBackupIndex parameter and/or the MaxFileSize parameter on a File type Output element. ( If only one of these two values is set, then a default value is used for the other. )

The MaxFileSize parameter indicates the size of the logging files before rollover occurs. The numeric value specified can end in a suffix of KB, MB, or GB, to arrive at the obvious values: to limit your files to 10 megabytes use "10MB", for example.

The MaxBackupIndex parameter says how many backup files before the oldest gets deleted. If set to zero ( "0" ), then there will be no backup files and the log file will be truncated ( made empty ) when it reaches MaxFileSize.

If your file is specified as myLog.log, for example, then after rollovers new data will be added to myLog.log, the next oldest file will be myLog.log.1, the second next oldest will be myLog.log.2, etc.

It is also possible to specify MaxFileSize and MaxBackupIndex for all files by using command line options when starting your application. Here are some examples:

    -Dcom.sas.services.logging.maxFileSize=256KB
    -Dcom.sas.services.logging.maxBackupIndex=16

Settings on the command line take precedence over individual settings on the File type Output element. If only one of these options is set on the command line, then the parameter from the File type Output element for the other option will be used.

In all cases, if only one of the two options are specified, either on the command line or in the Output element, then the default value will be used for the other option.

#### Frequency-based Rollover

With frequency-based rollover, on a specified schedule the currently accumulating log file is closed and renamed, and a new file is opened to receive subsequent log data. Frequency-based rollover is enabled by setting the DatePattern parameter on a File type Output element. The date pattern determines the rollover freqency and the suffix appended to the file name. For example, to rollover a file daily at midnight, you would use a date pattern of `"'.'yyyy-MM-dd"`. Using this pattern, an active log file named `myApp.log` would be renamed to `myApp.log.2010-12-11 on December 11, 2010`. See the log4j documentation for the DailyRollingFileAppender for more information on the available values for the DatePattern parameter. It is also possible to specify a DatePattern for all files by using a command line option when starting your application. Here is an example:

    -Dcom.sas.services.logging.datePattern="'.'yyyy-MM-dd"

Settings on the command line take precedence over individual settings on the File type Output element. If both an individual DatePattern parameter is present in a logging service configuration and the -Dcom.sas.services.logging.datePattern option is present on the Java command line, then the Java command line setting takes precedence.

#### General Notes on Rollover

If both size-based rollover and frequency-based rollover are specified for a file, either in the logging service configuration or on the command line, then the sized-based rollover settings will take precedence.

There should be only one rollover Output element per actual file ( two rollover Outputs should not send logging output to the same file ).

### Debugging the Logging Service

In order to trace down logging problems, it's possible to configure the Logging Service to output additional messages about its operation. This is done by setting the Logging Service debug environment variable, which can be set on the Java command line that starts the application:

    -Dcom.sas.services.logging.debug=true

## Guidelines for Logging Service messages

Having a common format for logging message by the various users of the Logging Service will enhance the logging output in several ways. Foremost is that it will make the logging output more readable and providing a unified appearance to the log messages. While a general format is outlined here, it should be noted that there may be times when it is appropriate to stray from this format. In fact, the flexibility of the format is one of the features of the Logging Service.

Topics covered in this section include:

- Recommended format
- Suggested Logging Contexts
- Priority Levels

### Recommended format

In general, keeping the relative order of the entries consistent within a logging message will go a long way in providing readable output. For a default format, here is a suggested layout pattern string:

    %d %-5p [%s,%u] %c - %m%n

This provides:

- Date/time
- Log priority level, padded to 5 characters
- Session ID and user name inside square brackets
- The logging context of the log message
- The log message, separated from the logging context by the dash character

Some example output resulting from this layout pattern:

    2001-12-03 09:41:41,139 INFO  [a3d585dc0ef85540:51127a:fac546d315:-7fb2,pfsuser] com.sas.services.PrintLDAPInformation - Currently processing information for user "Igor"
    2001-12-03 09:41:41,790 DEBUG [a3d585dc0ef85540:51127a:fac546d315:-7fb2,pfsuser] com.sas.services.SampleApplication - ID principal Igor in domain ldap authenticated successfully

Several points to note regarding this logging format:

- Date and time are provided first, as these can be very important when reading log messages, particularly in log files that accumulate over days or weeks.
- The priority is also a high importance field. By placing it early in the log message it will be easy to scan the messages looking for a particular priority ( such as ERROR ).
- The session ID and user name may not be useful in all cases. Therefore, it should be considered optional. In multi-threaded applications, it might be helpful to replace this information with the thread context by employing the %t specifier.
- The logging contexts in the example are the fully-qualified class names of the classes where the logging messages originated. See the section on Suggested Logging Contexts below.
- The actual message appears last in the logging message. Since it is the most variable in length, its appearance at the end of the logging message is appropriate since it will not affect the vertical alignment of any of the other logging message fields.

### Suggested Logging Contexts

What should be used as the logging context for a log message? It is recommended that the fully-qualified class name of the class where the logging message originated be used. This has several advantages:

- It's immediately apparent where the message originated.
- If the class is in a dot-notated package, such as com.sas.services.logging, then the hierarchical nature of the logging context name space can be used to control logging by functional areas. See the section Hierarchical name space of logging contexts elsewhere in this document.
- If the class uses the inverted internet domain name notation, such as com.sas.whatever, then in cases where code from multiple vendors or domains is being used, it will be obvious from which vendor or domain the message originates.

There may be times when a different logging context naming scheme should be employed. This is likely to be in cases where the Logging Service is used for purposes other than general operational logging.

### Priority Levels

Which priority level should be used for a particular log message? There are 5 levels available. In increasing order of severity they are: DEBUG, INFO, WARN, ERROR, and FATAL. Here are some general guidelines on what type of messages would belong in each category:

- DEBUG - These are messages that you would not expect to see in a production run of an application. They would be turned on when someone is trying to diagnose a problem with the software or trying to understand the internal details of the software's operation.
- INFO - These messages would contain information pertinent to the general user of the application, but that do not signify any problems with the current state of the application.
- WARN - Warning messages would be appropriate when an unusual or unexpected state has been reached, but where this state does not necessarily indicate an error has occurred.
- ERROR - An error condition has occurred. The program may or may not be able to continue. This type of message normally originates in an Exception catch block in Java code.
- FATAL - A fatal error has occurred. The program is being terminated.

In general, assume that DEBUG messages will not be reported in a production run of an application, but that messages of the other four priority levels will be processed and reported.

## Example Java Code

The examples presented here are organized by whether they result in per-server logging, per-session logging, or both. ( See Remote Logging for a description of these terms. )

Here is an example of per-Server logging:

    LoggingServiceInterface loggingService = (LoggingServiceInterface)
        DiscoveryService.defaultInstance().findService(
             new ServiceTemplate(
                new Class[] {com.sas.services.logging.LoggingServiceInterface.class}));
    LoggerInterface logger = loggingService.getLogger(MyApp.class.getName());

    // log a debug message
    if( logger.isDebugEnabled())
    	logger.debug(message);

Here is an example of per-Session logging:

    // if for some reason your code does not generate a logger and
    // you are always presented with session context, then you can
    // use it to log your messages back to the logger created in this
    // session (may or may not be the same JVM)

    LoggerInterface logger = null;
    try {
    	logger = sessionContext.getLogger();
    }
    catch( RemoteException e ) {
    	// Handle exception here...
    }

    // log a debug message
    if( logger != null && logger.isDebugEnabled(loggingContext) )
    	logger.debug(message, loggingContext);

Here is an example of simultaneous per-Server/per-Session logging:

    // you can create a logger with a specified sessionContext...

    LoggingServiceInterface loggingService = (LoggingServiceInterface)
        DiscoveryService.defaultInstance().findService(
             new ServiceTemplate(
                new Class[] {com.sas.services.logging.LoggingServiceInterface.class}));

    LoggerInterface logger = loggingService.getLogger(MyApp.class.getName(), sessionContext);

    // log a debug message
    // this message will be logged at the local JVM as well as the JVM
    // that the session originated at if the JVMs are different...
    if( logger.isDebugEnabled())
    	logger.debug(message);

## Example Logging Configurations

Here is an example of a Logging Service configuration:

      <LoggingService implementation="log4j">
         <!-- LoggingContexts -->
         <RootLoggingContext priority="INFO">
              <OutputRef outputID="A1"/>
         </RootLoggingContext>
         <LoggingContext name="com.sas.services"
                         priority="WARN"
                         chained="false">
              <OutputRef outputID="A1"/>
              <OutputRef outputID="F1"/>
         </LoggingContext>
         <!-- Outputs -->
         <Output id="A1"
                 type="Console"
                 layoutPattern="%d [%t] %-5p %c - %m%n">
         </Output>
         <Output id="F1"
                 type="File"
                 layoutPattern="%d [%t] %-5p %c - %m%n">
            <param name="File"
                   value="c:\\Log\\application.log"/>
            <param name="Append"
                   value="false"/>
            <param name="ImmediateFlush"
                   value="true"/>
         </Output>
      </LoggingService>

Note that currently the `implementation="log4j"` attribute is not required on the `LoggingService` element, since log4j is the default implementation.

Here is another example of a Logging Service configuration file.

    <LoggingService isBasicLogging="true" basicLoggingPriority="DEBUG"/>

The above example specifies that the `isBasicLogging` attribute is `"true"`. In this case, all output is directed to the console, and a standard Pattern Layout string is employed. Currently this string is `"%-4r [%t] %-5p %c - %m%n"`, which would result in output similar to this:

    1102 [main] DEBUG MyApp - Here is a debug message.
    1122 [main] ERROR MyApp - Here is an error message.

End of examples.