Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 4.0

The Audit Logging plugin can add simple Hibernate Events based Audit Logging to a Grails project and it can also add support to domain models for hooking into the hibernate events system in a fashion that is similar in semantics to a database trigger. Support for the following closures are added: onSave, onDelete, and onChange which each give access to before and after states of the object so you may write business logic to handle specific types of changes to the object.

The Audit Logging Plugin provides tracking of database data changes on a row and column level this is known as change audit logging and should not be confused with security audit logging or with profiling. The development of this plugin was inspired by the needs of DBAs to be able to reconstruct data level changes over time. It does not address security or security auditing. For more information on this type of logging, see Audit Log and Hibernate Audit Logging.

NOTE: GORM Events hooks 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. I have chosen to prefix the handler names with "on" so that they do not conflict with other handler names in other existing plugins.

Conceptually the "on" event handler occurs in the middle of the event, this is not technically possible since Hibernate exists above the database layer, we are mimicking the semantic behavior inside in this plugin. If you have designed a solution with the use of triggers but either need the trigger to be portable to other databases or do not have DBA resources this plugin is for you. 

It should be noted that any exceptions you throw from inside the triggers you write using this plugin will invalidate any session firing them. That means you should be careful to make as simple and easily debuggable triggers as possible using this plugin. You should in fact find ways to decouple the trigger from business logic as this is best practice no matter how you implement a trigger.

Installation

Code Block
$ grails install-plugin audit-logging

Usage

You can use the grails-audit-logging plugin in several ways. First, in a domain class...

Code Block
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. Additionally you may use the optional event handlers which I refer to as "triggers".

Examples:

Code Block
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]
			}
		})
	}//*/
}

Alternately you may choose to disable the audit logging and only use the triggers (event handlers). You would do this by specifying:

Code Block
static auditable = [handlersOnly:true]

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

As of version 0.3 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)
in Config.groovy add these lines:

Code Block
auditLog {
  actorKey = 'userPrincipal.name'
}

...or alternately...

Code Block
auditLog {
  actorKey = 'userPrincipal.id'
}

... if you prefer to log the user's id.

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

In Config.groovy

Code Block
auditLog {
  actorKey = 'session.username'
}

... or if your user is similar to the simple authentication user object in the tutorials...

in Config.groovy

Code Block
auditLog {
  actorKey = 'session.user.name'
}

... finally 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:

Code Block
import edu.yale.its.tp.cas.client.filter.CASFilter
auditLog {
  username = CASFilter.CAS_FILTER_USER
}

... and the audit_log table will have a record of which user and what controller triggered the hibernate event.

As of version 0.4 you may also specify columns to ignore...

Code Block
static auditable = [ignore:['version','lastUpdated','myField']]

You may use this in concert with the other configuration parameters like so...

Code Block
static auditable = [handlersOnly:true,ignore:['version','lastUpdated','myField']]

Changes to the fields 'version' and 'lastUpdated' will be ignored by default. If you wish to log these columns as well you may specify an ignore configuration that does not mention them. Like so...

Code Block
static auditable = [ignore:[]]

... which means log everything.

Known Issues

Use of the event handlers in objects that are serialized in a WebFlow context can cause the exception:

Code Block
builder.ClosureInvokingAction Exception occured invoking flow action: null

... mark the closure as a transient to avoid this...

Code Block
transient onChange = {
        // ... code ...
   }


Future Release Plan

User requested features include:

  • better debugging and trace from execeptions thrown from inside triggers
  • audit facade pattern option
  • audit object model generator
  • make master audit log optional
  • decouple the triggers from audit logging so triggers can be used independently
  • support for alternative audit log recording models

JIRA

JIRA Issues
columnstype;key;summary
urlhttp://jira.codehaus.org/sr/jira.issueviews:searchrequest-xml/temp/SearchRequest.xml?&pid=11450&component=13352&status=1&sorter/field=issuetype&sorter/order=ASC&tempMax=1000