Wednesday, November 7, 2007

How to setup Java Logging in OC4J

by Eduardo Rodrigues

Sometime ago I had a great idea for a web application logger that would basically log events as a feed (RSS or ATOM). After a lot of thinking of the best way to implement my idea, I decided to follow the Java Logging Framework. So, basically, all I had to do was to create my own FeedHandler extending java.util.logging.Handler and also create a new java.util.logging.Formatter extension for each specific standard feed format. I started implementing RSS20Formatter based on RSS 2.0 specification.

It took only 2 days for me to be completely satisfied with my own little Java Feed Logging library (which came to work really well, by the way) but then I had to make it work with my J2EE applications running in OC4J 10.1.3.x. And I wondered what would be the best way to do that.

I had read OC4J’s documentation on logging and saw that it is possible to define a log handler in OC4J’s logging configuration file j2ee-logging.xml declaring its class as a subclass of java.util.logging.Handler, but that’s all the information available on how to configure OC4J loggers using the Java Logging Framework because the focus seems to be on the Oracle Diagnostic Logging Framework instead.

I already use (and recommend) the ODL Framework in my J2EE applications running in OC4J mainly for its integration with web-based Oracle Enterprise Manager 10g Application Server Control Console which turns log viewing and analysis into a much more easy and comfortable experience. So, my first attempt was to add a new <log_handler> to <log_handlers> element in my j2ee-logging.xml file, basically copying my existing <log_handler> and changing its attributes and properties like that:

Original j2ee-logging.xml file

<?xml version = '1.0' encoding = 'iso-8859-1'?>
<logging_configuration>
   <log_handlers>
      <log_handler name="contaweb-handler"
                   class="oracle.core.ojdl.logging.ODLHandlerFactory"
                   formatter="oracle.core.ojdl.logging.ODLTextFormatter">
         <property name="path"
                   value="../application-deployments/log/ContaWeb"/>
         <property name="maxFileSize" value="10485760"/>
         <property name="maxLogSize" value="104857600"/>
         <property name="encoding" value="ISO-8859-1"/>
         <property name="useSourceClassAndMethod" value="true"/>
         <property name="supplementalAttributes"
                   value="J2EE_APP.name,J2EE_MODULE.name"/>
      </log_handler>
   </log_handlers>
   <loggers>
      <logger name="tim.contaweb" level="ALL" useParentHandlers="false">
         <handler name="contaweb-handler"/>
      </logger>
   </loggers>
</logging_configuration>


New j2ee-logging.xml file

<?xml version = '1.0' encoding = 'iso-8859-1'?>
<logging_configuration>
   <log_handlers>
      <log_handler name="contaweb-handler"
                   class="oracle.core.ojdl.logging.ODLHandlerFactory"
                   formatter="oracle.core.ojdl.logging.ODLTextFormatter">
         <property name="path"
                   value="../application-deployments/log/ContaWeb"/>
         <property name="maxFileSize" value="10485760"/>
         <property name="maxLogSize" value="104857600"/>
         <property name="encoding" value="ISO-8859-1"/>
         <property name="useSourceClassAndMethod" value="true"/>
         <property name="supplementalAttributes"
                   value="J2EE_APP.name,J2EE_MODULE.name"/>
      </log_handler>
      <log_handler name="contaweb-rss-handler"
                   class="oracle.br.logging.feed.FeedHandler"
                   formatter="oracle.br.logging.feed.RSS20Formatter">
         <property name="path" value="../applications/ContaWeb/ContaWeb/rss"/>
         <property name="level" value="INFO"/>
         <property name="title" value="ContaWeb Log Events"/>
         <property name="link" value="http://localhost:8888/em/"/>
         <property name="limit" value="100"/>
      </log_handler>

   </log_handlers>
   <loggers>
      <logger name="tim.contaweb" level="ALL" useParentHandlers="false">
         <handler name="contaweb-handler"/>
         <handler name="contaweb-rss-handler"/>
      </logger>
   </loggers>
</logging_configuration>


Note that I just added my new log handler to my existing logger named “tim.contaweb” which was already used by my application. In other words, every single log event generated by this logger will be directed to both handlers in a transparent way. The problem was it didn’t work at all :((((

Making the long story short, after googling a lot, I first found that the <property> elements and the “formatter” attribute in a <log_handler> are effective only if its class is oracle.core.ojdl.logging.ODLHandlerFactory. Then I also found that my answer was inside the ODL JAR file (ojdl.jar): the logging configuration DTD/Schema.

If you look inside ojdl.jar (which is generally located at $ORACLE_HOME/diagnostics/lib) you’ll find files oracle.core.ojdl.logging.logging-config.dtd and oracle.core.ojdl.logging.logging-config.xsd and, after examining them, you’ll notice the non-documented element <logging_properties> which is the first optional element inside the root element <logging_configuration>. In fact, this <logging_properties> only takes <property name=”” value””/> elements and has the exact same behavior as those properties declared in file $JAVA_HOME/jre/lib/logging.properties, and those are the ones needed by Java Logging Framework. So, my working j2ee-logging.xml file is:

<?xml version = '1.0' encoding = 'iso-8859-1'?>
<logging_configuration>
   <logging_properties>
      <property name="oracle.br.logging.feed.FeedHandler.formatter"
                value="oracle.br.logging.feed.RSS20Formatter"/>
      <property name="oracle.br.logging.feed.FeedHandler.path"
                value="../applications/ContaWeb/ContaWeb/rss"/>
      <property name="oracle.br.logging.feed.FeedHandler.level"
                value="INFO"/>
      <property name="oracle.br.logging.feed.FeedHandler.title"
                value="ContaWeb Log Events"/>
      <property name="oracle.br.logging.feed.FeedHandler.link"
                value="http://localhost:8888/em/"/>
      <property name="oracle.br.logging.feed.FeedHandler.limit"
                value="100"/>
   </logging_properties>

   <log_handlers>
      <log_handler name="contaweb-handler"
                   class="oracle.core.ojdl.logging.ODLHandlerFactory"
                   formatter="oracle.core.ojdl.logging.ODLTextFormatter">
         <property name="path"
                   value="../application-deployments/log/ContaWeb"/>
         <property name="maxFileSize" value="10485760"/>
         <property name="maxLogSize" value="104857600"/>
         <property name="encoding" value="ISO-8859-1"/>
         <property name="useSourceClassAndMethod" value="true"/>
         <property name="supplementalAttributes"
                   value="J2EE_APP.name,J2EE_MODULE.name"/>
      </log_handler>
      <log_handler name="contaweb-rss-handler"
                   class="oracle.br.logging.feed.FeedHandler"/>

   </log_handlers>
   <loggers>
      <logger name="tim.contaweb" level="ALL" useParentHandlers="false">
         <handler name="contaweb-handler"/>
         <handler name="contaweb-rss-handler"/>
      </logger>
   </loggers>
</logging_configuration>


It’s also very important to say that all log handlers declared in file j2ee-loggin.xml will be automatically instantiated during OC4J’s startup process. Because of this, all needed classes must be reachable from OC4J’s boot class loader. There were some options to achieve that but, in my case, the easiest was to deploy my new logging library to a JAR file and just put it in $ORACLE_HOME/j2ee/home/lib/ext directory.

That’s all for now. I hope it’s useful.

5 comments:

Pa1 said...

Hi,

can you share you custom handler n formatter code with me. I'm Pavan, working with Oracle, India. I'm exploring logging features provided by oracle diagnosis logging features. Out of curiosity, is there a way to log each and every project running on application server can log in separate log files? becz, by default oc4j all logs will goto some-path/logs/log.xml and if i want to search through these logs with custom parameters of that particular project, it's not possible with current log.xml file.

Small information, i know how to put a logger for a project and print those events in separate files. But thing here is, I'm interested in the logs that the engine presented on application server logs the all events occurred during execution of each n every project on application server.

Hope I'm clear what am saying? Can I get any help in this?

Eduardo Rodrigues said...

Hi Pavan,

Please send me an e-mail to eduardo.rodrigues@oracle.com from your oracle e-mail so I can send you the logging library.

As for your question, if I got your point correctly, I think the best way to achieve what you want is to add <odl> element to each of your project's orion-application.xml deployment descriptor. Something like this:

<log>
   <odl path="../log/petstore/" max-file-size="1000" max-directory-size="10000" />
</log>

For further details read http://download-uk.oracle.com/docs/cd/B32110_01/web.1013/b28950/logadmin.htm#i1027867

Hope it helps.

Danail said...

Hi Eduardo,

I want to ask a little bit offtopic question.

What is the easiest way to insert custom information into the xml logs of oc4j? Like, new tag or change some of the existing tags?

10x in advance. And, btw, great article! :)

Eduardo Rodrigues said...

Well Danail, I don't know if there's an easy way to do what you're suggesting. Personally, I would try to create my own implementations of oracle.core.ojdl.logging.HandlerFactory and also of oracle.core.ojdl.logging.ODLHandler.

The problem with this is that OJDL is not an open framework. We don't have access to its source code not even to its documentation. I know it doesn't make things impossible but certainly makes them tougher.

Besides, there's also another issue involved. Even if you manage to enhance the default XML log with your own extended OJDL, there's no guarantee that those enhancements will be recognized and displayed on OracleAS Control Console.

Cheers,
Eduardo.

Deepak said...

Hi,
Your article is quite useful. I can see my log messages in log.xml. What i stried to do is logging ODL messaages in separate log file for my application.

the log.xml is created an logged but not recognized and displayed on OracleAS Control Console

Any clues or additional configuration required.

Tx,
Deepak