Data Audit

Detailed information about the extension points and facilities for auditing data changes. It distinguishes between an Audit Log and an Audit Trail.

The audit log functionality stores the time and user of creation, modification and deletion of objects. This is stored for the root item in a channel specific way, and for every database table also.

The Audit Trail functionality stores also the value which has been changed in a historical way. So you can see not only who and when the record has been changed, but also what has been changed (which column), what was the value before etc.

Audit Trail

With Version 10.1 a completely new audit trail feature has been introduced which fully replaces the old audit trail facilities. Old and previously deprecated APIs have been removed and a new persistence layer has been created for the audit trail feature.

See the Knowledge Base for more general overview of the feature.

The new Audit Trail architecture is tightly integrated in the persistence layer of Product 360. For every create, modify or delete operation an EntityItemChange Document will be created and stored within the Elastic document storage.

Please see the Configuration Manual for details on how the Audit Trail feature can be configured.

The Migration Guide on details about the migration job which reads the old audit trail data from the relational database and moves it to the new storage.

There are a few Audit Trail Extension points which allow a customizing of the feature.

Audit Log


Audit logging is an important feature in an application which has a lot of users and data transaction every day. Providing delta reports for 3rd party systems like web-shops was one of the main functional focuses on the audit log released with the version 5.3. Therefore we enhanced the complete Persistence Model and provided also a new extension point specifically designed to be implemented by consulting in order to be prepared for the future and be most flexible in this area.

Physical audit log

Nearly all persistence objects support the Auditable base class (starting with the version 5.3). Therefore all the corresponding database tables have been enhanced accordingly (please see Persistence Model for details). The persister framework checks every persistence object which is going to be saved in the database and updates the creation/modification timestamps automatically. Clients must do just nothing for this feature except supporting the needed columns in their persistence tables.

Logical audit log

The requirements for logical audit logging of root entities is being driven by use cases like "Show all items which have been created by user 'abc' since yesterday", or "Show all items which have been modified since last week". To be able to fulfill these requirements we need to store audit log data not only in every table (like with the physical audit log), but also on the business root object. Unless that, we would need to join nearly all tables for a specific entity item so we can determine if the item has been changed. (Maybe only a price has changed, which would not be reflected in a change of the Article (or ArticleRevision) table. Additionally to that, the definition of "changed, created and deleted" may differ depending on specific scenarios which use this information. For example, regarding an ERP replication process only certain fields may be relevant for replication - therefore as seen from the ERP system, an object has been changed when one of those fields change only.

Up from the version 5.3 we returned from the approach of storing this data in a generic table, since in fact, the Product 360 server has no dynamic Persistence Model - we only have a dynamic Business Model. Introducing a generic model which stores data for multiple different entity types was confusing and error prone, thus we refactured this part in 5.3 again.

AuditLogWriter

The persister calls the AuditLogWriter after the persistence object has been modified by the mediators, but before flush is being called on the JPA EntityManager. With this we ensure two things:

  • Limit the number of database round trips and provide hibernate with the possibility to streamline the SQL statements it sends to the database.

  • Make sure that the audit log records are written in a synchronous and transaction safe manner. Thus we make sure that the audit log records are not written in case the entity item can not be saved due any reason.

    It's currently not possible to customize the AuditLogWriter itself, please use the AuditLogProvider for this

AuditLogProvider (deprecated)

Deprecation Notice

Starting with Version 8.1 users can configured a list of fields (optionally qualified) for the channel entity directly in the Desktop UI's channel management. The AuditLogProvider extension point is deprecated starting with version 10.1 and we do not recommend to use it any longer. Customers should use channels and their field configuration for this purpose.

Since direct interaction with the persistence layer is not a recommended customizing, we provide an extra interface which is specifically designed to be customized. The AuditLogProvider interface provides methods to implement special custom logic. The AuditLogWriter will read the current audit log record and calls then the AuditLogProvider which itself is responsible to set the creation/modification/deletion user and timestamp in the given AuditLogRecord object. The AuditLogProvider implementation however must not save this record to the database in any case! It's the AuditLogWriter which is responsible to build the bridge between Persister and AuditLogProvider and will save the AuditLogRecord in the most effective way. Please note that the AuditLogProvider interface also provides methods for bulk modifications of entity items. These methods will be called in case of bulk updates which occur in deletion scenarios mostly.

An entity item can have multiple logical audit log records which are distinguished by the classifier field. So you could have an audit log record specific for different export channels like ERP system or Web-Shop etc.

AuditLogProviders can be contributed with the com.heiler.ppm.persistence.auditLog extension point. If you want to have multiple audit log records, you will need to contribute also an appropriate classifier in this extension point.

In case you have multiple classifiers and therefore would have multiple audit log providers, we recommend to implement the MultiAuditLogProvider interface which makes it possible to provide all audit log values for all those classifiers in one call - this significantly improves performance depending on the needed logic in the audit log provider.

Sample implementation for MultiAuditLogProvider
package com.heiler.ppm.persistence.server.audit;
 
import java.util.Collection;
import java.util.Set;
 
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.emf.ecore.sdo.EDataObject;
 
import com.heiler.ppm.persistence.server.mediator.BusinessChangeSummary;
import com.heiler.ppm.repository.EntityType;
import com.heiler.ppm.repository.core.RepositoryComponent;
import com.heiler.ppm.repository.core.RepositoryService;
import com.heiler.ppm.revision.commons.RevisionToken;
 
public class CustomMultiAuditLogProvider extends MultiAuditLogProviderBaseImpl
{
private static final Log log = LogFactory.getLog( CustomMultiAuditLogProvider.class );
 
private RepositoryService repositoryService;
 
public CustomMultiAuditLogProvider()
{
this.repositoryService = RepositoryComponent.getRepositoryService();
}
 
@Override
public void onCreate( AuditLogData logData, Collection< AuditLogRecord > logRecords, RevisionToken revisionToken,
BusinessChangeSummary changeSummary, EDataObject businessObject )
{
if ( doTrigger( changeSummary ) )
{
log.info( "trigger onCreate( )" );
}
}
 
private boolean doTrigger( BusinessChangeSummary changeSummary )
{
boolean doTrigger = true;
EntityType mediaAssetDocumentEntityType = this.repositoryService.getEntityTypeByIdentifier( "MediaAssetDocumentType" );
Set< EDataObject > mediaAssetDocuments = changeSummary.getDataObjectsForEntityType( mediaAssetDocumentEntityType );
 
for ( EDataObject mediaAssetDocument : mediaAssetDocuments )
{
String quality = mediaAssetDocument.getString( "quality" );// find "object name" in types area of repository
if ( "web".equals( quality ) )
{
doTrigger = false;
break;
}
}
return doTrigger;
}
 
@Override
public void onChange( AuditLogData logData, Collection< AuditLogRecord > logRecords, RevisionToken revisionToken,
BusinessChangeSummary changeSummary, EDataObject businessObject )
{
if ( doTrigger( changeSummary ) )
{
log.info( "trigger onChange( )" );
}
}
 
@Override
public void onBulkChange( AuditLogData logData, Collection< AuditLogRecord > logRecord, RevisionToken revisionToken,
AuditChangeSummary changeSummary, Object[] primaryKeys )
{
// ...
}
 
@Override
public void onBulkDelete( AuditLogData logData, Collection< AuditLogRecord > logRecord, RevisionToken revisionToken,
AuditChangeSummary changeSummary, Object[] primaryKeys )
{
// ...
}
}

HPM Provider

Since in previous Product 360 releases we already had a root entity audit log feature enabled for certain entities we needed to provide a default implementation which fulfills this known feature. The default implementation writes a "created, changed and deleted" value based on the physical events. Thus in case of any change, the default implementation will write the modification date/user and in case of delete it will write the deleted date/user.
This default implementation is contributed for all entity types and the classifier: "HPM".

Repository Definition

The types area of the repository has been enhanced to have a 1:n sub-entity for every root entity for all entity types. Logical key will be the mentioned classifier. The custom entity uses an enumeration of available classifiers and a default qualification for this key with "HPM". So the fields can be re-qualified by the user to show the audit log information for a different classifier. The used classifier enum provider uses the classifier elements from the com.heiler.ppm.persistence.auditLog extension point.