Logging and Auditing
logging
Log
Logging is an important means of gaining insight into your application's runtime
behavior. OpenJPA provides a flexible logging system that integrates with many
existing runtime systems, such as application servers and servlet runners.
There are five built-in logging plugins: a
default logging framework that
covers most needs, a Log4J
delegate, a SLF4J
delegate, an Apache Commons Logging
delegate, and a no-op
implementation for disabling logging.
Logging can have a negative impact on performance. Disable verbose logging (such
as logging of SQL statements) before running any performance tests. It is
advisable to limit or disable logging for a production system. You can disable
logging altogether by setting the openjpa.Log property to
none.
Logging Channels
logging
channels
Logging is done over a number of logging channels, each of
which has a logging level which controls the verbosity of
log messages recorded for the channel. OpenJPA uses the following logging
channels:
openjpa.Tool: Messages issued by the OpenJPA command line
and Ant tools. Most messages are basic statements detailing which classes or
files the tools are running on. Detailed output is only available via the
logging category the tool belongs to, such as openjpa.Enhance
for the enhancer (see ) or
openjpa.MetaData for the mapping tool (see
). This logging category
is provided so that you can get a general idea of what a tool is doing without
having to manipulate logging settings that might also affect runtime behavior.
enhancement
log messages
openjpa.Enhance: Messages pertaining to enhancement and
runtime class generation.
metadata
log messages
openjpa.MetaData: Details about the generation of metadata
and object-relational mappings.
openjpa.Runtime: General OpenJPA runtime messages.
Query
log messages
openjpa.Query: Messages about queries. Query strings and any
parameter values, if applicable, will be logged to the TRACE
level at execution time. Information about possible performance concerns will be
logged to the INFO level.
caching
log messages
openjpa.DataCache: Messages from the L2 data cache plugins.
JDBC
log messages
openjpa.jdbc.JDBC: JDBC connection information. General JDBC
information will be logged to the TRACE level. Information
about possible performance concerns will be logged to the INFO
level.
SQL
log messages
openjpa.jdbc.SQL: This is the most common logging channel to
use. Detailed information about the execution of SQL statements will be sent to
the TRACE level. It is useful to enable this channel if you
are curious about the exact SQL that OpenJPA issues to the datastore.
The SQL issued to the database may contain sensitive information. By default the
parameter values used in the prepared statements generated by OpenJPA will not
be printed in the SQL log - instead you will see a ? for each value. The actual
values may be printed by adding PrintParameters=True to the
openjpa.ConnectionFactoryProperties property. Also
see Using the OpenJPA
DataSource
When using the built-in OpenJPA logging facilities, you can enable SQL logging
by adding SQL=TRACE to your openjpa.Log
property.
OpenJPA can optionally reformat the logged SQL to make it easier to read. To
enable pretty-printing, add PrettyPrint=true to the
openjpa.ConnectionFactoryProperties property. You can control
how many columns wide the pretty-printed SQL will be with the
PrettyPrintLineLength property. The default line length is 60 columns.
While pretty printing makes things easier to read, it can make output harder to
process with tools like grep.
Pretty-printing properties configuration might look like so:
<property name="openjpa.Log" value="SQL=TRACE"/>
<property name="openjpa.ConnectionFactoryProperties"
value="PrettyPrint=true, PrettyPrintLineLength=72"/>
SQLDiag
log messages
openjpa.jdbc.SQLDiag: This logging channel provides additional
information about entity actitvies such as create, find, update or delete, and eager
loading of relation or field properties. If you enable this channel, it is recommended
that openjpa.jdbc.SQL channel is also enabled.
The additional trace can help you relate the entity activities to the execution of
SQL statements that OpenJPA issued to the datastore.
When using the built-in OpenJPA logging facilities, you can enable SQLDiag logging
by adding SQLDiag=TRACE to your openjpa.Log
property.
schema
log messages
openjpa.jdbc.Schema: Details about operations on the
database schema.
OpenJPA Logging
logging
default
By default, OpenJPA uses a basic logging framework with the following output
format:
millisdiagnostic contextlevel [thread name] channel - message
For example, when loading an application that uses OpenJPA, a message like the
following will be sent to the openjpa.Runtime channel:
2107 INFO [main] openjpa.Runtime - Starting OpenJPA 2.2.0
The default logging system accepts the following parameters:
File: The name of the file to log to, or stdout
or stderr to send messages to standard out and
standard error, respectively. By default, OpenJPA sends log messages to standard
error.
DefaultLevel: The default logging level of unconfigured
channels. Recognized values are TRACE, INFO, WARN, ERROR
and FATAL. Defaults to INFO.
DiagnosticContext: A string that will be prepended to all
log messages. If this is not supplied and an openjpa.Id
property value is available, that value will be used.
<channel>: Using the last token of the
logging channel name, you can
configure the log level to use for that channel. See the examples below.
Standard OpenJPA Log Configuration
<property name="openjpa.Log" value="DefaultLevel=WARN, Runtime=INFO, Tool=INFO"/>
Standard OpenJPA Log Configuration + All SQL Statements
<property name="openjpa.Log" value="DefaultLevel=WARN, Runtime=INFO, Tool=INFO, SQL=TRACE"/>
Logging to a File
<property name="openjpa.Log" value="File=/tmp/org.apache.openjpa.log, DefaultLevel=WARN, Runtime=INFO, Tool=INFO"/>
Disabling Logging
logging
disabling
Disabling logging can be useful to analyze performance without any I/O overhead
or to reduce verbosity at the console. To do this, set the openjpa.Log
property to none.
Disabling logging permanently, however, will cause all warnings to be consumed.
We recommend using one of the more sophisticated mechanisms described in this
chapter.
Log4J
logging
Log4j
When openjpa.Log is set to log4j, OpenJPA
will delegate to Log4J for logging. In a standalone application, Log4J logging
levels are controlled by a resource named log4j.properties
, which should be available as a top-level resource (either at the top level of
a jar file, or in the root of one of the CLASSPATH
directories). When deploying to a web or EJB application server, Log4J
configuration is often performed in a log4j.xml file
instead of a properties file. For further details on configuring Log4J, please
see the Log4J
Manual. We present an example log4j.properties file
below.
Standard Log4J Logging
log4j.rootCategory=WARN, console
log4j.category.openjpa.Tool=INFO
log4j.category.openjpa.Runtime=INFO
log4j.category.openjpa.Remote=WARN
log4j.category.openjpa.DataCache=WARN
log4j.category.openjpa.MetaData=WARN
log4j.category.openjpa.Enhance=WARN
log4j.category.openjpa.Query=WARN
log4j.category.openjpa.jdbc.SQL=WARN
log4j.category.openjpa.jdbc.SQLDiag=WARN
log4j.category.openjpa.jdbc.JDBC=WARN
log4j.category.openjpa.jdbc.Schema=WARN
log4j.appender.console=org.apache.log4j.ConsoleAppender
Apache Commons Logging
logging
Apache Commons
Set the openjpa.Log property to commons to
use the Apache
Commons Logging thin library for issuing log messages. The
Commons Logging library act as a wrapper around a number of popular logging
APIs, including the
Jakarta Log4J
project, and the native
java.util.logging package in JDK.
When using the Commons Logging framework in conjunction with Log4J,
configuration will be the same as was discussed in the Log4J section above.
JDK java.util.logging
logging
JDK
When using JDK logging in conjunction with OpenJPA's Commons Logging
support, logging will proceed through Java's built-in logging provided by the
java.util.logging package. For details on configuring the built-in
logging system, please see the
Java Logging Overview.
By default, JDK's logging package looks in the
JAVA_HOME/lib/logging.properties file for logging configuration. This
can be overridden with the java.util.logging.config.file
system property. For example:
java -Djava.util.logging.config.file=mylogging.properties com.company.MyClass
JDK Log Properties
# specify the handlers to create in the root logger
# (all loggers are children of the root logger)
# the following creates two handlers
handlers=java.util.logging.ConsoleHandler, java.util.logging.FileHandler
# set the default logging level for the root logger
.level=ALL
# set the default logging level for new ConsoleHandler instances
java.util.logging.ConsoleHandler.level=INFO
# set the default logging level for new FileHandler instances
java.util.logging.FileHandler.level=ALL
# set the default formatter for new ConsoleHandler instances
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
# set the default logging level for all OpenJPA logs
openjpa.Tool.level=INFO
openjpa.Runtime.level=INFO
openjpa.Remote.level=INFO
openjpa.DataCache.level=INFO
openjpa.MetaData.level=INFO
openjpa.Enhance.level=INFO
openjpa.Query.level=INFO
openjpa.jdbc.SQL.level=INFO
openjpa.jdbc.SQLDiag.level=INFO
openjpa.jdbc.JDBC.level=INFO
openjpa.jdbc.Schema.level=INFO
SLF4J
logging
SLF4j
When openjpa.Log is set to slf4j, OpenJPA
will delegate to SLF4J API for logging, which provides several adapters or
a simple logging mechanism. For further details on logging adapters and
configuring SLF4J, please see the
SLF4J website.
Note, as SLF4J does not provide a FATAL log level the
SLF4JLogFactory will map it to the ERROR
log level.
Custom Log
logging
custom
If none of available logging systems meet your needs, you can configure the
logging system with a custom logger. You might use custom logging to integrate
with a proprietary logging framework used by some applications servers, or for
logging to a graphical component for GUI applications.
A custom logging framework must include an implementation of the
org.apache.openjpa.lib.log.LogFactory interface. We present
a custom LogFactory below.
Custom Logging Class
package com.xyz;
import org.apache.openjpa.lib.log.*;
public class CustomLogFactory
implements LogFactory {
private String _prefix = "CUSTOM LOG";
public void setPrefix(String prefix) {
_prefix = prefix;
}
public Log getLog(String channel) {
// Return a simple extension of AbstractLog that will log
// everything to the System.err stream. Note that this is
// roughly equivalent to OpenJPA's default logging behavior.
return new AbstractLog() {
protected boolean isEnabled(short logLevel) {
// log all levels
return true;
}
protected void log(short type, String message, Throwable t) {
// just send everything to System.err
System.err.println(_prefix + ": " + type + ": "
+ message + ": " + t);
}
};
}
}
To make OpenJPA use your custom log factory, set the
openjpa.Log configuration
property to your factory's full class name. Because this property is a plugin
property (see ), you can also
pass parameters to your factory. For example, to use the example factory above
and set its prefix to "LOG MSG", you would set the openjpa.Log
property to the following string:
com.xyz.CustomLogFactory(Prefix="LOG MSG")
OpenJPA Audit
Transactional applications often require to audit changes in persistent objects.
OpenJPA can enable audit facility for all persistent entities in few simple steps.
ConfigurationAnnotate Persistent Entity
Any persistence entity can be enabled for audit by annotating with
org.apache.openjpa.audit.Auditable.
@javax.persistence.Entity
@org.apache.openjpa.audit.Auditable
public class MyDomainObject { ...}
This Auditable annotation enables auditing of creation, update or delete of
MyDomainObject instances. The Auditable annotation accepts
list of enumerated values org.apache.openjpa.audit.AuditableOperation namely
CREATE, UPDATE and DELETE to customize
only appropriate operations be audited. By deafult, all of the above operations are audited.
Configure Persistence Configuration
The audit facility is invoked at runtime via configuration of META-INF/persistence.xml.
The following property configures auditing via a default auditor
<property name="openjpa.Auditor" value="default"/>
The default auditor does not do much. It simply prints each auditable instance with its latest and original
states on a standard console (or to a designated file).
The latest state of an instance designates the state which is commited to the
database.
The originalstate designates the state when the instance entered the managed persistent
context. For example, when a new instance is persisted or a existing instance is loaded from the database.
Developing custom auditing
For real use case, an application will prefer more than printing the changed instances. The application, in
such case, needs to implement org.apache.openjpa.audit.Auditor interface.
This simple interface has the following method:
/**
* OpenJPA runtime will invoke this method with the given parameters
* within a transaction.
*
* @param broker the active persistence context.
* @param newObjects the set of auditable objects being created. Can be empty, but never null.
* @param updates the set of auditable objects being updated. Can be empty, but never null.
* @param deletes the set of auditable objects being deleted. Can be empty, but never null.
*/
public void audit(Broker broker, Collection<Audited> newObjects, Collection<Audited> updates,
Collection<Audited> deletes);
OpenJPA runtime will invoke this method before database commit. Via this callback method,
the application receives
the auditable instances in three separate collections of org.apache.openjpa.audit.Auditable.
An Auditable instance provides the latest and original state of a persistent object.
The latest object is
the same persistent instance to be committed. The original instance is a transient instance holding the
original state of the instance when it entered the managed context. The active persistence context
is also supplied in this callback method, so that an application may decide to persist the audit log
in the same database.
It is important to note that the original object can not be persisted in the same transaction, because
it has the same persistent identity of the latest object.
A single instance of implemented org.apache.openjpa.audit.Auditor interface
is available for a persistence unit. However, an application's own implementation of this interface
need not be thread-safe, because OpenJPA runtime guards against concurrent invocation of the
callback method.
The org.apache.openjpa.audit.Auditor interface is configurable. Hence any bean style
getter and setter method on its implementation will be populated as usual for any other OpenJPA plugin.
In the following example,
<property name="openjpa.Auditor" value="com.acme.Auditor(param2=10,param2='hello')"/>
An instance of com.acme.Auditor will be instantiated and if it has been style getter and
setter methods for param1 and param2, then the respective setters
will be called with 10 and "hello" before the instance being used.