### Example AuditLog Plugin Configuration Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/configuration.adoc A comprehensive example of how to configure various settings for the AuditLog plugin within the application.groovy file, including domain class name, verbose mode, excluded fields, and masking. ```groovy // AuditLog Plugin config grails { plugin { auditLog { auditDomainClassName = 'my.example.project.MyAuditTrail' verbose = false verboseEvents = [AuditEventType.UPDATE, AuditEventType.INSERT] failOnError = true excluded = ['version', 'lastUpdated', 'lastUpdatedBy'] mask = ['password'] logIds = true stampEnabled = true } } } ``` -------------------------------- ### Run Grails Application Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/examples/audit-test/README.md Start the Grails application to interact with Authors and AuditTrails entries. ```bash grails run-app ``` -------------------------------- ### Audit Logging Examples (INSERT, UPDATE, DELETE) Source: https://context7.com/grails-plugins/grails-audit-logging-plugin/llms.txt Demonstrates how audit logging works for INSERT, UPDATE, and DELETE operations on a domain class implementing the `Auditable` trait. Shows expected `AuditTrail` entries for each operation. ```groovy // --- Usage in a service or controller --- // INSERT: every auditable property gets one AuditTrail row with eventName='INSERT' Author.withNewTransaction { def author = new Author(name: 'Tolkien', age: 81, famous: true) author.save(flush: true, failOnError: true) } // Expected AuditTrail rows (one per auditable property): // { className:'test.Author', eventName:'INSERT', propertyName:'name', oldValue:null, newValue:'Tolkien', actor:'SYS' } // { className:'test.Author', eventName:'INSERT', propertyName:'age', oldValue:null, newValue:'81', actor:'SYS' } // { className:'test.Author', eventName:'INSERT', propertyName:'famous', oldValue:null, newValue:'true', actor:'SYS' } // { className:'test.Author', eventName:'INSERT', propertyName:'ssn', oldValue:null, newValue:'**********', actor:'SYS' } // UPDATE: only the changed property is logged Author.withNewTransaction { def author = Author.findByName('Tolkien') author.age = 85 } // Expected: // { eventName:'UPDATE', propertyName:'age', oldValue:'81', newValue:'85' } // DELETE: all auditable property values at deletion time are logged with eventName='DELETE' Author.withNewTransaction { Author.findByName('Tolkien').delete(flush: true) } // Expected (one row per property, oldValue=value, newValue=null): // { eventName:'DELETE', propertyName:'name', oldValue:'Tolkien', newValue:null } ``` -------------------------------- ### Generate Audit Log Domain Class Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/README.md Use this command after installing version 2.0.x or later of the plugin to create a customizable audit log domain class. The domain class name is configured in application.groovy. ```groovy grails audit-quickstart org.example.myproject MyAuditLogEvent ``` -------------------------------- ### Implement Auditable Trait in Domain Class Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/installation.adoc Implement the Auditable trait in any domain class you wish to audit. This example shows a basic implementation. ```groovy import grails.plugins.orm.auditable.Auditable class MyDomain implements Auditable { String whatever ... } ``` -------------------------------- ### Enable Auditing in Domain Class (3.0.x+) Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/upgrading.adoc Implement the Auditable trait in your domain class to enable default audit logging behavior starting from version 3.0.0. ```groovy import grails.plugins.orm.auditable.Auditable class MyDomain implements Auditable { .. } ``` -------------------------------- ### Acegi Plugin Audit Resolver Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/usage.adoc Extend DefaultAuditRequestResolver to integrate with the Acegi security plugin. This resolver uses the authenticateService to get the principal's username. ```groovy /** * @author Jorge Aguilera */ class AcegiAuditResolver extends DefaultAuditRequestResolver { def authenticateService @Override String getCurrentActor() { authenticateService?.principal()?.username ?: super.getCurrentActor() } } ``` -------------------------------- ### Shiro Plugin Audit Resolver Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/usage.adoc Extend DefaultAuditRequestResolver to integrate with the Shiro security plugin. This resolver uses Shiro's SecurityUtils to get the current subject's principal. ```groovy @Component('auditRequestResolver') class ShiroAuditResolver extends DefaultAuditRequestResolver { @Override String getCurrentActor() { org.apache.shiro.SecurityUtils.getSubject()?.getPrincipal() } } ``` -------------------------------- ### Extend Auditable Trait for Custom Behavior Source: https://context7.com/grails-plugins/grails-audit-logging-plugin/llms.txt Extend the Auditable trait to share custom behavior across multiple domain classes. This example shows custom value serialization and attaching a tenant ID. ```groovy import grails.plugins.orm.auditable.Auditable trait EnterpriseAuditable extends Auditable { // Custom value serialization applied to all domains using this trait @Override String convertLoggedPropertyToString(String propertyName, Object value) { if (value instanceof java.util.Currency) { return value.currencyCode } if (value instanceof java.net.URL) { return value.toExternalForm() } super.convertLoggedPropertyToString(propertyName, value) } // Attach a tenant ID to every audit entry (requires custom AuditTrail field) @Override boolean beforeSaveLog(Object auditEntry) { auditEntry.tenantId = TenantContext.current?.id true } } // Apply to domain classes: class Invoice implements EnterpriseAuditable { String invoiceNumber BigDecimal amount java.util.Currency currency } class Contract implements EnterpriseAuditable { String title java.net.URL documentUrl } ``` -------------------------------- ### Generate Audit Domain Class Source: https://context7.com/grails-plugins/grails-audit-logging-plugin/llms.txt Run this command to generate the audit domain class and register it in `application.groovy`. ```bash # Generate the audit domain class and register it in application.groovy grails audit-quickstart org.example.myproject AuditTrail # Adds to application.groovy: # grails.plugin.auditLog.auditDomainClassName = 'org.example.myproject.AuditTrail' ``` -------------------------------- ### Run Grails Tests Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/examples/audit-test/README.md Execute the integration tests for the audit logging plugin using the provided command. ```bash grails test-app ``` -------------------------------- ### Whitelist Properties for Audit Logging with AuditLogContext.withConfig Source: https://context7.com/grails-plugins/grails-audit-logging-plugin/llms.txt Utilize AuditLogContext.withConfig(included: [...]) to specify a whitelist of properties to be logged for a given block. Properties not in the list will be skipped, reducing log noise. ```groovy // Whitelist: only log the specified properties for this block Author.withNewTransaction { AuditLogContext.withConfig(included: ['name', 'age']) { def author = new Author(name: 'Lewis', age: 58, famous: true, ssn: '999-00-1234') author.save(flush: true, failOnError: true) } } // Only 'name' and 'age' AuditTrail rows are created; 'famous' and 'ssn' are skipped ``` -------------------------------- ### Legacy Domain Class Auditing (Pre-3.0.0) Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/upgrading.adoc Demonstrates the legacy static property syntax used for enabling and whitelisting properties for audit logging in versions prior to 3.0.0. ```groovy // Legacy enable/disable static auditable = true // Legacy whitelist static auditable = [auditableProperties: ['name', 'famous', 'lastUpdated']] ``` -------------------------------- ### Configure Verbose Logging for Specific Events with AuditLogContext.withConfig Source: https://context7.com/grails-plugins/grails-audit-logging-plugin/llms.txt Set AuditLogContext.withConfig(verbose: false, verboseEvents: [...]) to enable verbose (per-property) logging only for specified event types. Other events will receive standard single-row logging. ```groovy // Verbose logging for only UPDATE events globally // (in application.groovy — but can also be mimicked at runtime) AuditLogContext.withConfig(verbose: false, verboseEvents: [AuditEventType.UPDATE]) { // Only UPDATE operations will produce per-property rows; INSERT/DELETE get one row } ``` -------------------------------- ### Enable Logging of Full Class Name Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/configuration.adoc Configure the plugin to log the full entity class name, including the package name, instead of just the entity class name. This setting is true by default. ```groovy grails.plugin.auditLog.logFullClassName = true ``` -------------------------------- ### Enable Verbose Logging Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/configuration.adoc Enable per-property logging for all operations. This is the default behavior. ```groovy grails.plugin.auditLog.verbose = true ``` -------------------------------- ### Retrieve Domain Changes in Controller Source: https://github.com/grails-plugins/grails-audit-logging-plugin/wiki/Dynmic-Finder Use this controller code to fetch a domain instance and its associated changes from the audit log. Replace 'YourDomain' with your actual domain class name. ```groovy def show = { def domainInst = YourDomain.get(params.id) def domainChanges = domainInst.getChanges() return [domainInst: domainInst, domainChanges:domainChanges] } ``` -------------------------------- ### Enable Full Class Name Logging with AuditLogContext.withConfig Source: https://context7.com/grails-plugins/grails-audit-logging-plugin/llms.txt Control whether the full class name is logged using AuditLogContext.withConfig(logFullClassName: ...). Setting it to false logs only the simple class name, which can be useful for brevity. ```groovy // Full-class-name logging with a per-call override AuditLogContext.withConfig(logFullClassName: false) { // AuditTrail.className will be 'Author' instead of 'com.example.Author' new Author(name: 'Short', age: 10).save() } ``` -------------------------------- ### Add Dependency to build.gradle Source: https://context7.com/grails-plugins/grails-audit-logging-plugin/llms.txt Add this dependency to your `build.gradle` file to include the audit logging plugin. ```groovy // build.gradle dependencies { compile 'org.grails.plugins:audit-logging:6.0.1' } ``` -------------------------------- ### Generate Audit Domain Artifact Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/installation.adoc Use this command to create the audit domain class and register it in application.groovy. Replace and with your specific values. ```bash grails audit-quickstart ``` -------------------------------- ### Enable Verbose Logging for Specific Events Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/configuration.adoc Configure verbose logging for particular event types like UPDATE. If `verbose` is also true, it takes precedence. ```groovy grails.plugin.auditLog.verboseEvents = [AuditEventType.UPDATE] ``` -------------------------------- ### Add Audit Logging Plugin Dependency Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/installation.adoc Add this dependency to your build.gradle file to include the audit-logging plugin. Replace {VERSION} with the desired plugin version. ```groovy dependencies { compile 'org.grails.plugins:audit-logging:{VERSION}' } ``` -------------------------------- ### Implement Auditable Trait for Basic Auditing Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/usage.adoc To enable default auditing for a domain, simply implement the Auditable trait. This uses default configurations merged with plugin defaults. ```groovy class Author implements Auditable { String name Integer age static hasMany = [books: Book] } ``` -------------------------------- ### Refresh Gradle Dependencies Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/installation.adoc Run this command in your project to refresh Gradle dependencies after adding the plugin. ```gradle gradle classes ``` -------------------------------- ### Blacklist Properties for Audit Logging with AuditLogContext.withConfig Source: https://context7.com/grails-plugins/grails-audit-logging-plugin/llms.txt Use AuditLogContext.withConfig(excluded: [...]) to specify a blacklist of properties to be excluded from audit logging for a specific block. This is useful for sensitive or irrelevant fields. ```groovy // Blacklist: suppress specific properties for this block Author.withNewTransaction { AuditLogContext.withConfig(excluded: ['ssn', 'famous']) { def author = Author.findByName('Lewis') author.age = 60 author.save() } } ``` -------------------------------- ### Define getChanges Method in Domain Class Source: https://github.com/grails-plugins/grails-audit-logging-plugin/wiki/Dynmic-Finder Add this method to your domain class to retrieve all audit log events associated with an instance. Ensure 'AuditLogEvent' is imported. ```groovy List getChanges() { AuditLogEvent.findAllByClassNameAndPersistedObjectId( this.getClass().getName(), this.id) } ``` -------------------------------- ### Implement Custom AuditRequestResolver Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/usage.adoc Implement this interface to provide custom logic for resolving the current actor and request URI for audit logs. Register your implementation as a bean in resources.groovy. ```groovy interface AuditRequestResolver { /** * @return the current actor */ String getCurrentActor() /** * @return the current request URI or null if no active request */ String getCurrentURI() } ``` ```groovy beans = { auditRequestResolver(CustomAuditResolver) { customService = ref('customService') } } ``` -------------------------------- ### Implement Custom AuditRequestResolver for Apache Shiro Source: https://context7.com/grails-plugins/grails-audit-logging-plugin/llms.txt Extend `DefaultAuditRequestResolver` to integrate Apache Shiro for user principal resolution. Ensure Shiro is configured in your application. ```groovy // grails-app/conf/spring/resources.groovy import grails.plugins.orm.auditable.resolvers.DefaultAuditRequestResolver import org.apache.shiro.SecurityUtils import edu.yale.its.tp.cas.client.filter.CASFilter import org.grails.web.servlet.mvc.GrailsWebRequest // --- Option A: Spring Security (registered automatically if springSecurityService bean exists) --- // The SpringSecurityRequestResolver is auto-registered — no manual wiring needed. // --- Option B: Apache Shiro --- @groovy.transform.CompileStatic class ShiroAuditResolver extends DefaultAuditRequestResolver { @Override String getCurrentActor() { SecurityUtils.getSubject()?.getPrincipal() ?: super.getCurrentActor() } } // --- Option C: CAS Authentication --- class CASAuditResolver extends DefaultAuditRequestResolver { @Override String getCurrentActor() { GrailsWebRequest request = GrailsWebRequest.lookup() request?.session?.getAttribute(CASFilter.CAS_FILTER_USER) ?: super.getCurrentActor() } } // --- Option D: Fully custom resolver --- class ApiKeyAuditResolver implements grails.plugins.orm.auditable.resolvers.AuditRequestResolver { ApiKeyService apiKeyService // injected @Override String getCurrentActor() { apiKeyService?.currentClientId ?: 'SYSTEM' } @Override String getCurrentURI() { GrailsWebRequest.lookup()?.request?.requestURI } } // Register in resources.groovy: beans = { auditRequestResolver(ApiKeyAuditResolver) { apiKeyService = ref('apiKeyService') } } ``` -------------------------------- ### Implement Auditable and Stampable Traits Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/installation.adoc Implement both Auditable and Stampable traits if you need to enable stamping for your domain class. Ensure Auditable is also implemented. ```groovy import grails.plugins.orm.auditable.Auditable class MyDomain implements Auditable, Stampable { String whatever ... } ``` -------------------------------- ### Intercept Audit Entries with `beforeSaveLog` Source: https://context7.com/grails-plugins/grails-audit-logging-plugin/llms.txt Override the `beforeSaveLog` method to intercept and potentially modify or veto individual audit log entries before they are persisted. Returning `false` from this method will suppress the logging of a specific audit entry. ```groovy import grails.plugins.orm.auditable.Auditable class SensitiveDocument implements Auditable { String title String classification String naturalKey @Override boolean beforeSaveLog(Object auditEntry) { // Attach a business key to every audit record (custom field on AuditTrail) auditEntry.naturalKey = naturalKey // Veto logging for 'classification' changes by returning false if (auditEntry.propertyName == 'classification') { return false } true } } ``` -------------------------------- ### Disable Audit Logging with Convenience Methods Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/usage.adoc Convenience methods are available on AuditLogContext to quickly disable verbose logging or all logging. ```groovy AuditLogContext.withoutVerboseAuditLog { ... } ``` ```groovy AuditLogContext.withoutAuditLog { ... } ``` -------------------------------- ### Default Audit Request Resolver Implementation Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/usage.adoc The plugin provides a default implementation for resolving audit request context. Applications can override this bean if needed. ```groovy class DefaultAuditRequestResolver implements AuditRequestResolver { ... } ``` -------------------------------- ### Log Associated Object IDs Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/configuration.adoc Enable logging of object-ids for associated objects. This setting is enabled by default. ```groovy grails.plugin.auditLog.logIds = true ``` -------------------------------- ### Configure Verbose Log Truncation Length Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/configuration.adoc Set the maximum length for detail information logged in the oldValue and newValue columns when verbose mode is enabled. The default is 255 characters. ```groovy truncateLength = 400 ``` -------------------------------- ### Configure Audit Logging Plugin in application.groovy Source: https://context7.com/grails-plugins/grails-audit-logging-plugin/llms.txt Tune the behavior of the audit logging plugin by setting various properties within the `grails.plugin.auditLog` namespace. This includes enabling verbose logging, excluding properties, and setting default values. ```groovy // grails-app/conf/application.groovy import grails.plugins.orm.auditable.AuditEventType grails { plugin { auditLog { // REQUIRED: set by 'grails audit-quickstart' auditDomainClassName = 'org.example.myproject.AuditTrail' // Verbose mode: one AuditTrail row per changed property (default: true) verbose = true // Or restrict verbose logging to specific event types only: // verboseEvents = [AuditEventType.UPDATE, AuditEventType.INSERT] // Event types to never log (globally) // ignoreEvents = [AuditEventType.INSERT] // Throw on audit save failure (default: false — silently skips) failOnError = true // Log full package-qualified class name (default: true) logFullClassName = true // Log associated object IDs (default: true) logIds = true // Properties always excluded from logging excluded = ['version', 'lastUpdated', 'lastUpdatedBy'] // Global property whitelist (null = all non-excluded properties) // included = ['name', 'status'] // Properties whose values are replaced with the mask string mask = ['password', 'ssn', 'creditCardNumber'] propertyMask = '**********' // Truncate old/new values to this length (default: maxSize constraint) truncateLength = 1000 // Default actor when no user context is available defaultActor = 'SYS' // Enable Stampable support (default: true) stampEnabled = true // Use getPersistentValue() for old values (default: true) usePersistentDirtyPropertyValues = true } } } ``` -------------------------------- ### Inject Stampable Trait into All Domains Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/stamping.adoc Implement TraitInjector to automatically apply the Stampable trait to all domain objects. Ensure the Stampable trait is available in the scope. ```groovy @CompileStatic class StampableTraitInjector implements TraitInjector { @Override Class getTrait() { Stampable } @Override String[] getArtefactTypes() { ['Domain'] as String[] } } ``` -------------------------------- ### Ignore Specific Event Types with AuditLogContext.withConfig Source: https://context7.com/grails-plugins/grails-audit-logging-plugin/llms.txt Configure AuditLogContext.withConfig(ignoreEvents: [...]) to prevent specific event types (e.g., DELETE) from being logged within a closure. This allows fine-grained control over which operations generate audit trails. ```groovy // Ignore specific event types for this block AuditLogContext.withConfig(ignoreEvents: [AuditEventType.DELETE]) { Author.withNewTransaction { Author.findByName('Lewis').delete(flush: true) } } // No AuditTrail rows created for this delete ``` -------------------------------- ### Disable Verbose Audit Logging with AuditLogContext.withoutVerboseAuditLog Source: https://context7.com/grails-plugins/grails-audit-logging-plugin/llms.txt Employ AuditLogContext.withoutVerboseAuditLog to disable only per-property logging while still retaining a single event row for the operation. This offers a balance between detail and performance. ```groovy // Disable only verbose (per-property) logging; still logs a single event row AuditLogContext.withoutVerboseAuditLog { Author.withNewTransaction { Author.findByName('Tolkien').tap { age = 90 }.save() } } ``` -------------------------------- ### Query Audit Events with GORM Finders Source: https://context7.com/grails-plugins/grails-audit-logging-plugin/llms.txt Use standard GORM finders on the AuditTrail domain class to retrieve audit history. You can filter by class name, object ID, event name, and property name. ```groovy // Find all audit events for a specific domain class def authorEvents = AuditTrail.findAllByClassName('org.example.Author') // Find changes for a specific object instance def id = author.id.toString() def objectHistory = AuditTrail.findAllByClassNameAndPersistedObjectId( 'org.example.Author', id, [sort: 'dateCreated', order: 'desc'] ) // Find only UPDATE events for a specific property def nameChanges = AuditTrail.withCriteria { eq('className', 'org.example.Author') eq('eventName', 'UPDATE') eq('propertyName', 'name') order('dateCreated', 'desc') } // Use built-in namedQuery for full-text search across actor/values/ids def results = AuditTrail.forQuery('Tolkien').forDateCreated(new Date() - 30).list() // Convenience helper on the domain class itself (add to your domain): class Author implements Auditable { String name // ... List getAuditHistory() { AuditTrail.findAllByClassNameAndPersistedObjectId( this.class.name, this.id?.toString(), [sort: 'dateCreated', order: 'asc'] ) } } // In a controller: def history = Author.get(params.id).auditHistory // history = [ // AuditTrail(eventName:'INSERT', propertyName:'name', oldValue:null, newValue:'Tolkien'), // AuditTrail(eventName:'UPDATE', propertyName:'age', oldValue:'81', newValue:'85'), // AuditTrail(eventName:'DELETE', propertyName:'name', oldValue:'Tolkien', newValue:null), // ] ``` -------------------------------- ### Configure Included Properties in Domain Class (3.0.x+) Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/upgrading.adoc Override the getLogIncluded() method on the Auditable trait to specify which properties should be included in audit logs. ```groovy @Override Collection getLogIncluded() { ['name', 'famous', 'lastUpdated'] } ``` -------------------------------- ### Grails Callback for Audit Logging (3.0.x+) Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/upgrading.adoc Utilize Grails' beforeInsert callback method to perform custom actions based on auditable property changes, replacing the removed handler callbacks. ```groovy def beforeInsert() { def dirtyAudit = getAuditableDirtyPropertyNames() // Do something special if certain properties are dirty, etc. } ``` -------------------------------- ### Enable/Disable Stamping Configuration Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/stamping.adoc Configure the audit logging plugin to enable or disable the stamping feature globally. Disabling stamping may cause validation failures if Stampable entities are still in use. ```groovy // Enable or disable stamping grails.plugin.auditLog.stampEnabled = true ``` -------------------------------- ### Implement Stampable Trait for Automatic Stamping Source: https://context7.com/grails-plugins/grails-audit-logging-plugin/llms.txt Implement the Stampable trait in your domain classes to automatically populate created/updated timestamps and user information on save operations. Ensure the AuditRequestResolver is configured to provide user details. ```groovy import grails.plugins.orm.auditable.Stampable class Train implements Stampable { String number static constraints = { number blank: false } } // --- Usage --- Train.withNewTransaction { def train = new Train(number: '42') train.save(flush: true, failOnError: true) assert train.createdBy == 'SYS' // resolved from AuditRequestResolver assert train.lastUpdatedBy == 'SYS' assert train.dateCreated != null assert train.lastUpdated != null } // After updating: Train.withNewTransaction { def train = Train.findByNumber('42') train.number = '99' train.save(flush: true) assert train.dateCreated != train.lastUpdated // timestamps differ after update } ``` -------------------------------- ### Set Constraints for Large Log Values Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/configuration.adoc When setting truncateLength to a value greater than 255, ensure the oldValue and newValue fields in your AuditLog domain class are large enough by setting appropriate maxSize constraints. This is crucial for preventing truncation warnings and ensuring partial information is logged. ```groovy static constraints = { // For large column support (as in < 1.0.6 plugin versions) oldValue(nullable: true, maxSize: 65534) newValue(nullable: true, maxSize: 65534) } ``` -------------------------------- ### Apply Stampable to All Domain Classes with TraitInjector Source: https://context7.com/grails-plugins/grails-audit-logging-plugin/llms.txt Use a Grails TraitInjector to automatically apply the Stampable trait to every domain class. This adds dateCreated, lastUpdated, createdBy, and lastUpdatedBy fields without modifying each class individually. ```groovy import grails.compiler.traits.TraitInjector import grails.plugins.orm.auditable.Stampable import groovy.transform.CompileStatic @CompileStatic class StampableTraitInjector implements TraitInjector { @Override Class getTrait() { Stampable } @Override String[] getArtefactTypes() { ['Domain'] as String[] } } // Register as a Spring bean in resources.groovy: // beans = { stampableTraitInjector(StampableTraitInjector) } // Now every domain class automatically has: dateCreated, lastUpdated, createdBy, lastUpdatedBy ``` -------------------------------- ### Masking Domain Class Properties Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/configuration.adoc Define which properties in a domain class should be masked in the audit logs when verbose mode is enabled. Values for these properties will be replaced with '**********'. ```groovy @Override Collection getLogMask() { ['password', 'otherField'] } ``` -------------------------------- ### AuditTrail Domain Class Definition Source: https://context7.com/grails-plugins/grails-audit-logging-plugin/llms.txt This is the generated `AuditTrail` domain class that stores audit log information. It includes fields for actor, URI, class name, event type, and changes to properties. ```groovy // grails-app/domain/org/example/myproject/AuditTrail.groovy (generated) class AuditTrail implements Serializable { String id Date dateCreated Date lastUpdated String actor // who made the change String uri // request URI at the time of the change String className // fully-qualified domain class name String persistedObjectId Long persistedObjectVersion String eventName // INSERT | UPDATE | DELETE String propertyName // which property changed String oldValue String newValue static constraints = { actor(nullable: true) uri(nullable: true) oldValue(nullable: true) newValue(maxSize: 10000, nullable: true) } static mapping = { table 'audit_log' id generator: 'uuid2', type: 'string', length: 36 version false } } ``` -------------------------------- ### Override Audit Log Configuration with AuditLogContext Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/usage.adoc Use AuditLogContext to override configuration parameters for a specific block of code. This is useful for disabling logging for bulk operations or system tasks. ```groovy AuditLogContext.withConfig(verbose: true, logFullClassName: true, excluded: ['ssn']) { ... } ``` ```groovy AuditLogContext.withConfig(verbose: false) { ... } ``` ```groovy AuditLogContext.withConfig(disabled: true) { ... } ``` -------------------------------- ### Ignore Specific Events in Domain Class Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/configuration.adoc Override the getLogIgnoreEvents() method in a domain class to ignore specific audit event types for that particular class. ```groovy @Override Collection getLogIgnoreEvents() { [AuditEventType.INSERT] } ``` -------------------------------- ### Disable All Audit Logging with AuditLogContext.withoutAuditLog Source: https://context7.com/grails-plugins/grails-audit-logging-plugin/llms.txt Use AuditLogContext.withoutAuditLog to temporarily disable all audit logging within a closure. This is useful for bulk operations where audit trails are not required, preventing unnecessary AuditTrail rows. ```groovy import grails.plugins.orm.auditable.AuditLogContext import grails.plugins.orm.auditable.AuditEventType // Disable all audit logging for a bulk import (no AuditTrail rows created) AuditLogContext.withoutAuditLog { Author.withNewTransaction { csvRows.each { new Author(name: row.name, age: row.age).save() } } } ``` -------------------------------- ### Custom Value Serialization with `convertLoggedPropertyToString` Source: https://context7.com/grails-plugins/grails-audit-logging-plugin/llms.txt Override the `convertLoggedPropertyToString` method on the `Auditable` trait to define custom serialization logic for property values. This is useful for complex types like `Money` or custom enums, ensuring they are logged in a human-readable format. ```groovy import grails.plugins.orm.auditable.Auditable class Contract implements Auditable { Money value // custom value type StatusEnum status // Default behavior already handles: Enum → name(), GormEntity → "[id:]toString", // Collection (with logIds=true) → comma-joined, null → null. // Override to add custom serialization: @Override String convertLoggedPropertyToString(String propertyName, Object value) { if (propertyName == 'value' && value instanceof Money) { return "${value.amount} ${value.currency}" // e.g. "1500.00 USD" } super.convertLoggedPropertyToString(propertyName, value) } } // AuditTrail row after update: // { propertyName:'value', oldValue:'1000.00 USD', newValue:'1500.00 USD' } ``` -------------------------------- ### Ignore Specific Events within a Context Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/configuration.adoc Temporarily ignore specific audit event types for a particular block of code by using the AuditLogContext.withConfig method. ```groovy AuditLogContext.withConfig(ignoreEvents = [AuditEventType.INSERT]) { // // Anything here will only log UPDATE and DELETE events // } ``` -------------------------------- ### Ignore Specific Events Globally Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/configuration.adoc Globally ignore specific audit event types by listing them in the grails.plugin.auditLog.ignoreEvents configuration property. ```groovy grails.plugin.auditLog.ignoreEvents = [AuditEventType.INSERT] ``` -------------------------------- ### CAS Authentication Audit Resolver Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/usage.adoc Extend DefaultAuditRequestResolver for CAS authentication. This resolver retrieves the username from the session attribute set by the CASFilter. ```groovy import edu.yale.its.tp.cas.client.filter.CASFilter class CASAuditResolver extends DefaultAuditRequestResolver { def authenticateService @Override String getCurrentActor() { GrailsWebRequest request = GrailsWebRequest.lookup() request?.session?.getAttribute(CASFilter.CAS_FILTER_USER) } } ``` -------------------------------- ### Disable All Auditing Globally Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/configuration.adoc Globally disable the audit logging feature by setting this property to true in your configuration. Event handlers will still be triggered, but no changes will be committed to the audit log table. This is useful for performance during bulk operations or conditional auditing. ```groovy grails.plugin.auditLog.disabled = true ``` -------------------------------- ### Customize Auditing with `Auditable` Trait Overrides Source: https://context7.com/grails-plugins/grails-audit-logging-plugin/llms.txt Override methods on the `Auditable` trait within a domain class to customize auditing behavior for that specific entity. This allows for conditional auditing, custom entity IDs, property blacklisting/whitelisting, masking sensitive fields, and ignoring specific event types. ```groovy import grails.plugins.orm.auditable.Auditable import grails.plugins.orm.auditable.AuditEventType class Publisher implements Auditable { String code String name boolean active = false // 1. Conditional auditing: only audit when active == true @Override boolean isAuditable(AuditEventType eventType) { active } // 2. Custom entity ID logged as "ABC123|Random House" instead of the numeric DB id @Override String getLogEntityId() { "${code}|${name}" } // 3. Per-entity property blacklist @Override Collection getLogExcluded() { ['active', 'version'] } // 4. Per-entity property whitelist (overrides excluded) // @Override // Collection getLogIncluded() { ['code', 'name'] } // 5. Mask sensitive fields on this entity @Override Collection getLogMask() { ['internalCode'] } // 6. Ignore specific event types on this entity @Override Collection getLogIgnoreEvents() { [AuditEventType.INSERT] // never log initial creation for this entity } static constraints = { code blank: false } } // Active publisher → changes are audited; persistedObjectId uses custom format Publisher.withNewTransaction { def pub = new Publisher(code: 'PH001', name: 'Penguin', active: true) pub.save(flush: true, failOnError: true) pub.name = 'Penguin Random House' pub.save() } // AuditTrail: { persistedObjectId:'PH001|Penguin Random House', eventName:'UPDATE', // propertyName:'name', oldValue:'Penguin', newValue:'Penguin Random House' } // Inactive publisher → no audit rows created at all Publisher.withNewTransaction { new Publisher(code: 'PH002', name: 'Dormant Press', active: false).save() } // AuditTrail count for 'test.Publisher' where code='PH002': 0 ``` -------------------------------- ### Override Auditable Trait for Per-Entity Auditing Control Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/usage.adoc Override methods of the Auditable trait within a domain to control auditing on a per-entity basis. This allows fine-grained control over which operations are logged. ```groovy @Override boolean isAuditable() { this.status == ACTIVE } ``` ```groovy @Override Collection getLogExcluded() { ['myField', 'version'] } ``` ```groovy @Override Collection getLogIncluded() { ['whiteListField1', 'whiteListField2'] } ``` ```groovy @Override String getLogEntityId() { "${name}:${age}" } ``` -------------------------------- ### Stampable Trait Definition Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/stamping.adoc Defines the Stampable trait which adds dateCreated, lastUpdated, createdBy, and lastUpdatedBy attributes to domain objects. ```groovy trait Stampable extends GormEntity { Date dateCreated Date lastUpdated String createdBy String lastUpdatedBy } ``` -------------------------------- ### Extend Auditable Trait for Custom Auditing Behavior Source: https://github.com/grails-plugins/grails-audit-logging-plugin/blob/6.0.x/plugin/src/docs/usage.adoc Extend the Auditable trait to completely override default auditing behavior, such as customizing property conversion or populating custom attributes on the audit log entity. ```groovy trait MyAuditable extends Auditable { // Customize formatting behavior for new and old values @Override String convertLoggedPropertyToString(String propertyName, Object value) { if (value instanceof MySpecialThing) { return ((MySpecialThing)value).formatAsString() } super.convertLoggedPropertyToString(propertyName, value) } // Customize to populate custom attributes on the audit log entity @Override boolean beforeSaveLog(Object auditEntity) { auditEntity.naturalKey = getNaturalKey() } } ``` -------------------------------- ### AuditEventType Enum Values Source: https://context7.com/grails-plugins/grails-audit-logging-plugin/llms.txt The AuditEventType enum identifies GORM lifecycle events and is used in configuration and trait overrides. It has three values: INSERT, UPDATE, and DELETE. ```groovy import grails.plugins.orm.auditable.AuditEventType // Three values: AuditEventType.INSERT // GORM PostInsert AuditEventType.UPDATE // GORM PreUpdate AuditEventType.DELETE // GORM PreDelete // Usage in domain override — skip INSERT events entirely for this entity class ReadOnlyArchive implements Auditable { String content @Override Collection getLogIgnoreEvents() { [AuditEventType.INSERT] } } // Usage in AuditLogContext AuditLogContext.withConfig(verboseEvents: [AuditEventType.UPDATE]) { // Only UPDATE events produce per-property rows // INSERT and DELETE events produce a single summary row archive.content = 'revised content' archive.save() } // Usage in global config grails.plugin.auditLog.ignoreEvents = [AuditEventType.DELETE] ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.