Audit Trail and Change Logging
Create detailed audit trail records when sensitive fields are modified, maintaining compliance and tracking changes.
Table: incident When: after
#audit #logging #compliance #tracking #after #update #change-history #security
Script Code
JavaScript
1(function executeRule(current, previous /*null when async*/) {
2
3 // Configuration: Define fields to audit
4 var auditedFields = [
5 'priority',
6 'state',
7 'assignment_group',
8 'assigned_to',
9 'close_code',
10 'resolved_by'
11 ];
12
13 // Configuration: Define critical tables that require full auditing
14 var criticalTables = ['incident', 'change_request', 'problem'];
15
16 // Check if any audited fields changed
17 var changedFields = [];
18 auditedFields.forEach(function(fieldName) {
19 if (current[fieldName].changes()) {
20 changedFields.push(fieldName);
21 }
22 });
23
24 // Only proceed if there are changes to audit
25 if (changedFields.length === 0) {
26 return;
27 }
28
29 // Create audit records for each changed field
30 changedFields.forEach(function(fieldName) {
31 var grAudit = new GlideRecord('u_audit_trail'); // Create this table for audit logging
32 grAudit.initialize();
33
34 // Record metadata
35 grAudit.u_table_name = current.getTableName();
36 grAudit.u_record_id = current.sys_id.toString();
37 grAudit.u_record_number = current.number.toString();
38 grAudit.u_field_name = fieldName;
39
40 // Get field label
41 var fieldLabel = current.getElement(fieldName).getLabel();
42 grAudit.u_field_label = fieldLabel;
43
44 // Record old and new values
45 var oldValue = previous ? previous.getValue(fieldName) : '';
46 var newValue = current.getValue(fieldName);
47
48 grAudit.u_old_value = oldValue;
49 grAudit.u_new_value = newValue;
50
51 // Get display values for reference fields
52 if (current.getElement(fieldName).getED().isReference()) {
53 grAudit.u_old_display_value = previous ? previous[fieldName].getDisplayValue() : '';
54 grAudit.u_new_display_value = current[fieldName].getDisplayValue();
55 }
56
57 // Record who made the change
58 grAudit.u_changed_by = gs.getUserID();
59 grAudit.u_changed_at = new GlideDateTime();
60
61 // Record IP address and session info
62 grAudit.u_ip_address = gs.getSession().getClientIP();
63 grAudit.u_session_id = gs.getSession().getSessionToken();
64
65 // Categorize the change type
66 if (fieldName === 'state') {
67 grAudit.u_change_type = 'Status Change';
68 } else if (fieldName === 'assignment_group' || fieldName === 'assigned_to') {
69 grAudit.u_change_type = 'Assignment Change';
70 } else if (fieldName === 'priority') {
71 grAudit.u_change_type = 'Priority Change';
72 } else {
73 grAudit.u_change_type = 'Field Update';
74 }
75
76 // Add business context
77 grAudit.u_reason = current.work_notes.toString() || 'No reason provided';
78
79 // Insert audit record
80 var auditId = grAudit.insert();
81
82 if (auditId) {
83 gs.info('Audit trail created for ' + current.number + ', field: ' + fieldLabel +
84 ', changed by: ' + gs.getUserName());
85 }
86 });
87
88 // Optional: Send alert for critical changes
89 if (changedFields.indexOf('priority') !== -1) {
90 var oldPriority = previous ? previous.priority.toString() : '';
91 var newPriority = current.priority.toString();
92
93 // Alert if priority increased to Critical
94 if (newPriority === '1' && oldPriority !== '1') {
95 gs.eventQueue('audit.critical_priority_change', current, gs.getUserID(), current.sys_id);
96 gs.warn('AUDIT: Priority changed to Critical for ' + current.number +
97 ' by ' + gs.getUserName());
98 }
99 }
100
101 // Optional: Add audit summary to work notes
102 var auditSummary = 'AUDIT: Fields changed - ' + changedFields.join(', ') +
103 ' | Changed by: ' + gs.getUserName() +
104 ' | Time: ' + new GlideDateTime().getDisplayValue();
105 current.comments = auditSummary;
106
107})(current, previous);
How to Use
1. Create a custom table u_audit_trail with fields: u_table_name, u_record_id, u_record_number, u_field_name, u_field_label, u_old_value, u_new_value, u_old_display_value, u_new_display_value, u_changed_by, u_changed_at, u_ip_address, u_session_id, u_change_type, u_reason
2. Create an after Business Rule on tables you want to audit
3. Check "Update" checkbox only
4. Customize auditedFields array for your requirements
5. Consider data retention policies for audit records
6. Test thoroughly to ensure no performance impact
Related Scripts
Auto-assign Based on Category
Automatically assign tickets to the appropriate assignment group based on category.
Send Email Notifications
Send customized email notifications when specific conditions are met.
Populate Fields on Insert
Automatically populate fields with default values or calculated values when a record is created.