13.2. Audit Log

Storing information about the execution of process instances are useful in many cases. For example, when you need to:
  • verify which actions have been executed for a particular process instance.
  • monitor and analyze the efficiency of a particular process.
However, storing history information in the runtime database can result in the database rapidly increasing in size. Additionally, monitoring and analysis queries might influence the performance of your runtime engine. This is why process execution history information is stored separately.
This history log of execution information is created based on events that the process engine generates during execution. This is possible because the JBoss BPM Suite runtime engine provides a generic mechanism to listen to events. The necessary information can easily be extracted from these events and then persisted to a database. You can also use filters to limit the scope of the logged information.
The jbpm-audit module contains an event listener that stores process-related information in a database using JPA. The data model itself contains three entities, one for process instance information, one for node instance information, and one for (process) variable instance information:
  • The ProcessInstanceLog table contains the basic log information about a process instance.
  • The NodeInstanceLog table contains information about which nodes were actually executed inside each process instance. Whenever a node instance is entered from one of its incoming connections or is exited through one of its outgoing connections, that information is stored in this table.
  • The VariableInstanceLog table contains information about changes in variable instances. The default is to only generate log entries when (after) a variable changes. It is also possible to log entries before the variable (value) changes.
To log process history information in a database, you need to register the logger on your session as shown below:
EntityManagerFactory emf = ...;
StatefulKnowledgeSession ksession = ...;
AbstractAuditLogger auditLogger = AuditLoggerFactory.newJPAInstance(emf);
ksession.addProcessEventListener(auditLogger);

// invoke methods one your session here
To specify the database where the information must be stored, modify the file persistence.xml file to include the audit log classes as well (ProcessInstanceLog, NodeInstanceLog and VariableInstanceLog), as shown below:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<persistence

  version="2.0"

  xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd

  http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_2_0.xsd"

  xmlns="http://java.sun.com/xml/ns/persistence"

  xmlns:orm="http://java.sun.com/xml/ns/persistence/orm"

  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance>



  <persistence-unit name="org.jbpm.persistence.jpa" transaction-type="JTA">

    <provider>org.hibernate.ejb.HibernatePersistence</provider>

    <jta-data-source>jdbc/jbpm-ds</jta-data-source>

    <mapping-file>META-INF/JBPMorm.xml</mapping-file>

    <class>org.drools.persistence.info.SessionInfo</class>

    <class>org.jbpm.persistence.processinstance.ProcessInstanceInfo</class>

    <class>org.drools.persistence.info.WorkItemInfo</class>

    <class>org.jbpm.persistence.correlation.CorrelationKeyInfo</class>

    <class>org.jbpm.persistence.correlation.CorrelationPropertyInfo</class>

    <class>org.jbpm.runtime.manager.impl.jpa.ContextMappingInfo</class>



    <class>org.jbpm.process.audit.ProcessInstanceLog</class>

    <class>org.jbpm.process.audit.NodeInstanceLog</class>

    <class>org.jbpm.process.audit.VariableInstanceLog</class>



    <properties>

      <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>

      <property name="hibernate.max_fetch_depth" value="3"/>

      <property name="hibernate.hbm2ddl.auto" value="update"/>

      <property name="hibernate.show_sql" value="true"/>

      <property name="hibernate.transaction.jta.platform"

      value="org.hibernate.service.jta.platform.internal.BitronixJtaPlatform"/>

    </properties>

  </persistence-unit>

</persistence>
You can easily query this information and use them in a lot of use cases, ranging from creating a history log for one specific process instance to analyzing the performance of all instances of a specific process.
This audit log must only be considered a default implementation. For performance reasons, it is recommended to only store the relevant data that you require for analysis. Depending on your use cases, define your own data model for storing the information you need, and use the process event listeners to extract that information.
Process events are stored in the database synchronously and within the same transaction as actual process instance execution. This takes some time especially in highly loaded systems and may have some impact on the database when both history log and runtime data are kept in the same database. To provide an alternative option for storing process events, JBoss BPM Suite provides a JMS based logger. You can configure it to submit messages to JMS queue instead of directly persisting them in the database. You can configure it to be transactional as well to avoid issues with inconsistent data in case of process engine transaction is rolled back.
ConnectionFactory factory = ...;
Queue queue = ...;
StatefulKnowledgeSession ksession = ...;
Map<String, Object> jmsProps = new HashMap<String, Object>();
jmsProps.put("jbpm.audit.jms.transacted", true);
jmsProps.put("jbpm.audit.jms.connection.factory", factory);
jmsProps.put("jbpm.audit.jms.queue", queue);
AbstractAuditLogger auditLogger = AuditLoggerFactory.newInstance(Type.JMS, session, jmsProps);
ksession.addProcessEventListener(auditLogger);

// invoke methods one your session here