7 Creating logs for services - Reference Documentation
Authors: Alejandro GarcĂa Granados
Version: 0.4
7 Creating logs for services
Auditing and logging is one of the most important things you must consider when building web applications. Grails injects thelog
object for you in every artifact (such as domain classes, controllers and services), but the Spring Aspect Oriented Programming approach tells you that it is not a clean way to manage the logging. We strongly recommend the use of Spring AOP for this task.Sometimes, it is difficult to configure AOP in Grails. There are a lot of blog entries suggesting you how to do it, but currently there isn't a standard approach. With this in mind, Optimus plugin lets you generate the corresponding AOP logs for every service method.You can achieve this by executing the create-logs command:
grails create-logs [domainClass]
mypackage.Person
. With the create-logs command, you will get the following log files:
src/groovy/mypackage/aop/PersonServiceList.groovy
src/groovy/mypackage/aop/PersonServiceCreate.groovy
src/groovy/mypackage/aop/PersonServiceUpdate.groovy
src/groovy/mypackage/aop/PersonServiceGet.groovy
src/groovy/mypackage/aop/PersonServiceDelete.groovy
File | Command |
---|---|
src/groovy/mypackage/aop/PersonServiceList.groovy | create-service-list-log |
src/groovy/mypackage/aop/PersonServiceCreate.groovy | create-service-create-log |
src/groovy/mypackage/aop/PersonServiceUpdate.groovy | create-service-update-log |
src/groovy/mypackage/aop/PersonServiceGet.groovy | create-service-get-log |
src/groovy/mypackage/aop/PersonServiceDelete.groovy | create-service-delete-log |
src/groovy/mypackage/aop/PersonServiceList.groovy
file, we will find something like this:
package mypackage.aopimport org.aspectj.lang.annotation.AfterReturning import org.aspectj.lang.annotation.AfterThrowing import org.aspectj.lang.annotation.Aspect import org.aspectj.lang.annotation.Before import org.aspectj.lang.annotation.Pointcutimport org.springframework.stereotype.Component@Component @Aspect class PersonServiceList { @Pointcut( value='execution(java.util.Map com.company.app.PersonService.list(..)) && bean(personService) && args(params)', argNames='params') public void list( Map params ) {} @Before('list(params)') void before( Map params ) { log.info( "Begins request: ${params}" ) } @AfterReturning( pointcut='list(java.util.Map)', returning='map') void afterReturning( Map map ) { log.info( "End of request: ${map}" ) } @AfterThrowing( pointcut='list(java.util.Map)', throwing='e' ) void afterThrowing( Exception e ) { log.info("Error in request: ${e.class.simpleName} - ${e.message}) }}
Component
. Tells Spring that this class should be considered as Spring bean. It is configured viagrails-app/conf/Config.groovy
in thegrails.spring.bean.packages
property (the plugin does it for you).Aspect
. Indicates that the class must be managed as an aspect.Pointcut
. Indicates the method to be logged.Before
. Indicates the method to be executed before the method indicated in thePointcut
annotation is invoked.AfterReturning
. Indicates the method to be executed after the method indicated in thePointcut
annotation returns a value.AfterThrowing
. Indicates the method to be executed if the method indicated in thePointcut
annotation throws an exception.
We strongly recommend you to read the Spring AOP documentation for a further explanation.When you run the application and execute some actions, the logs will appear in the output console and they will be written in the
log/activity
file:Listing items:
yyyy-MM-dd HH:mm:ss [thread] INFO aop.PersonServiceList - Begins request: [action:content, controller:person] yyyy-MM-dd HH:mm:ss [thread] INFO aop.PersonServiceList - End of request: [items:[], total:0]
yyyy-MM-dd HH:mm:ss [thread] INFO aop.PersonServiceCreate - Begins request: com.company.app.Person : (unsaved) yyyy-MM-dd HH:mm:ss [thread] INFO aop.PersonServiceCreate - End of request
yyyy-MM-dd HH:mm:ss [thread] INFO aop.PersonServiceGet - Begins request:1 yyyy-MM-dd HH:mm:ss [thread] INFO aop.PersonServiceGet - End of request: com.company.app.Person : 1
yyyy-MM-dd HH:mm:ss [thread] INFO aop.PersonServiceUpdate - Begins request: com.company.app.Person : 1 yyyy-MM-dd HH:mm:ss [thread] INFO aop.PersonServiceUpdate - End of request
yyyy-MM-dd HH:mm:ss [thread] INFO aop.PersonServiceDelete - Begins request:com.company.app.Person : 1 yyyy-MM-dd HH:mm:ss [thread] INFO aop.PersonServiceDelete - End of request
The default output is poor friendly (It uses the toString
default method). You can edit the log output according to your own needings.