<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml-stylesheet type="text/xsl" href="blog.xsl"?>
<article>
 <title>Logging with BFO</title>
 <subtitle/>
 <excerpt>The release of 2.11.6 of the BFO PDF library sees the introduction of a consolidated logging API that can be integrated into customer's existing logging systems. Read on to find out how to configure BFO products to log with Log4J or java.util.logging.</excerpt>
 <time>2009-07-07T15:38:31</time>
 <author>jim</author>
 <category>pdf</category>
 <tags>logging log4j</tags>
 <body><p>
The release of 2.11.6 of the BFO PDF library sees the introduction of a consolidated logging API that can 
be integrated into customer's existing logging systems.
</p>

<h3>Background</h3>
<p>
Prior to 2.11.6 logging from the BFO PDF library would simply write warnings (and debug, if enabled) to
 <code>System.err</code>. When things were running smoothly this would generate little or no output, but
  dodgy PDFs could throw a large number of messages, and although these could always be turned off, there
   was no way to manage the logging in more detail.
</p>

<h3>The new Logging API</h3>
<p>
Fixing this required some flexibility. Some of our API's still run on Java 1.3, so we can't rely on 
<a href="http://docs.oracle.com/javase/8/docs/api/java/util/logging/package-summary.html" rel="nofollow">java.util.logging</a>,
 and some customers prefer to use <a href="http://logging.apache.org/log4j/1.2/index.html" rel="nofollow">Log4j</a> instead. 
 Apache Commons logging is  <a href="http://www.qos.ch/logging/thinkAgain.jsp" rel="nofollow">broken by design</a>, so we've 
 written our own wrapper which will log to <code>Log4j</code> if it's available and configured, falling back 
 to <code>java.util.logging</code> if it's availabe or <code>System.err</code> if it's not.
</p>

<h3>Logging with Log4J</h3>
<p>
If Log4J is available and a <code>log4j.properties</code> file configured, BFO libraries will use it. If you've
 installed it we'll assume you know how to configure it, so we won't cover that here in too much detail - as a
  quick example, here's an example <code>log4j.properties</code> that would write output to the console.
</p>
<pre class="brush:plain">log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=\
    %d{yyyy-MM-dd HH:mm:ss} %p %m %x%n
log4j.rootLogger=debug, stdout
</pre>
<p>
This would log all warnings, but in the event you want individual warning messages turned off or changed to a
 different level you can do that too.
</p>
<pre class="brush:plain">log4j.logger.org.faceless.pdf2.warning.PD6 = OFF
log4j.logger.org.faceless.pdf2.warning.RD4 = FATAL</pre>
<p>
This would disable the "PD6" warnings and make RD4 warnings fatal. As you can see, all warnings from the PDF 
library wil be in the "org.faceless.pdf2" package, which makes them easy to redirect to a separate file if 
necessary.
</p>
<p>
If you prefer to use the XML method for configuring Log4J, that will work too. The configuration file is 
called <code>log4j.xml</code> rather than <code>log4j.properties</code> - the equivalent of the above example
 is this:</p>
<pre class="brush:xml">
&lt;?xml version="1.0" encoding="UTF-8" ?&gt;
&lt;!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"&gt;
&lt;log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"&gt;

 &lt;appender name="stdout" class="org.apache.log4j.ConsoleAppender"&gt;
  &lt;param name="threshold" value="debug" /&gt;
  &lt;layout class="org.apache.log4j.PatternLayout"&gt;
   &lt;param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %p %m %x%n" /&gt;
  &lt;/layout&gt;
 &lt;/appender&gt;

 &lt;category name="org.faceless.pdf2.warning.PD6"&gt;
  &lt;priority value="off"/&gt;
 &lt;/category&gt;

 &lt;category name="org.faceless.pdf2.warning.RD4"&gt;
  &lt;priority value="fatal"/&gt;
 &lt;/category&gt;

 &lt;root&gt;
  &lt;priority value="debug" /&gt;
  &lt;appender-ref ref="stdout" /&gt;
 &lt;/root&gt;
&lt;/log4j:configuration&gt;
</pre>

<h3>Logging with java.util.logging</h3>
<p>
The <code>java.util.logging</code> API was added in Java 1.4, although it has a number of problems by design
 which make this package next to useless out of the box. Some highlights are:</p>
<ul>
<li>Classloader wide configuration, which makes logging multiple threads impractical without extending.</li>
<li>Really ugly default formatting of messages</li>
<li>An inability to write to multiple files or change this formatting easily</li>
</ul>
<p>
However, as it is supplied with Java 1.4 we need to work around these points. Customers deploying in a 
servlet environment will typically have two of these points fixed by the servlet engine. Apache Tomcat, 
for example, provides their own <a href="http://tomcat.apache.org/tomcat-6.0-doc/logging.html" rel="nofollow">JULI</a> 
logging framework which will build on the default, however configuration can be cryptic.
</p><p>
You can configure JULI logging in a couple of ways, but while getting started the simplest approach is to
 place a file called <code>logging.properties</code> in the <code>WEB-INF/classes</code> folder of your 
 web application. Here's a simple example:
</p>
<pre class="brush:plain">handlers = org.apache.juli.FileHandler
org.apache.juli.FileHandler.directory = ${catalina.base}/logs
org.apache.juli.FileHandler.prefix = mywebapp.
</pre>
<p>
As with Log4J, all messages are logged under the "org.faceless.pdf2" logger and you can turn logging for
 individual message on or off very easily by setting the appropriate levels in <code>logging.properties</code>.
  We've included a <a href="http://docs.oracle.com/javase/8/docs/api/java/util/logging/Formatter.html" rel="nofollow">Formatter</a>
   so you can also format the output in the same way as the Log4J 
   <a href="http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html" rel="nofollow">PatternLayout</a>
    (you can download it <a viewtext="true" href="patternform.java">here</a>, it's public domain).
</p>
<pre class="brush:plain">org.faceless.pdf2.warning.F4 = OFF
org.faceless.pdf2.warning.RD4 = SEVERE
org.apache.juli.FileHandler.formatter = \
    org.faceless.util.log.PatternFormatter
org.faceless.util.log.PatternFormatter.format = \
    %d{yyyy-MM-dd HH:mm:ss} %p %m %x%n
</pre>
<p>
This will turn off F4 warnings, make RD4 warnings fatal, and cause the remaining warning message to be 
formatted to fit on one line.
</p>
<p>
That's fine if you're logging from within Tomcat, but what about if you're running a regular application
 from the command line? Here's an example showing how you might see a warning message from this:
</p>
<pre class="brush:plain; highlight:1">java org.faceless.pdf2.viewer2.PDFViewer corrupt.pdf
WARNING RD6: Stream 4/0 is 8 bytes too long - PDF may be corrupt
WARNING RD6: Stream 9/0 is 8 bytes too long - PDF may be corrupt
</pre>
<p>
Although not obvious, these messages are logged using <code>java.util.logging</code> as well: by default 
if no custom configuration is found, we install our own <code>PatternFormatter</code> to format messages 
onto one line.
</p><p>
If you want more control over the logging, you can set up your own <code>logging.properties</code>. Here's 
an example that would log all <code>Token</code> debug entries to a file:</p>
<pre class="brush:plain">java.util.logging.FileHandler.formatter = org.faceless.util.log.PatternFormatter
java.util.logging.FileHandler.pattern = bfodebug.log
org.faceless.util.log.PatternFormatter.format = %m%n

org.faceless.pdf2.level = ALL
org.faceless.pdf2.debug.Token = FINE
org.faceless.pdf2.handlers = java.util.logging.ConsoleHandler, java.util.logging.FileHandler
org.faceless.pdf2.useParentHandlers = false
</pre>
<p>Save that file and make sure it's passed into Java</p>
<pre class="brush:plain">java -Djava.util.logging.config.file=logging.properties ...</pre>
<p>
<h3>Logging without a Logger</h3>
For customers still on Java 1.3, messages are sent to <code>System.err</code>, and you can turn messages 
on or off using System properties:
</p><pre class="brush:plain">
java -Dorg.faceless.pdf2.warning.RD4=off ...</pre>

<h3>The warning codes</h3>
<p>
Full details of the <code>org.faceless.pdf</code> system properties and warning messages can be found in 
Appendices A &amp; B of the PDF Library <a href="/products/pdf/docs/userguide.pdf">user guide</a>.
</p>
</body>
<include xmlns="http://www.w3.org/2001/XInclude" href="comments.xml"/>
</article>