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.
Background
Prior to 2.11.6 logging from the BFO PDF library would simply write warnings (and
debug, if enabled) to
System.err
. 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.
The new Logging API
Fixing this required some flexibility. Some of our API's still run on Java 1.3, so
we can't rely on
java.util.logging,
and some customers prefer to use Log4j instead.
Apache Commons logging is broken by design, so we've
written our own wrapper which will log to Log4j
if it's available and configured, falling back
to java.util.logging
if it's availabe or System.err
if it's not.
Logging with Log4J
If Log4J is available and a log4j.properties
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 log4j.properties
that would write output to the console.
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
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.
log4j.logger.org.faceless.pdf2.warning.PD6 = OFF log4j.logger.org.faceless.pdf2.warning.RD4 = FATAL
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.
If you prefer to use the XML method for configuring Log4J, that will work too. The
configuration file is
called log4j.xml
rather than log4j.properties
- the equivalent of the above example
is this:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> <appender name="stdout" class="org.apache.log4j.ConsoleAppender"> <param name="threshold" value="debug" /> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %p %m %x%n" /> </layout> </appender> <category name="org.faceless.pdf2.warning.PD6"> <priority value="off"/> </category> <category name="org.faceless.pdf2.warning.RD4"> <priority value="fatal"/> </category> <root> <priority value="debug" /> <appender-ref ref="stdout" /> </root> </log4j:configuration>
Logging with java.util.logging
The java.util.logging
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:
- Classloader wide configuration, which makes logging multiple threads impractical without extending.
- Really ugly default formatting of messages
- An inability to write to multiple files or change this formatting easily
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 JULI logging framework which will build on the default, however configuration can be cryptic.
You can configure JULI logging in a couple of ways, but while getting started the
simplest approach is to
place a file called logging.properties
in the WEB-INF/classes
folder of your
web application. Here's a simple example:
handlers = org.apache.juli.FileHandler org.apache.juli.FileHandler.directory = ${catalina.base}/logs org.apache.juli.FileHandler.prefix = mywebapp.
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 logging.properties
.
We've included a Formatter
so you can also format the output in the same way as the Log4J
PatternLayout
(you can download it here, it's public domain).
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
This will turn off F4 warnings, make RD4 warnings fatal, and cause the remaining warning message to be formatted to fit on one line.
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:
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
Although not obvious, these messages are logged using java.util.logging
as well: by default
if no custom configuration is found, we install our own PatternFormatter
to format messages
onto one line.
If you want more control over the logging, you can set up your own logging.properties
. Here's
an example that would log all Token
debug entries to a file:
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
Save that file and make sure it's passed into Java
java -Djava.util.logging.config.file=logging.properties ...
Logging without a Logger
For customers still on Java 1.3, messages are sent toSystem.err
, and you can turn messages
on or off using System properties:
java -Dorg.faceless.pdf2.warning.RD4=off ...
The warning codes
Full details of the org.faceless.pdf
system properties and warning messages can be found in
Appendices A & B of the PDF Library user guide.