Plugins You can find out about all the publicly available Grails plugins.

Audit Logging Plugin

26 votes

5% of Grails users

compile "org.grails.plugins:audit-logging:1.1.3"

 Documentation  Source  Issues


This is the Grails 1.x / 2.x plugin page. For the Grails 3.x version, see Grails 3 Plugin Portal
Automatically log change events for domain objects. The Audit Logging plugin additionally adds an instance hook to domain objects that allows you to hang Audit events off of them. The events include onSave, onChange, and onDelete. When called, the event handlers have access to oldObj and newObj definitions that will allow you to take action on what has changed.


Install as plugin dependency in BuildConfig.groovy (see above).

If you use Grails < 2.0, perform:

$ grails install-plugin audit-logging

AuditLogEvent Domain creation using audit-quickstart (since 1.1.0)

When installing plugin version 1.1.0 or above, you must perform the following command to let the plugin create the audit-logging domain class within your project.
grails audit-quickstart <> <YourAuditLogEventClassName>
grails audit-quickstart org.myaudit.example AuditLogEvent

If you used an older plugin version, set the mapping and constraint settings accordinghly. The created Domain artifact contains comments for the former config settings applied.

Advantage of the new approach is that you got full control of the Audit Domain Class.

Latest stable releases

  • 1.1.3 (Grails 2.1 or above, AuditLogEvent Domain by audit-quickstart, recommended version)
  • 1.0.5 (Grails 2.0 or above)
  • (Grails 1.3 or above)
  • 0.5.3 (Grails 1.2 or below)

audit_log database table creation

After installing the plugin, you need to create the audit_log database table. The table creation depends on your project settings. This can either be
  1. dbCreate setting in DataSource.groovy (create, create-drop, update)
  2. or by using the database-migration plugin
For details see the Grails documentation.


The Audit Logging plugin adds Grails GORM Events (Hibernate Events when using version < 1.0.0) based Audit Logging capabilities to a Grails project and it also adds support to domain models for hooking into the Grails GORM events system. Support for the following closures are added: onSave, onDelete, and onChange.

The onChange closure can be used in two ways. First, it can be used with no parameters or it can be used with two parameters, oldMap and newMap. The first parameter is a LinkedHashMap representing the old state of the object before the change was applied, the second parameter is a LinkedHashMap representing the state of the object after changes are applied.

NOTE: GORM Events hook into the ''beforeInsert'' and the ''beforeUpdate'' events which work great for preventing updates but do not work well for ''Audit Logging'' where we would need critical information about the entity that is only available after these actions complete. We've chosen to prefix the handler names with "on" so that they do not conflict with other handler names in other existing plugins.


Users of Grails 1.2.x and below should use version 0.5.3 of this plugin. Users of Grails 1.3.x and above should use version of this plugin. If you use Grails >= 2.3 we recommend to use 1.1.0 or above.

Starting with version 1.0.0, this plugin is ORM mapper agnostic, so you can use it with the ORM mapper of your choice (Hibernate3, Hibernate4, MongoDB, etc.).


You can use the grails-audit-logging plugin in several ways.

1. Auditing of domain class

class Person {
  static auditable = true

… }

Enables audit logging using the introduced domain class AuditLogEvent which will record insert, update, and delete events. Update events will be logged in detail with the property name and the old and new values.

2. Auditing plus domain event handlers

You may use the optional event handlers in your Domain classes.


class Person {
 static auditable = true
 Long id
 Long version

String firstName String middleName String lastName

String email

static constraints = { firstName(nullable:true,size:0..60) middleName(nullable:true,size:0..60) lastName(nullable:false,size:1..60) email(email:true) }

def onSave = { println "new person inserted" // may optionally refer to newState map } def onDelete = { println "person was deleted" // may optionally refer to oldState map } def onChange = { oldMap,newMap -> println "Person was changed ..." oldMap.each({ key, oldVal -> if(oldVal != newMap[key]) { println " * $key changed from $oldVal to " + newMap[key] } }) }//*/ }

3. Use event handlers only (no auditing)

You may choose to disable the audit logging and only use the event handlers. You would do this by specifying in your domain class:

static auditable = [handlersOnly:true]

With "handlersOnly:true" specified, no AuditLogEvents will be persisted to the database and only the event handlers will be called.


Auditing Current User Information

With version >= 0.5, additional configuration can be specified in the Config.groovy file of the project to help log the authenticated user for various security systems. For many security systems the defaults will work fine. To specify a property of the userPrincipal to be logged as the actor name (the person performing the action which triggered the event, e.g. the username) add these lines to Config.groovy:
auditLog {
  actorClosure = { request, session ->

Spring Security Core Plugin 1.1.2 or higher

If you save data from an unprotected URL (configAttribute:IS_AUTHENTICATED_ANONYMOUSLY), the principal is a String-object not a Principal-object. To cope with this behaviour you should use the following Closure definition in Config.groovy:

Import statement:

import org.codehaus.groovy.grails.plugins.springsecurity.SpringSecurityUtils
auditLog {
 actorClosure = { request, session ->
   if (request.applicationContext.springSecurityService.principal instanceof java.lang.String){
    return request.applicationContext.springSecurityService.principal
   def username = request.applicationContext.springSecurityService.principal?.username
   if (SpringSecurityUtils.isSwitched()){
    username = SpringSecurityUtils.switchedUserOriginalUsername+" AS "+username
   return username

Spring Security Core 1.0.1 Plugin

Based off of Jorge Aguilera's example, the Spring Security Plugin uses the SpringSecurityService.
auditLog {
  actorClosure = { request, session ->

Acegi Plugin

Thanks to Jorge Aguilera for his example on how to integrate with the Acegi plugin:
auditLog {
 actorClosure = { request, session ->
   return request.applicationContext.authenticateService.principal()?.username

CAS Authentication

For example if you are using a system such as CAS you can specify the CAS user attribute using a special configuration property to get the CAS user name. In Config.groovy just add the following lines to the top of the file:
auditLog { 
 actorClosure = { request, session ->
… and the audit_log table will have a record of which user and what controller triggered the event.

Shiro Plugin

With Shiro, add the following lines to use the currently logged in user's username:
auditLog {
 actorClosure = { request, session ->

Other security systems

If you are using a custom authentication system in your controller that puts the user data into the session you can set up the actorClosure to work with your security system instead.

Property Ignore List

It's possible to configure which properties get ignored by auditing. The default ignore field list is: ['version','lastUpdated']. If you want to provide your own ignore list specify the ignore list like this:
static auditable = [ignore:['version','lastUpdated','myField']]

If instead you want to trigger on version and lastUpdated changes you may specify an empty ignore list:

static auditable = [ignore:[]]

Whitelist properties to audit (since 1.1.3)

Since version 1.1.3, instead of blacklisting which attributes to ignore, you can also define a list of properties to audit (whitelist) per Domain class. The auditableProperties setting has precedence over ignore. Thanks to Paul Taylor for this feature.
static auditable = [auditableProperties: ['name', 'famous', 'lastUpdated']]

Verbose mode

You can enable verbose mode. If enabled, column by column change logging in insert and delete events is enabled. Old- and new values are stored in detailed to the audit logging table. Enable verbose logging with:
auditLog {
  verbose = true
This setting is disabled by default.

Note: When enabling verbose audit logging, you may get errors if you explicitly flush the session. In this case, do not enable verbose logging. Since version 1.0.1, additional closures are available to disable logging or verbose mode in a code block.

Logging of associated objectIds (since 0.5.5)

You can log the object-ids of associated objects. Logging will be performed in the format: "[id:<objId>]objDetails". You can enable id-logging with
auditLog {
  logIds = true

This setting is disabled by default.

Large value column mode (since 0.5.5)

You can enable large value columns to log more details. If large value columns are enabled, the column limit is 65534 for oldValue and newValue. This setting is especially designed to work with "verbose" mode. If you enabled the large value column mode, you can set TRUNCATE_LENGTH to a value larger 255 and smaller 65535. Enable large value columns in Config.groovy with:
auditLog {
  largeValueColumnTypes = true // use large column db types for oldValue/newValue.
Whenever you change the largeValueColumnTypes flag, you need to update your database schema(s).

Property value masking (since 0.5.5)

You can configure properties to mask on a per-Domain-Class base. If properties are defined as masked, their values are not stored into the audit log table if verbose mode is enabled. Instead, a mask of "**********" will be logged. By default, "password" properties are masked. You can mask property fields in domain classes like this:
static auditable = [mask:'password','otherField']

Verbose log truncation length

If you enabled verbose mode, you can configure the truncation length of detail information in the oldValue and newValue columns (Default is 255). Configure the TRUNCATE_LENGTH in Config.groovy:
auditLog {
  TRUNCATE_LENGTH = 400 // don't forget to enable largeValueColumnTypes if > 255!
  largeValueColumnTypes = true // use large column db types for oldValue/newValue.
When you set TRUNCATE_LENGTH to a value > 255 you must enable largeValueColumnTypes (see above). When you forgot to enable large value column mode while setting TRUNCATE_LENGTH > 255, a warning is logged during startup and the setting will be ignored (255 will be used instead).

Renaming the Audit-Log table name (since 0.5.5)

You can specify the audit log table name. Default is "audit_log". Change the table name in Config.groovy with:
auditLog {
  tablename = "other_audit_log_name"

If you change the tablename, you need to update your database schema(s).

Disable Hibernate caching of AuditLogEvent

You can disable the caching of the AuditLogEvents by specifying:
auditLog {
  cacheDisabled = true

Transactional AuditLog events

In Config.groovy you may specify whether the Audit Log uses transactions or not. If set to true then the logger will begin and commit transactions around audit log save events. If set to false then the AuditLog will be persisted without a transaction wrapping its call to save. This setting should not be changed from defaults lightly as it can cause problems in integration testing.
auditLog {
  transactional = true 

You are only likely to want to change the defaults if you are working with a transactional database in test and production.

Disable auditing by config (since

You can disable auditing by config. If you disable auditing, event handlers are still triggered but no changes are comitted to the audit log table. This can be used e.g. if you need to bootstrap many objects and want to programmatically disable auditing to not slow down the bootstrap process or if you want to audit log by Enviroment. With version >= 1.0.0 of the plugin, you can disable auditing on a per-datasource base as well Currently, disabling the plugin on a per-datasource base does not work. See GPAUDITLOGGING-68
auditLog {
  disabled = true 

Disabling in DataSource.groovy:

dataSource_foo {
    auditLog.disabled = true

This setting is "false" by default (auditing is enabled).

nonVerboseDelete logging (since 1.0.1)

If verbose logging is enabled (see above), you can log deletes in a non-verbose manner. This means, only the delete event is logged, but not the properties the deleted object hold prior the deletion.
auditLog {
  nonVerboseDelete = true 
This setting is "false" by default (verbosity of deletes depend on the verbose setting).

log full domain class name (since 1.0.3)

By default, only the entity class name is logged. If you want to log the entity full name (including the package name), you can enable full logging. Thanks to tcrossland for this feature.

logFullClassName = true
This setting is "false" by default (entity name is logged).

getAuditLogUri closure (since 1.0.4)

By default, the "uri" field is filled with the request uri which caused the action. You can define a closure "getAuditLogUri" on a per-domain object base to define what should be written to the AuditLog "uri" field.

class User {
  static auditable = true
  static belongsTo = [Client]

def getAuditLogUri = { clientId as String } }

You need to take special care how you obtain the "uri" data in the getAuditLogUri closure. It is recommended to not perform costly calls.

Domain class stamping support (since 1.0.4)

Since version 1.0.4, it is possible to enable domain class stamping support. With this feature enabled, all domain classes annotated with @Stamp or with field "static stampable = true" will get the fields dateCreated, lastUpdated, createdBy, lastUpdatedBy using an AST transformation. You can create your own StampASTTransformation implementation for your specific needs. The createdBy and lastUpdatedBy fieldnames can be declared in Config.groovy. These fields will be filled with the result of the actor closure on the event PreInsert, PreUpdate and PreDelete. Thanks to tkvw for this feature.

stampEnabled = true // enable stamping support
stampAlways = false // always stamp domain classes, regardless of @Stamp or static stampable = true existence
stampCreatedBy = 'createdBy' // fieldname
stampLastUpdatedBy = 'lastUpdatedBy' // fieldname

Use specific datasource (since 1.0.4)

Since version 1.0.4 it is possible to set the datasource name to use for the audit logging table.
useDatasource = 'second' // use "second" datasource defined in DataSource.groovy

Custom ID Mapping

Since version 1.0.4, it is possible to configure the id mapping for the AuditLogEvent domain.

idMapping = [generator:"uuid2", type:"string", length:36] // UUID id-type for AuditLogEvent

Ignoring certain events (since 1.0.5)

Since version 1.0.5, it is possible to ignore certain events on a per-domain base.

static auditable = [ignoreEvents:["onChange","onSave"]]

Example configuration

Example Config.groovy configuration with various settings as described above:
// AuditLog Plugin config
auditLog {
 verbose = true // verbosely log all changed values to db
 logIds = true  // log db-ids of associated objects.
 // Note: if you change next 2 properties, you must update your database schema!       
 tablename = 'my_audit' // table name for audit logs.     
 largeValueColumnTypes = true // use large column db types for oldValue/newValue.
 cacheDisabled = true
 logFullClassName = true
 replacementPatterns = ["":""] // replace with empty string.
 actorClosure = { request, session ->
    // SpringSecurity Core 1.1.2
    if (request.applicationContext.springSecurityService.principal instanceof java.lang.String){
       return request.applicationContext.springSecurityService.principal
    def username = request.applicationContext.springSecurityService.principal?.username
    if (SpringSecurityUtils.isSwitched()){
       username = SpringSecurityUtils.switchedUserOriginalUsername+" AS "+username
    return username
 stampEnabled = true
 stampAlways = true
 idMapping = [generator:"uuid2", type:"string", length:36]

AuditLogEvent Controller

The plugin provides a minimalistic Controller to list audit events. By default, it is mapped to uri /auditLogEvent

Version History

  • Grails <= 1.2
  • Grails >= 1.3
  • Added collections support
  • Added logIds config property
  • Possiblity to specify the auditLog tablename
  • Large auditlog "value" columns support
  • Property value masking support
  • Grails >= 1.3
  • Added disabled config property to disable audit logging by config
  • Grails 2.x
  • ORM agnostic implementation
  • Possibility to disable audit logging on a per-datasource base.
  • Grails 2.x
  • Propagate the object identifier to onSave() handlers
  • Added nonVerboseDelete config property
  • Grails 2.x
  • Fix GPAUDITLOGGING-63 (PersistedObjectVersion not logged in update events)
  • Fix GPAUDITLOGGING-56 (Home link does not point to home)
  • Fix GPAUDITLOGGING-66 (Pass exceptions to the caller in closures)
  • Grails 2.x
  • Fix GPAUDITLOGGING-64 (Duplicate log entries written per configured dataSource)
  • Fix GPAUDITLOGGING-63 (Support logging of full entity name - logFullClassName property)
  • Grails 2.x
  • Fix GPAUDITLOGGING-69 allow to set uri per domain object
  • Fix GPAUDITLOGGING-62 Add identifier in handler map
  • Fix GPAUDITLOGGING-29 support configurable id mapping for AuditLogEvent
  • Fix GPAUDITLOGGING-70 support configurable datasource name for AuditLogEvent
  • Fix GPAUDITLOGGING-74 Impossible to log values of zero or false
  • Fix GPAUDITLOGGING-75 Support automatic (audit) stamping support on entities
  • Grails 2.x
  • Migration of JIRA to GitHub Issues
  • Fix #92 (Support for ignoring certain Events)
  • auto id conversion in controller fix
  • fix back link to grailsHomeRoot (thanks to fcambarieri)
  • Starting with this release, the main branch for the 1.0.x series is 1.x_maintenance. Master branch is for Grails 3.0 support, now. Both branches will be tested by Travis-CI.
  • fix #91 Compile fails with mongoDB plugin
  • merge PR #96 Make identifiers available in the maps during onChange event
  • fix #99 Plugin not working with MongoDB as Only Database
  • fix #100 Id generation default for AuditLogEvent should align with GORM default
  • Removed grails-hibernate EventTriggeringInterceptor dependency from Plugin descriptor to be ORM agnostic.
  • Minimum Grails version raised to 2.1 due to Datastore limitations in applicationContext
  • Changed issue management url to GH.
  • fix #106 Enforce text type usage in largeColumValues mode
  • #13 Externalize AuditTrailEvent domain to user
  • #39 Refactor Plugin to generate AuditLogEvent Artifact
  • #93 Use MongoDB as datasource in a multiple-datasource configuration
  • #94 automatic type conversion does not work
  • #90 / GPAUDITLOGGING-80 Add support for enabling/disabling auto import of AuditLogEvent domain class in HQL queries
  • #89 / GPAUDITLOGGING-78 custom naming of id sequence generator
  • #126 Support Many-To-Many Associations (backport from master). Thanks to Andrey Zhuchkov
  • #133 preDelete is not Stampable (backport from master). Thanks to Dennis de Lange
  • #135 audit_trail table not created in MySQL for large columns (backport from master). Thanks to Sebastien Arbogast
  • #138 Respect auditable.ignore property list for insert and delete operations. Thanks to Paul Taylor
  • Small code improvements
  • #113 Whitelist properties instead of blacklist. Thanks to Paul Taylor

Continuous Integration Server

We are using CI server hosted at