Feature

Germain’s Document Audit mechanism (state changes as events) stores documents (custom business objects) and their history of changes, while outputting events that represent the real-time changes to those documents as they are updated.

Use Cases

Data Audit Trail

Track changes / auditing any Structured Data (records) in any external system (e.g. via REST, SQL, SOAP, etc)

Business Data Status

Track how long a record stays in a specific status.

Examples

  • Time to respond to a ticket

  • Time to resolve a service request

  • etc

User Behavior Analytics

Collect statistics on User behavior

Examples:

  • Times a User edits a record

  • Most prolific editors

  • etc.

Alert on Content

Alert based on content of document fields;

Example:

  • Look for keywords that trigger alerts / events in a system.

Configuration

Consume DocumentChange outputs

Customize the “document-audit-default” Rule or create a new Rule for processing the DocumentChange events output by the Document Service. (In the configuration console, make sure germain.apm.documentAudit.rule is set to document-audit-default or the name of your new Rule.)

The “document-audit-default” Rule customized for Siebel Service Requests:

package com.germainsoftware.apm.analytics.audit;

dialect "mvel"
 
import com.germainsoftware.apm.data.model.*;
import com.germainsoftware.apm.storage.documentAudit.DocumentChange;
import java.time.*;

global org.slf4j.Logger logger;
global com.germainsoftware.apm.storage.StorageService storage;

rule "Siebel Service Request Rule"
when
	$update : DocumentChange( documentType == "Siebel SR", path == "status" )
then
	logger.info("SR Change: {}", $update.value);
	// create new SR Status Changed Event
	GenericEvent ev = new GenericEvent();
	ev.name = $update.documentType;
	ev.type = "Siebel:SR Change";
	ev.timestamp = $update.timeCreated;
	ev.businessObject = $update.value;
	ev.sequence = $update.documentId;
	storage.insertFact(ev);
	retract($update)
end
CODE

Schema of a DocumentChange:

class DocumentChange {
    String documentId;
    String documentType;
    Map<String, String> documentMetadata;
    ValueMap documentBody;
    OffsetDateTime timeCreated;
    Map<String, String> metadata;
    String author;
    String path;
    Object value;
    Object oldValue;
}
CODE

Generate DocumentUpdate inputs (engine)

Customize the Rule(s) used by the various monitoring components (e.g. QueryMonitor) to generate DocumentUpdate events for input into the Document Service.

The following is an example based around Siebel Service Requests. The SQL used by the QueryMonitor:

select LAST_UPD, ROW_ID, CREATED, CREATED_BY, LAST_UPD_BY, SR_NUM, SR_PRIO_CD, SR_SEV_CD, SR_STAT_ID, SR_TITLE
from SIEBEL.S_SRV_REQ
where LAST_UPD > ?
order by LAST_UPD asc
SQL

The Rule referenced by the QueryMonitor:

import java.util.Calendar;
import java.util.regex.*;
import java.time.*;
import java.time.temporal.*;
import com.germainsoftware.apm.config.data.*;
import com.germainsoftware.apm.converter.*;
import com.germainsoftware.apm.data.model.*;
import com.germainsoftware.apm.data.indexer.*;
import com.germainsoftware.apm.message.*;
import com.germainsoftware.apm.model.*;
import com.germainsoftware.apm.router.*;
global org.slf4j.Logger logger;
global com.germainsoftware.apm.converter.DatamartConverter datamart;
global com.germainsoftware.apm.router.RouterContext context;

rule "Siebel SR"
when
    $msg : QueryResultMessage( category == "Siebel SR" )
then
    DocumentUpdate doc = new DocumentUpdate($msg.getString(1), "Siebel SR", $msg.getString(4));

    doc.timestamp = $msg.getTimestamp(0); // LAST_UPD
    doc.set("created", $msg.getTimestamp(2).toString()); // CREATED
    doc.set("createdBy", $msg.getString(3)); // CREATED_BY
    doc.set("number", $msg.getString(5)); // SR_NUM
    doc.set("priority", $msg.getString(6)); // SR_PRIO_CD
    doc.set("severity", $msg.getString(7)); // SR_SEV_CD
    doc.set("status", $msg.getString(8)); // SR_STAT_ID
    doc.set("title", $msg.getString(9)); // SR_TITLE

    Queues.postDocumentUpdate(doc);

    retract($msg);
end
JAVA

Schema of a DocumentUpdate:

interface DocumentUpdate {
  DocumentUpdate(String documentId, String documentType, String author);
  OffsetDateTime timestamp;
  HashMap<String, String> documentMetadata; // Custom properties about the document e.g. { title: 'My First Opportunity' }
  void addAttribute(String attributeName, String value); // Set custom properties about this change
  void set(String path, @Nullable Object value); // Set fields of the document. The format of paths: "child.grandchild.greatgrandchild"
  void deletePath(String path); // To drop a field from a document.
}
CODE

Generate DocumentUpdate inputs (Web UX)

Customize the initScript, of the corresponding Web-UX Monitoring Profile, to generate DocumentUpdate events for input into the Document Service.

BOOMR.utils.addToDocumentAuditQueue(update: DocumentUpdate);

type DocumentUpdate = {
  documentId: string
  documentType: string
  documentMetadata: Record<string, string> // Custom properties about the document
  timestamp: number
  author: string
  metadata: Record<string, string> // Custom properties about this change
  fieldUpdates: FieldUpdate[]
}

type FieldUpdate = {
  path: string
  valueJson: string
  spliceIndex: number
  deleteCount: number
}
TYPESCRIPT

Notes

All this may change depending on your data sources and requirements

Service: Analytics

Feature Availability: 2022.1 or later