What are your favorite Grails debugging tricks? [closed]
Solution 1:
Some general tips:
- Clear stacktrace.log, do grails run-app, then open stacktrace.log in a viewer (I prefer
less stacktrace.log
on linux)... once in your viewer, search for .groovy and .gsp... that generally brings you to what you actually care about.
- When a stacktrace refers to a line number in a GSP file, you should open that view in a browser with
?showSource
in the query string, i.e.http://localhost:8080/myProject/myController/myAction?showSource
... this shows the compiled GSP source, and all GSP line numbers in the stacktrace refer to the compiled GSP, not the actual GSP source
- Always, always, always surround your saves with at least some minimal error handling.
Example:
try {
if(!someDomainObject.save()) {
throw new Exception ("Save failed")
}
} catch(Exception e) {
println e.toString()
// This will at least tell you what is wrong with
// the instance you are trying to save
someDomainObject.errors.allErrors.each {error ->
println error.toString()
}
}
Beyond that, a lot of it just comes down to recognizing stacktraces and error messages... a lot of the time, Grails is incredibly unhelpful in the error messages it gives you, but you can learn to recognize patterns, like the following:
- Some of the hardest errors to make sense of are because you didn't run
grails clean
orgrails upgrade
... to avoid these problems, I always use the following on the command line to run grails:grails clean; yes | grails upgrade; grails run-app
- If the error has to do with duplicate definitions of a class, make sure that you declare the package the class belongs to at the top of the class's file
- If the error has to do with schema metadata, connection, socket, or anything like that, make sure your database connector is in
lib/
, make sure your permissions are correct both inDataSource.groovy
and in the database for username, password, and host, and make sure that you know the ins and outs of your connector's version (i.e. mysql connector version 5.1.X has a weird issue with aliases that may require you to setuseOldAliasMetadataBehavior=true
on the url inDataSource.groovy
)
And so on. There are a lot of patterns to learn to recognize.
Solution 2:
-
To add to Chris King's suggestion on save, I wrote a reusable closure:
Closure saveClosure = { domainObj -> if(domainObj.save()) println "Domain Object $domainObj Saved" else { println "Errors Found During Save of $domainObj!" println domainObj.errors.allErrors.each { println it.defaultMessage } } }
Then you can just use it everywhere and it will take care of error reporting:
def book = new Book(authorName:"Mark Twain")
saveClosure(book)
Additionally, I use the debug plugin - it allows extra logging, and I added tag to the bottom of my main - that gives me a view of all the variables in session / request.
Runtime Logging plugin allows to enable logging at runtime.
While writing this answer, P6SPY plugin also seems like it could be useful - it logs all statements your app makes against the database by acting as a proxy.
Grails Console is also useful. I use it to interactively poke around and experiment with some code, which also comes in handy during debugging.
And of course, being able to step through Debugger is sweet. I switched to IntelliJ IDEA since it has the best Grails / Groovy support.
Solution 3:
I once asked an experienced groovy developer about how he effectively debugged his applications. His answer:
I write tests!
And he has a very good point: If your code has sufficient unit and integration tests, you will hardly ever need to debug anything. Plus you get to say smug things like that to your fellow developers...
For Grails:
- Unit Testing
- Functional Testing
- Really excellent grails app testing developerWorks article
Solution 4:
To log exceptions with GrailsUtil.
try{
...
}catch (Exception e){
log.error("some message", GrailsUtil.sanitize(e))
...
}
More info about sanitize.
Solution 5:
I'm not sure if this can be done out-of-the-box, but in webapps I find it useful to have a "who am I?" facility in the various view files.
The idea is to emit a message into the rendered HTML, to identify the fragment. This is especially true when I am encountering an app for the first time.
In Grails, I do this with a custom tag. For example, consider list.gsp for a Student:
<g:debug msg="student list" />
Here is the code:
class MiscTagLib {
def debug = { map ->
if (grailsApplication.config.grails.views.debug.mode == true) {
def msg = map['msg']
out << "<h2>${msg}</h2><br/>"
}
}
}
The key is that you can leave those tags in there, if desired, as they only appear in when the mode is enabled in Config.groovy:
grails.views.debug.mode=true