ADFLogger: Using a Custom Formatter Class to Print Log Messages

Based on some posts on the OTN JDeveloper forum this article shows how to implement a custom fdormatter class to use with ADFLogging and how to integrate it with the embedded WLS instance in JDeveloper. Sample workspace for the custom logger is available at the end of the article.
For this post I assume you now your way around java.util.logging. I show how to implement a custom formatter class to format the log messages with more information and a different style. The picture below shows the general java logging model:

General Logging Model

General Logging Model


As the model shows the formatter is used by the log handler which gets a log record and processes it by piping the record through a filter and then through a formatter to finaly pass it to the attached output target. In most cases the output target is a file, a db table, a system log or a stream. For the console logger its most often a stream (e.g. stdout and/or stderr).

A typlical JDev log message from the ConsoleFormatter looks like this:

<AdfcAppInitializer> <loadDebugFacades> ADFc: Initializing ADF Debugger

I’ll change this to:

FINE: 22.09.2011 13:18:17 - de.hahn.blog.popupregion.backingbeans.pageflow.SelectionBean$beaVersion0_39.selectionListenerEmp(SelectionBean.java:92) - 15 - de.hahn.blog.popupregion.backingbeans.pageflow.SelectionBean
  Selected: oracle.jbo.Key[105 ]

The general layout of the log message is

data in [] is customizable, data in {} is printed only if available
level: date time [- threadId] [- class] [- method] [- message] {- throwable.message}
These parameters configure which information to print
       t = thread
       n = logger name
       l = line number; if 'l' is selected 'c' and 'm' are not used
       c = class name
       m = method name

As you see there is more information printed, e.g. source and line number and log level. As this creates long log lines I made this customizable. How the parameters are passed to the logger is shown later.

First of all I implement a class DebugFormatter which extends java.util.logging.SimpleFromatter as this class is an implementation of the abstract class java.util.logging.Formatter the base of all formatter attached to a log handler. The key part of this class is the method

public String format(LogRecord record) {...}

which gets a log record and returns a string of the information which send to the handler for further action. The format method checks the parameters given and returns a string according to them.

To wire things up I modify the logging.xml file which can be reached from the ‘Application Server Navigator’. Right click on the integrated WLS and select ‘Configure Oracle Diagnostic Logging for …’. This will open a nice graphical overview

Logging.xml

Logging.xml


Now I add a new logger by clicking the green ‘+’ sign and specifying the log level and the name of the logger, which is actually the part of the class path the logger reacts on.
Add  Logger

Add Logger


this creates a new line in the logging.xml file looking like
Added Line

Added Line


Next I set up a new log handler in the logging.xml file which uses my DebugLogger class as formatter. Together with the log handler I specify the parameters which configure the output format of the string. The DebugLogger is not used directly, but instead a wrapper class WLSConsoleFormatter used which specifies default parameter set to the DebugFormatter. This way you can omit the parameters in the setup. Below is the resulting log handler entry in the logging.xml file:

        <log_handler name='blog-console-handler'
                     class='de.hahn.blog.consoleformatter.logger.BlogConsoleHandler' level='ALL'
                     encoding='UTF-8'>
            <property name='formatStyle' value='tnlcm'/>
            <property name='formatter'
                      value='de.hahn.blog.consoleformatter.logger.WLSConsoleFormatter'/>
        </log_handler>

To add this you need to change to the source view for the logging.xml file.
Finally I change the added logger to use the new handler

        <logger name='de' level='TRACE:1' useParentHandlers='false'>
            <handler name='blog-console-handler'/>
            <handler name="odl-handler"/>
        </logger>

I have to set the useParentHandlers to false to prevent that the messages get printed multiple times. To be able to analyze the messages with the log analyzer I add the ODL handler too. Now all log messages are printed to the console and to the ODL logger.

Now that the logger are setup in the logging.xml all I need to do is to make the classes available to the WLS instance. For this I build a jar from the project and put the resulting BlogConsoleFormatter.jar in a folder where WLS picks it up while starting. There a a couple of folder, but I choose <ide.system.dir>/DefaultDomain/lib folder. ide.system.dir is also known as the systemfolder of your JDeveloper installation. If you don't know where to find it check this blog. You can either copy the jar into the folder or setup the deployment profile to generate the jar in this folder.

Sample Oiutout

Sample Oiutout

The picture above show a small code sample with the generated output from DebugFormatter. As you see the log lines are marked as links. If you click on such a line you see that you are transfered to the code location of the message.

You can download the source code for the BlogLogConsoleFormatter.zip and a BlogPopupRegion.zip using the ADFLogger to generate messages in different log levels. After downloading the files you need to remove the ‘.doc’ suffix and rename them to ‘.zip’ as the files are normal zip files.
The sample workspaces are developed with JDeveloper 11.1.2.0.0, BlogPopupRegion uses the HR schema as DB connection.

ADF News Session – ADF Logging

Am 01.10.2010 fand die ADF Newssession zum Thema “Logging in ADF Anwendungen” statt. Wie in der Session besprochen werde ich in diesem Eintrag die verwendeten Workspaces bereitstellen.

Der Workspace SCMDebugLogging beinhaltet den in der Session verwendeten ConsoleHandler, die angesprochene Wrapperklasse WLSConsoleHanndler sowie den DebugFormatter.
Die Klassen sind in Code dokumentiert.

Damit JDeveloper die Klassen verwenden kann, müssen sie als JAR verpackt werden und entweder in den CLASSPATH aufgenommen werden, oder in ein Verzeichnis kopiert werden, welches der im JDeveloper integrierte WLS beim Starten automatisch durchsucht.

Ich verwende die zweite Methode und dazu das Verzeichnis
‘WLSHome’/system11.1.1.3.37.56.60/DefaultDomain/lib
‘WLSHome’ ist dabei durch das auf ihrem System entsprechende Verzeichnis zu ändern.

Dieses Verzeichnis ist im Deployment-Descriptor des Workspace angegeben und muss auf Ihre Installation angepasst werden, oder Sie kopieren das JAR von Hand.

Der Workspace PopupRegion enthält die Beispielanwendung, die auf dem HR Schema von Oracle beruht.

Hier noch die Zusätze zur logging.xml innerhalb des JDev:

 <log_handler name='smc-console-handler' class='de.smc.common.logger.SMCConsoleHandler' level='ALL' encoding='UTF-8'>
  <!-- t = thread
       n = logger name
       l = line number; falls angegeben werden c und m nicht berücksichtigt
       c = class name
       m = method name
  -->
   <property name='formatStyle' value='tnlcm'/>
   <property name="formatter"
             value="de.smc.common.logger.WLSConsoleFormatter"/>
  </log_handler> 
  
  <logger name='de' level='TRACE:1' useParentHandlers='false'>
   <handler name='smc-console-handler'/>
   <handler name="odl-handler"/>
  </logger>  

Viel Spaß bei Probieren…

Folien der Session als PDF:
Logging in Web-Anwendungen

SMCDebugLogger (bitte mit ‘Link speichern unter…’ laden und nach ‘.zip’ umbenennen!):
SMCDebugLogging_ThuSep30170446CEST2010.zip

PopupRegion (bitte mit ‘Link speichern unter…’ laden und nach ‘.zip’ umbenennen!):
PopupRegion_ThuSep30170502CEST2010.zip

Logging unter JDev 11g

JDev 11gR1 ermöglicht es einen neuen Logger für die Logausgaben des Framework anzugeben. Dieser Formatiert die Ausgaben geringfügig anders als der bisher bekannte Consolenlogger. Der große Vorteil liegt allerdings adrin, das der ADF Logger über den WLS konfiguriert werden kann.

Um die Frameworkausgaben auf den neuen ADFLogger umzuleiten, werden in der Run-Konfiguration einfach die folgenden Variablen definiert:

-Djbo.debugoutput=adflogger -Djbo.adflogger.level=FINE

Weiter kann wir früher auch console, file oder silent für jbo.debugoutput angegeben werden.

Die Debugausgaben können im WLS einfach über die Konsole eingestellt werden. Es ist allerdings nicht ganz einfach herauszufinden, welche Einstellungen man genau ändern muss, um das gewünschte Ergebnis zu erhalten.

In einem folgenden Blog werde ich darüber berichten. Bis dahin hier nur der Weg, wie man zu den Einstellungen gelangt:

In der Konsole DomainStructure->Domain->Environment->Servers->Server->Debug bringt einen an die richtige stelle.

Dann viel Spass beim Probieren….

Logausgaben im Logwindow aktivieren

Unter JD11TP3 werden nach dem Start des Embedded-Servers keine Logausgaben mehr in das Log-Window geschreiben. Die Ursache dafür, ist in der Konfigurationsdatei des Embedded-Servers für das Logging zu suchen. Die Datei dei diese Einstellungen beinhaltet heisst j2ee-logging.xml und ist für den Embedded-OC4J Container unter dem Verzeichnis:
UserverzsichisAnwendungsdatenJDevelopersystem11.1.1.0.22.47.96o.j2eeembedded-oc4jconfig
zu finden.
Das Original sieht nach der Installation so aus (in Teilen)

<logging_configuration>
   <log_handlers>
      <log_handler name="console-handler" class="oracle.oc4j.util.ConsoleHandler" level="WARNING"/>
      <log_handler name="oc4j-handler" class="oracle.core.ojdl.logging.ODLHandlerFactory">
...

Leider scheint es so, als ob die Klasse oracle.oc4j.util.ConsoleHandler nicht gefunden wird vom Embedded-OC4J Container. Daher sollte man die Klasse ändern in java.util.logging.ConsoleHandler. Passt man auch noch das Level an (z.B. auf FINE) erhält man wieder alle Meldungen.
Das Resultat sieht dann (in Teilen) so aus:

<logging_configuration>
   <log_handlers>
      <log_handler name="console-handler" class="java.util.logging.ConsoleHandler" level="FINE"/>
      <log_handler name="oc4j-handler" class="oracle.core.ojdl.logging.ODLHandlerFactory">
...

Logausgaben in das Application-Log

Um Logausgaben in das Applicationlog zu schreiben, kann der Servletcontext verwendet werden

FacesContext fc = FacesContext.getCurrentInstance();
ServletContext sc = (ServletContext) fc.getExternalContext().getContext();
sc.log("My log message for Application.log");

Es sthet auch eine Log-Methode zur Verfügung, die auch noch eine Exception logged.