10Duke SDK writes information to logs by using Logger singleton class that receives Log entries and publishes them to subscribers. Log entries carry information of events to be logged, including:
event type tells whether the log entry should be treated as error, warning or information
Debug level is used to indicate how important it is that event described by the log entry is brought to attention of people managing the application. Although errors can often be considered more critical in this sense, there are cases where "normal" application events are as interesting as errors. For instance, after error that suggests that an application feature has stopped working, another log entry with information telling that the feature has been recovered is of very high information value. In this case both of these log entries should have high importance, e.g. DebugLevel.Critical.
log message is textual description of the event
Exception related to the event can also be passed as additional information for the event
Logger class decouples code that creates log entries from log writers. Logs are actually written by LogEntrySubscribers that subscribe events from Logger.
When application lifecycle is started, a default LogEntrySubscriber is created and added as a subscriber for the Logger singleton instance. Applications can also freely implement and add LogEntrySubscribers. This way applications can write log entries to custom log files or log interfaces, filter and handle certain log entries by specific handlers, write several separate logs etc.
Examples of calls reporting log entries to Logger are given below:
try {
//
...
} catch (Exception exception) {
//
// Critical error with textual description and exception
Logger.instance().addEntry(new LogEntry(EventType.Error, DebugLevel.Critical,
"My application has failed catastrophically", exception));
}
//
// Detailed information of application execution
Logger.instance().addEntry(new LogEntry(EventType.Info, DebugLevel.VeryVerbose,
"My application has completed an operation in 123 milliseconds"));Adding a subscriber to Logger can be done like this:
Logger.instance().subscribe(myLogEntrySubscriber);
After LogEntrySubscriber has been added to Logger, LogEntrySubscriber.logEntryReceived is called on it for each LogEntry received by Logger.
Default LogEntrySubscriber added to Logger when application lifecycle is started can be configured by JVM system property 10duke.logger.logentrysubscriber, or by web application environment entry with the same name for .war web applications. Value for this configuration parameter must be fully qualified class name of a class that implements LogEntrySubscriber interface. Example is given below:
10duke.logger.logentrysubscriber=com.tenduke.diagnostics.JavaLoggerLogWriter
If 10duke.logger.logentrysubscriber is not configured, ConsoleLogWriter is used as default LogEntrySubscriber.
Templates used by ConsoleLogWriter for formatting log messages can be configured in application configuration. Templates can be defined for each log entry event type. Configuration parameters for the templates are:
logging.consolelogwriter.template.error
logging.consolelogwriter.template.warning
logging.consolelogwriter.template.info
Value for each of these configuration parameters is a formatting pattern that will be passed to java.text.MessageFormat.format(...) for formatting. Format elements that can be used in the formatting pattern are:
{0}: Timestamp of the log entry (printed in ISO 8601 format)
{1}: Event type of the log entry as string ("Error" / "Warning" / "Info")
{2}: Log entry debug level (number 1 - 5)
{3}: Log entry message
{4}: Message of exception attached to the log entry
{5}: Stack trace of exception attached to the log entry
The formatting elements are also documented by LogEntry.print(...).
The following example configuration parameter defines formatting pattern for log entries with EventType.Error, using respective configuration parameter logging.consolelogwriter.template.error:
<entry key="logging.consolelogwriter.template.error">[{0}] {1} ({2}) {3}
{4} {5}</entry>In the example configuration parameter above, 
 is an xml escape sequence for line feed (\n). Example log entry printed using this formatting pattern is below:
[2011-08-10T14:24:53.113Z] Error (1) Null pointer exception caused for demonstration purposes
null java.lang.NullPointerException
at com.example.LogFormatExample.testLogFormat(LogFormatExample.java:24)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at junit.framework.TestCase.runTest(TestCase.java:164)
at junit.framework.TestCase.runBare(TestCase.java:130)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:120)
at junit.framework.TestSuite.runTest(TestSuite.java:230)
at junit.framework.TestSuite.run(TestSuite.java:225)
at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.run(JUnitTestRunner.java:518)
at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.launch(JUnitTestRunner.java:1052)
at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.main(JUnitTestRunner.java:906)ConsoleLogWriter also supports filtering log entries by LogEntry.DebugLevel. Configuration parameter logging.consolelogwriter.debug.level can be set to an integer value for omitting log entries where LogEntry.getDebugLevel() is greater than the defined value. Debug levels and their respective integer values are:
For example, the following configuration would allow ConsoleLogWriter to write only log entries with DebugLevel.Critical:
<entry key="logging.consolelogwriter.debug.level">1</entry>