你最喜欢的Grails调试技巧是什么?

时间:2023-02-08 20:45:43

Grails can be a bit of a bear to debug with its long stack dumps. Getting to the source of the problem can be tricky. I've gotten burned a few times in the BootStrap.groovy doing "def foo = new Foo(a: a, b: b).save()", for example. What are your favorite tricks for debugging Grails apps?

Grails可以通过长堆栈转储进行调试。找到问题的根源可能很棘手。我在BootStrap.groovy中做了几次烧伤,例如“def foo = new Foo(a:a,b:b).save()”。你最喜欢调试Grails应用程序的技巧是什么?

9 个解决方案

#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.
  • 清除stacktrace.log,执行grails run-app,然后在查看器中打开stacktrace.log(我更喜欢linux上的stacktrace.log)...一次在你的查看器中,搜索.groovy和.gsp ...通常会带来你真正关心的是什么。

  • 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
  • 当堆栈跟踪引用GSP文件中的行号时,您应该在浏览器中使用查询字符串中的?showSource打开该视图,即http:// localhost:8080 / myProject / myController / myAction?showSource ...这显示编译后的GSP源,堆栈跟踪中的所有GSP行号都是指编译后的GSP,而不是实际的GSP源

  • 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:

除此之外,很多东西只是归结为识别堆栈跟踪和错误消息......很多时候,Grails在它给你的错误消息中非常无益,但你可以学会识别模式,如下所示:

  • Some of the hardest errors to make sense of are because you didn't run grails clean or grails 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
  • 一些最难理解的错误是因为你没有运行grails clean或grails升级...为了避免这些问题,我总是在命令行上使用以下命令来运行grails:grails clean;是的| grails升级; 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 in DataSource.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 set useOldAliasMetadataBehavior=true on the url in DataSource.groovy)
  • 如果错误与架构元数据,连接,套接字或类似的东西有关,请确保您的数据库连接器位于lib /中,确保您的权限在DataSource.groovy和数据库中都是正确的用户名,密码和主机,并确保您知道连接器版本的细节(即mysql连接器版本5.1.X有一个奇怪的别名问题,可能需要您在DataSource.groovy中的url上设置useOldAliasMetadataBehavior = true)

And so on. There are a lot of patterns to learn to recognize.

等等。有许多模式需要学会识别。

#2


  • To add to Chris King's suggestion on save, I wrote a reusable closure:

    为了增加Chris King关于保存的建议,我写了一个可重用的闭包:

     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.

    在写这个答案时,P6SPY插件似乎也很有用 - 它通过充当代理来记录您的应用程序对数据库所做的所有语句。

  • Grails Console is also useful. I use it to interactively poke around and experiment with some code, which also comes in handy during debugging.

    Grails Console也很有用。我用它来交互式地浏览并试验一些代码,这些代码在调试时也很方便。

  • And of course, being able to step through Debugger is sweet. I switched to IntelliJ IDEA since it has the best Grails / Groovy support.

    当然,能够通过调试器是很好的。我切换到IntelliJ IDEA,因为它具有最好的Grails / Groovy支持。

#3


I once asked an experienced groovy developer about how he effectively debugged his applications. His answer:

我曾经问过一位经验丰富的groovy开发人员,他是如何有效调试他的应用程序的。他的回答是:

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:

#4


To log exceptions with GrailsUtil.

使用GrailsUtil记录异常。

try{
   ...
}catch (Exception e){
   log.error("some message", GrailsUtil.sanitize(e))
   ...
}

More info about sanitize.

有关sanitize的更多信息。

#5


adding this code To the Bootsrap.groovy:init will overwrite the save method and execute some other code as well, printing out error messages in this case.

将此代码添加到Bootsrap.groovy:init将覆盖save方法并执行其他一些代码,在这种情况下打印出错误消息。

class BootStrap {

    def grailsApplication

    def init = {servletContext ->

        grailsApplication.domainClasses.each { clazz ->
            clazz.clazz.get(-1)

            def gormSave = clazz.metaClass.getMetaMethod('save')

            clazz.metaClass.save = {->

                def savedInstance = gormSave.invoke(delegate)
                if (!savedInstance) {
                    delegate.errors.each {
                        println it
                    }
                }
                savedInstance
            }

            def gormSaveMap = clazz.metaClass.getMetaMethod('save', Map)
            clazz.metaClass.save = { Map m ->
                def savedInstance = gormSaveMap.invoke(delegate, m)
                if (!savedInstance) {
                    delegate.errors.each {
                        println it
                    }
                }
                savedInstance

            }

            def gormSaveBoolean = clazz.metaClass.getMetaMethod('save', Boolean)
            clazz.metaClass.save = { Boolean b ->
                def savedInstance = gormSaveBoolean.invoke(delegate, b)
                if (!savedInstance) {
                    delegate.errors.each {
                        println it
                    }
                }
                savedInstance


            }
        }
...
}

hope that helps someone :)

希望有人帮助:)

(i know its not really DRY)

(我知道它不是真的干)

ref: http://grails.1312388.n4.nabble.com/How-to-override-save-method-on-domain-class-td3021424.html

#6


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.

我不确定这是否可以开箱即用,但在webapps中,我觉得有一个“我是谁?”是有用的。设施在各种视图文件中。

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.

想法是在呈现的HTML中发出消息,以识别片段。当我第一次遇到应用程序时尤其如此。

In Grails, I do this with a custom tag. For example, consider list.gsp for a Student:

在Grails中,我使用自定义标记执行此操作。例如,考虑学生的list.gsp:

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

关键是如果需要,您可以将这些标签保留在那里,因为它们仅在Config.groovy中启用模式时出现:

grails.views.debug.mode=true

#7


Looking at the source code! This has saved me so many times now! And now that the code is hosted at GitHub it's easier than ever. Just press "t" and start typing to find the class that you're looking for!

看源代码!这已经拯救了我很多次了!现在,代码在GitHub上托管,比以往更容易。只需按“t”键即可开始输入以查找您正在寻找的课程!

http://github.com/grails/grails-core

#8


Here's some tricks collected by @groovymag from Grails people in twitter:

以下是来自Grails人在Twitter上收集的@groovymag的一些技巧:

http://blog.groovymag.com/2009/02/groovygrails-debugging/

#9


For simple applications I use println statement.It is very very easy trick.For complex applications use debug mode in intellij idea.

对于简单的应用程序,我使用println语句。这是非常容易的技巧。对于复杂的应用程序,在intellij idea中使用调试模式。

#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.
  • 清除stacktrace.log,执行grails run-app,然后在查看器中打开stacktrace.log(我更喜欢linux上的stacktrace.log)...一次在你的查看器中,搜索.groovy和.gsp ...通常会带来你真正关心的是什么。

  • 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
  • 当堆栈跟踪引用GSP文件中的行号时,您应该在浏览器中使用查询字符串中的?showSource打开该视图,即http:// localhost:8080 / myProject / myController / myAction?showSource ...这显示编译后的GSP源,堆栈跟踪中的所有GSP行号都是指编译后的GSP,而不是实际的GSP源

  • 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:

除此之外,很多东西只是归结为识别堆栈跟踪和错误消息......很多时候,Grails在它给你的错误消息中非常无益,但你可以学会识别模式,如下所示:

  • Some of the hardest errors to make sense of are because you didn't run grails clean or grails 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
  • 一些最难理解的错误是因为你没有运行grails clean或grails升级...为了避免这些问题,我总是在命令行上使用以下命令来运行grails:grails clean;是的| grails升级; 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 in DataSource.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 set useOldAliasMetadataBehavior=true on the url in DataSource.groovy)
  • 如果错误与架构元数据,连接,套接字或类似的东西有关,请确保您的数据库连接器位于lib /中,确保您的权限在DataSource.groovy和数据库中都是正确的用户名,密码和主机,并确保您知道连接器版本的细节(即mysql连接器版本5.1.X有一个奇怪的别名问题,可能需要您在DataSource.groovy中的url上设置useOldAliasMetadataBehavior = true)

And so on. There are a lot of patterns to learn to recognize.

等等。有许多模式需要学会识别。

#2


  • To add to Chris King's suggestion on save, I wrote a reusable closure:

    为了增加Chris King关于保存的建议,我写了一个可重用的闭包:

     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.

    在写这个答案时,P6SPY插件似乎也很有用 - 它通过充当代理来记录您的应用程序对数据库所做的所有语句。

  • Grails Console is also useful. I use it to interactively poke around and experiment with some code, which also comes in handy during debugging.

    Grails Console也很有用。我用它来交互式地浏览并试验一些代码,这些代码在调试时也很方便。

  • And of course, being able to step through Debugger is sweet. I switched to IntelliJ IDEA since it has the best Grails / Groovy support.

    当然,能够通过调试器是很好的。我切换到IntelliJ IDEA,因为它具有最好的Grails / Groovy支持。

#3


I once asked an experienced groovy developer about how he effectively debugged his applications. His answer:

我曾经问过一位经验丰富的groovy开发人员,他是如何有效调试他的应用程序的。他的回答是:

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:

#4


To log exceptions with GrailsUtil.

使用GrailsUtil记录异常。

try{
   ...
}catch (Exception e){
   log.error("some message", GrailsUtil.sanitize(e))
   ...
}

More info about sanitize.

有关sanitize的更多信息。

#5


adding this code To the Bootsrap.groovy:init will overwrite the save method and execute some other code as well, printing out error messages in this case.

将此代码添加到Bootsrap.groovy:init将覆盖save方法并执行其他一些代码,在这种情况下打印出错误消息。

class BootStrap {

    def grailsApplication

    def init = {servletContext ->

        grailsApplication.domainClasses.each { clazz ->
            clazz.clazz.get(-1)

            def gormSave = clazz.metaClass.getMetaMethod('save')

            clazz.metaClass.save = {->

                def savedInstance = gormSave.invoke(delegate)
                if (!savedInstance) {
                    delegate.errors.each {
                        println it
                    }
                }
                savedInstance
            }

            def gormSaveMap = clazz.metaClass.getMetaMethod('save', Map)
            clazz.metaClass.save = { Map m ->
                def savedInstance = gormSaveMap.invoke(delegate, m)
                if (!savedInstance) {
                    delegate.errors.each {
                        println it
                    }
                }
                savedInstance

            }

            def gormSaveBoolean = clazz.metaClass.getMetaMethod('save', Boolean)
            clazz.metaClass.save = { Boolean b ->
                def savedInstance = gormSaveBoolean.invoke(delegate, b)
                if (!savedInstance) {
                    delegate.errors.each {
                        println it
                    }
                }
                savedInstance


            }
        }
...
}

hope that helps someone :)

希望有人帮助:)

(i know its not really DRY)

(我知道它不是真的干)

ref: http://grails.1312388.n4.nabble.com/How-to-override-save-method-on-domain-class-td3021424.html

#6


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.

我不确定这是否可以开箱即用,但在webapps中,我觉得有一个“我是谁?”是有用的。设施在各种视图文件中。

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.

想法是在呈现的HTML中发出消息,以识别片段。当我第一次遇到应用程序时尤其如此。

In Grails, I do this with a custom tag. For example, consider list.gsp for a Student:

在Grails中,我使用自定义标记执行此操作。例如,考虑学生的list.gsp:

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

关键是如果需要,您可以将这些标签保留在那里,因为它们仅在Config.groovy中启用模式时出现:

grails.views.debug.mode=true

#7


Looking at the source code! This has saved me so many times now! And now that the code is hosted at GitHub it's easier than ever. Just press "t" and start typing to find the class that you're looking for!

看源代码!这已经拯救了我很多次了!现在,代码在GitHub上托管,比以往更容易。只需按“t”键即可开始输入以查找您正在寻找的课程!

http://github.com/grails/grails-core

#8


Here's some tricks collected by @groovymag from Grails people in twitter:

以下是来自Grails人在Twitter上收集的@groovymag的一些技巧:

http://blog.groovymag.com/2009/02/groovygrails-debugging/

#9


For simple applications I use println statement.It is very very easy trick.For complex applications use debug mode in intellij idea.

对于简单的应用程序,我使用println语句。这是非常容易的技巧。对于复杂的应用程序,在intellij idea中使用调试模式。