This topic provides code examples for the following auditing operations:
Note that you can audit a custom event by raising it on an object. Auditing a custom event is, in large part, a matter of creating the custom event and raising it on an object that is defined as the target of a subscription. For an example of this, see Creating and Raising a Custom Event. In order for a custom event to be audited when raised, you must first configure it for auditing, as described in Configuring a Class for Auditing.
For an overview of auditing functionality, see Auditing Concepts.
Auditing is configured on a per-class basis, in which a class is represented by a
SubscribableClassDefinition object.
An event to be audited for a class is represented by an
EventClassDefinition object.
The audit configuration information is held in an
AuditDefinition object,
and contains an EventClassDefinition
object.
There is one AuditDefinition
object for each event to be audited in a class.
A SubscribableClassDefinition
object can contain one or more AuditDefinition
objects.
The following steps describe how to configure a class for auditing:
SubscribableClassDefinition
object or subobject, such as the Document class.EventClassDefinition
object, such as the CreationEvent.AuditDefinition
object.AuditDefinitionList
object.AuditDefinition
object properties, such as EventClass, which takes the EventClassDefinition
object.AuditDefinition
object to the AuditDefinitionList
object.SubscribableClassDefinition
object's AuditDefinitions property to the AuditDefinitionList
object.In the following Java™ and C# examples, two events associated with the Document class are configured for auditing.
The Document
class is represented by DocumentClassDefinition
,
a subclass of SubscribableClassDefinition
.
The configured events are a system event, CreationEvent
, and a custom event. The custom event was previously created and is specified by a GUID.
The events to be audited are set in the EventClass property. Note that in addition to the EventClass property, other AuditDefinition
object properties are set.
Also note that the code verifies that auditing is enabled on the object store before the class is configured for auditing.
Java Example
// Make sure auditing is enabled for the object store if (os.get_AuditLevel()==AuditLevel.NONE) { os.set_AuditLevel(AuditLevel.ENABLED); os.save(RefreshMode.REFRESH); } // Fetch class definition for Document DocumentClassDefinition dcd = Factory.DocumentClassDefinition.fetchInstance(os, GuidConstants.Class_Document, null); // Get AuditDefinitionList from DocumentClassDefinition object AuditDefinitionList adl = dcd.get_AuditDefinitions(); // Create AuditDefinition object to be set with a system event AuditDefinition ad = Factory.AuditDefinition.createInstance(os); // Get EventClassDefinition for system event EventClassDefinition ecd = Factory.EventClassDefinition.getInstance(os, GuidConstants.Class_CreationEvent); // Set properties on AuditDefinition object for system event ad.set_EventClass(ecd); ad.set_AuditSuccess(new Boolean("TRUE")); ad.set_AuditFailure(new Boolean("TRUE")); ad.set_IncludeSubclassesRequested(new Boolean("TRUE")); ad.set_ObjectStateRecordingLevel(ObjectStateRecordingLevel.NONE); // Add first audit definition to list for system event adl.add(ad); // Create AuditDefinition object to be set with a custom event AuditDefinition ad2 = Factory.AuditDefinition.createInstance(os); // Get EventClassDefinition for custom event EventClassDefinition ecd2 = Factory.EventClassDefinition.getInstance(os, new Id("{9906D34A-DBE2-415E-B807-6B4CCA65B893}")); // Set properties on AuditDefinition object for custom event ad2.set_EventClass(ecd2); ad2.set_AuditSuccess(new Boolean("TRUE")); ad2.set_AuditFailure(new Boolean("TRUE")); ad2.set_IncludeSubclassesRequested(new Boolean("TRUE")); ad2.set_ObjectStateRecordingLevel(ObjectStateRecordingLevel.ORIGINAL_AND_MODIFIED_OBJECTS); // Add second audit definition to list for custom event adl.add(ad2); // Set AuditDefinitions property on DocumentClassDefinition object dcd.set_AuditDefinitions(adl); // Save DocumentClassDefinition object dcd.save(RefreshMode.REFRESH);
C# Example
// Make sure auditing is enabled for the object store if (os.AuditLevel == AuditLevel.NONE) { os.AuditLevel = AuditLevel.ENABLED; os.Save(RefreshMode.REFRESH); } // Fetch class definition for document IDocumentClassDefinition dcd = Factory.DocumentClassDefinition.FetchInstance(os, GuidConstants.Class_Document,null); // Get AuditDefinitionList from DocumentClassDefinition object IAuditDefinitionList adl = dcd.AuditDefinitions; // Create audit definition to be set with a system event IAuditDefinition ad = Factory.AuditDefinition.CreateInstance(os); // Get EventClassDefinition for system event IEventClassDefinition ecd = Factory.EventClassDefinition.GetInstance ( os, GuidConstants.Class_CreationEvent); // Set properties on audit definition object for system event ad.EventClass = ecd; ad.AuditSuccess = true; ad.AuditFailure = true; ad.IncludeSubclassesRequested = true; ad.ObjectStateRecordingLevel=ObjectStateRecordingLevel.NONE; // Add first audit definition to list for system event adl.Add(ad); // Create AuditDefinition object to be set with a custom event IAuditDefinition ad2 = Factory.AuditDefinition.CreateInstance(os); // Get EventClassDefinition for custom event IEventClassDefinition ecd2 = Factory.EventClassDefinition.GetInstance ( os, new Id("{9906D34A-DBE2-415E-B807-6B4CCA65B893}")); // Set properties on AuditDefinition object for custom event ad2.EventClass = ecd; ad2.AuditSuccess = true; ad2.AuditFailure = true; ad2.IncludeSubclassesRequested = true; ad2.ObjectStateRecordingLevel=ObjectStateRecordingLevel.ORIGINAL_AND_MODIFIED_OBJECTS; // Add second audit definition to list for custom event adl.Add(ad2); // Set AuditDefinitions property on DocumentClassDefinition object dcd.AuditDefinitions = adl; // Save DocumentClassDefinition object dcd.Save(RefreshMode.REFRESH);
You can retrieve the audit definitions defined for a class by getting the AuditDefinitions
property on a
SubscribableClassDefinition-derived object,
which returns a list of AuditDefinition
objects. By iterating the list for AuditDefinition
objects,
you can find the audited events for which the class is configured.
One use case for retrieving audit definitions is to verify that a particular audit event
is configured for a class. In the following Java and C# code snippets, the Document
class, as represented by a
DocumentClassDefinition
object, is tested for a custom event, which is specified by a GUID.
If the Document
class is configured to be audited for the custom event, the code prints out
configuration information about the audited custom event.
Java Example
// Retrieve class definition for Document DocumentClassDefinition dcd = Factory.DocumentClassDefinition.fetchInstance ( os, GuidConstants.Class_Document, null); // Get list of AuditDefinition objects configured for the Document class, // iterate through it, and test each AuditDefinition object for // the custom event. AuditDefinitionList adl=dcd.get_AuditDefinitions(); Iterator adlIter = adl.iterator(); while (adlIter.hasNext()) { AuditDefinition ad = (AuditDefinition) adlIter.next(); EventClassDefinition ecd = ad.get_EventClass(); if (ecd.get_Id().equals(new Id("{9906D34A-DBE2-415E-B807-6B4CCA65B893}"))) { System.out.println ( "Audited class is " + dcd.get_DisplayName() + "\n" + "Audited custom event is " + ecd.get_DisplayName() + "\n" + "Audit successes? " + ad.get_AuditSuccess() + "\n" + "Audit failures? " + ad.get_AuditFailure() + "\n" + "Audit subclasses? " + ad.get_IncludeSubclassesRequested() + "\n" + "Recording level? " + ad.get_ObjectStateRecordingLevel() ); } }
C# Example
// Retrieve class definition for Document IDocumentClassDefinition dcd = Factory.DocumentClassDefinition.FetchInstance ( os, GuidConstants.Class_Document, null); // Get list of AuditDefinition objects configured for the Document class, // iterate through it, and test each AuditDefinition object for the custom event. IAuditDefinitionList adl = dcd.AuditDefinitions; foreach (IAuditDefinition ad in adl) { IEventClassDefinition ecd = ad.EventClass; if (ecd.Id.Equals(new Id("{9906D34A-DBE2-415E-B807-6B4CCA65B893}"))) { System.Console.WriteLine ( "Audited class is " + dcd.Name + "\n" + "Audited custom event is " + ecd.DisplayName + "\n" + "Audited successes? " + ad.AuditSuccess + "\n" + "Audited failures? " + ad.AuditFailure + "\n" + "Audit subsclasses? " + ad.IncludeSubclassesRequested + "\n" + "Recording level? " + ad.ObjectStateRecordingLevel ); } }
You can retrieve audit history for instances of
classes with the
AuditedEvents property.
(You can also query the audit event log
for historical information.) The following Java and C# code snippets retrieve a Document
object's AuditedEvents property,
and then they print property values for each Event
object in the EventSet
collection.
Java Example
// Get Document object from which audit history will be retrieved Document doc=Factory.Document.fetchInstance(os, new Id("{7AFAC25E-D27B-49A8-B31C-E555EC87608A}"),null); // Get audited events that have been fired on Document object, if any EventSet es = doc.get_AuditedEvents(); // If EventSet collection not empty, iterate it for events that // have been fired on Document object. if (!es.isEmpty()) { Iterator esIter = es.iterator(); while (esIter.hasNext()) { Event event = (Event) esIter.next(); System.out.println( "Event is " + event.getClassName() + "\n" + "Event ID is " + event.get_Id().toString()+ "\n" + "Event initiator is " + event.get_InitiatingUser() + "\n" + "Event date is " + event.get_DateCreated().toString() ); } } else System.out.println("No audited events have been fired for this object");
C# Example
// Get Document object from which audit history will be retrieved IDocument doc = Factory.Document.FetchInstance ( os, new Id("{7AFAC25E-D27B-49A8-B31C-E555EC87608A}"), null); //Get audited events that have been fired on Document object, if any IEventSet es = doc.AuditedEvents; // If EventSet collection is not empty, iterate it for events that have been fired on Document object if (!es.IsEmpty()) { foreach (IEvent docEvent in es) { System.Console.WriteLine ( "Event is " + docEvent.GetClassName() + "\n" + "Event ID is " + docEvent.Id.ToString() + "\n" + "Event initiator is " + docEvent.InitiatingUser + "\n" + "Event date is " + docEvent.DateCreated.ToString() ); } } else { System.Console.WriteLine("No audited events have been fired for this object"); }
You can query the audit event log, which is the Event table in an object store's database. The easiest way to query the log is with Enterprise Manager, from which you can create SQL searches or launch out-of-the-box search templates (see Concepts: search and bulk operations). However, as described in this section, you can also use the Content Java and .NET APIs to work with the audit log.
The APIs include query classes designed for ad hoc searches, allowing you to pass a SQL statement specifying the Event
object
to be searched and the object's properties to be retrieved. As shown in the Java and C# examples below,
a SearchSQL
object is constructed with a SQL statement string that specifies a search for creation events.
To execute the search, the SearchSQL
object
is passed in the fetchRows
call on the SearchScope
object.
Then the property values are printed out for each recorded creation event.
For overview information, see Auditing and Trace Logging and Search Concepts. For information on which properties are searchable, selectable, and orderable, refer to the metadata for each property in Event Properties.
Java Example
// Build the SQL select statement String sqlString = "SELECT " + PropertyNames.ID +"," + PropertyNames.DATE_CREATED + "," + PropertyNames.INITIATING_USER + "," + PropertyNames.EVENT_STATUS; // Construct SearchSQL object to be used in the search operation for creation events. See Note below. SearchSQL sql = new SearchSQL(sqlString + " FROM " + GuidConstants.Class_CreationEvent + " ORDER BY " + PropertyNames.DATE_CREATED + " DESC"); // Execute the search operation SearchScope ss = new SearchScope(os); RepositoryRowSet rrc = ss.fetchRows(sql, null, null, null); // Iterate and print search results Iterator it = rrc.iterator(); while (it.hasNext()) { RepositoryRow rr = (RepositoryRow) it.next(); System.out.println ( rr.getProperties().getIdValue(PropertyNames.ID).toString()+ "\n" + rr.getProperties().getDateTimeValue(PropertyNames.DATE_CREATED)+ "\n" + rr.getProperties().getStringValue(PropertyNames.INITIATING_USER) + "\n" + rr.getProperties().getInteger32Value(PropertyNames.EVENT_STATUS) ); }
C# Example
// Build the SQL select statement string sqlString = "SELECT " + PropertyNames.ID + "," + PropertyNames.DATE_CREATED + "," + PropertyNames.INITIATING_USER + "," + PropertyNames.EVENT_STATUS; // Construct SearchSQL object to be used in the search operation. See Note below. SearchSQL sql = new SearchSQL(sqlString + " FROM " + GuidConstants.Class_CreationEvent + " ORDER BY " + PropertyNames.DATE_CREATED + " DESC"); // Execute the search operation SearchScope ss = new SearchScope(os); IRepositoryRowSet rrc = ss.FetchRows(sql, null, null, null); // Iterate and print search results foreach (IRepositoryRow rr in rrc) { System.Console.WriteLine ( rr.Properties.GetIdValue(PropertyNames.ID).ToString() + "\n" + rr.Properties.GetDateTimeValue(PropertyNames.DATE_CREATED)+ "\n" + rr.Properties.GetStringValue(PropertyNames.INITIATING_USER) + "\n" + rr.Properties.GetInteger32Value(PropertyNames.EVENT_STATUS) + "\n" ); }
NOTE The above examples show how to retrieve from the log auditing information for a specified event (creation).
Another use case is to get auditing information for a specified object.
For example, you could construct a query for all Event
objects where the
SourceObjectId property is equal to an auditable object of interest.
As described in Source Object Persistence, you can configure an AuditDefinition to record the source object of an event (the object on which the event is fired). Then, when the event is triggered, the source object is persisted to the audit event log (the Event table in the database), along with other event information.
Because of the extra database space required to store source objects in audited events, you can configure the recording level of the source object with the AuditDefinition.ObjectStateRecordingLevel
property. The recording levels are ORIGINAL_AND_MODIFIED_OBJECTS (both the original, pre-event object and the modified, post-event object are recorded), MODIFIED_OBJECT (only the modified, post-event object is recorded), and NONE (no source objects are recorded). If NONE is specified, then the event's ModifiedProperties property will also be empty because this value is derived from the event's SourceObject property.
The following Java and C# examples show how to retrieve source objects from the audit event log. The SQL statement specifies that checkin events of a certain age be retrieved from the log, and includes properties for the source modified object and the source original object. After the search executes, the code iterates the results. For each audited Event
object, the code prints information about the event and the event's source objects, if any. The code checks for events in which only the modified source object was recorded or in which no source objects were recorded.
NOTE Because there can be substantial numbers of records in the Event table, it is advised that an SQL statement that queries this table include a WHERE
clause to limit the result set.
Java Example
// Build the SQL select statement String sqlString = "SELECT " + PropertyNames.ID +"," + PropertyNames.DATE_CREATED + "," + PropertyNames.EVENT_STATUS + "," + PropertyNames.ORIGINAL_OBJECT + "," + PropertyNames.SOURCE_OBJECT; // Construct SearchSQL object to be used in search operation SearchSQL sql = new SearchSQL(sqlString + " FROM " + GuidConstants.Class_CheckinEvent + " WHERE " + PropertyNames.DATE_CREATED + "> 20080401T080000Z" + " ORDER BY " + PropertyNames.DATE_CREATED); // Execute the search operation SearchScope ss = new SearchScope(os); RepositoryRowSet rrc = ss.fetchRows(sql, null, null, null); // Iterate and print results Iterator it = rrc.iterator(); while (it.hasNext()) { RepositoryRow rr = (RepositoryRow) it.next(); // Get recorded Event object and print information about it Id eventId = rr.getProperties().getIdValue(PropertyNames.ID); Event eventObject = Factory.Event.fetchInstance(os, eventId, null); String eventStatus = rr.getProperties().getInteger32Value(PropertyNames.EVENT_STATUS).equals(new Integer(0)) ? "Succeeded" : "Failed"; System.out.println("Event Properties:\n" + " Event ID: " + eventId.toString()+ "\n" + " Event Name: " + eventObject.getClassName()+ "\n" + " Date Created: " + rr.getProperties().getDateTimeValue(PropertyNames.DATE_CREATED)+ "\n" + " Event Status: " + eventStatus ); // Get source modified object and print name of object and date last modified. // If the modified object was not recorded, null returned. IndependentObject modifiedObject = (IndependentObject)rr.getProperties().getObjectValue(PropertyNames.SOURCE_OBJECT); if (modifiedObject!=null) { try { System.out.println("Source modified object: " + "\n Name: " + modifiedObject.getProperties().getStringValue(PropertyNames.NAME) + "\n Date object modified: " + modifiedObject.getProperties().getDateTimeValue(PropertyNames.DATE_LAST_MODIFIED) ); } catch (EngineRuntimeException e) { System.out.println("Source modified object:\n " + e.getMessage() ); } } else { // If the modified object was not recorded then neither was the original object System.out.println("There is no source modified or source original object recorded for this audited event." + "\n=================================\n"); continue; } // Get source original object and print name of object and date last modified. // If original object was not recorded, null returned. IndependentObject originalObject = (IndependentObject) rr.getProperties().getObjectValue(PropertyNames.ORIGINAL_OBJECT); if (originalObject!=null) { try { System.out.println("Source original object: " + "\n Name: " + originalObject.getProperties().getStringValue(PropertyNames.NAME) + "\n Date object modified: " + originalObject.getProperties().getDateTimeValue(PropertyNames.DATE_LAST_MODIFIED) ); } catch (EngineRuntimeException e) { System.out.println("Source original object: \n " + e.getMessage() ); } System.out.println("\n=================================\n"); } else { System.out.println("There is no source original object recorded for this audited event." + "\n=================================\n"); } }
C# Example
// Build the SQL select statement String sqlString = "SELECT " + PropertyNames.ID + "," + PropertyNames.DATE_CREATED + "," + PropertyNames.EVENT_STATUS + "," + PropertyNames.ORIGINAL_OBJECT + "," + PropertyNames.SOURCE_OBJECT; // Construct SearchSQL object to be used in search operation SearchSQL sql = new SearchSQL(sqlString + " FROM " + GuidConstants.Class_CheckinEvent + " WHERE " + PropertyNames.DATE_CREATED + "> 20080401T080000Z" + " ORDER BY " + PropertyNames.DATE_CREATED); // Execute the search operation SearchScope ss = new SearchScope(os); IRepositoryRowSet rrc = ss.FetchRows(sql, null, null, null); // Iterate and print results foreach (IRepositoryRow rr in rrc) { IIndependentObject modifiedObject; IEvent eventObject; // Get recorded Event object and print information about it Id eventId = rr.Properties.GetIdValue(PropertyNames.ID); eventObject = Factory.Event.FetchInstance(os, eventId, null); String eventStatus = rr.Properties.GetInteger32Value(PropertyNames.EVENT_STATUS) == 0 ? "Succeeded" : "Failed"; System.Console.WriteLine("Event Properties:\n" + " Event ID: " + eventId.ToString() + "\n" + " Event Name: " + eventObject.GetClassName() + "\n" + " Date Created: " + rr.Properties.GetDateTimeValue(PropertyNames.DATE_CREATED)+ "\n" + " Event Status: " + eventStatus ); // Get source modified object and print name of object and date last modified. // If the modified object was not recorded, null returned. modifiedObject = (IIndependentObject)rr.Properties.GetObjectValue(PropertyNames.SOURCE_OBJECT); if (modifiedObject!=null) { try { System.Console.WriteLine("Source modified object: " + "\n Name: " + modifiedObject.Properties.GetStringValue(PropertyNames.NAME) + "\n Date object modified: " + modifiedObject.Properties.GetDateTimeValue(PropertyNames.DATE_LAST_MODIFIED) ); } catch (EngineRuntimeException e) { System.Console.WriteLine("Source modified object:\n " + e.Message ); } } else { // If the modified object was not recorded then neither was the original object System.Console.WriteLine("There is no source modified or source original object recorded for this audited event." + "\n=================================\n"); continue; } // Get source original object and print name of object and date last modified. // If original object was not recorded, null returned. IIndependentObject originalObject = (IIndependentObject)rr.Properties.GetObjectValue(PropertyNames.ORIGINAL_OBJECT); if (originalObject!=null) { try { System.Console.WriteLine("Source original object: " + "\n Name: " + originalObject.Properties.GetStringValue(PropertyNames.NAME) + "\n Date object modified: " + originalObject.Properties.GetDateTimeValue(PropertyNames.DATE_LAST_MODIFIED) ); } catch (EngineRuntimeException e) { System.Console.WriteLine("Source original object: \n " + e.Message ); } System.Console.WriteLine("\n=================================\n"); } else { System.Console.WriteLine("There is no source original object recorded for this audited event." + "\n=================================\n"); } }