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

Debugging 您最喜欢的Grails调试技巧是什么?,debugging,grails,Debugging,Grails,Grails可以通过其长堆栈转储进行调试。找到问题的根源可能很棘手。例如,我在BootStrap.groovy中做了几次“def foo=new foo(a:a,b:b).save()”时被烧坏了。调试Grails应用程序时,您最喜欢的技巧是什么?以下是@from Grails people在twitter上收集的一些技巧: 一些一般提示: 清除stacktrace.log,运行grails应用程序,然后在查看器中打开stacktrace.log(我更喜欢在linux上少一点stacktrac

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

以下是@from Grails people在twitter上收集的一些技巧:

一些一般提示:

  • 清除stacktrace.log,运行grails应用程序,然后在查看器中打开stacktrace.log(我更喜欢
    在linux上少一点stacktrace.log
    )。。。进入查看器后,搜索.groovy和.gsp。。。这通常会让你了解你真正关心的事情。

  • 当stacktrace引用GSP文件中的行号时,应在浏览器中使用查询字符串中的
    ?showSource
    打开该视图,即
    http://localhost:8080/myProject/myController/myAction?showSource
    。。。这显示了已编译的GSP源,stacktrace中的所有GSP行号都是指已编译的GSP,而不是实际的GSP源
  • 总是,总是,总是用至少一些最小的错误处理围绕您的存储
例如:

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()
    }
}
除此之外,很多都归结为识别堆栈跟踪和错误消息。。。很多时候,Grails在它给您的错误消息中毫无帮助,但您可以学习识别模式,如以下所示:

  • 一些最难理解的错误是因为您没有运行
    grailsclean
    grailsgrade
    。。。为了避免这些问题,我总是在命令行上使用以下命令来运行grails:
    GrailsClean;是| grails升级;grails run应用程序

  • 如果错误与类的重复定义有关,请确保在类文件的顶部声明该类所属的包
  • 如果错误与架构元数据、连接、套接字或类似内容有关,请确保您的数据库连接器位于
    lib/
    中,确保您在
    DataSource.groovy以及数据库中对用户名、密码和主机的权限正确,并确保您了解连接器版本的详细信息(即mysql连接器版本5.1.X的别名有一个奇怪的问题,可能需要您在
    数据源.groovy
    中的url上设置
    useOldAliasMetadataBehavior=true

等等。有很多模式需要学习识别。

  • 为了补充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
                  }
          }
       }
    
然后,您可以在任何地方使用它,它将负责错误报告:

  def book = new Book(authorName:"Mark Twain")
  saveClosure(book)
  • 此外,我使用-它允许额外的日志记录,并且我在main的底部添加了标记-它为我提供了会话/请求中所有变量的视图

  • 允许在运行时启用日志记录

  • 在写这个答案时,它似乎也很有用——它通过代理的方式记录你的应用程序对数据库所做的所有声明

  • Grails控制台也很有用。我使用它以交互方式浏览和实验一些代码,这在调试过程中也很方便

  • 当然,能够一步一步地通过调试器是件好事。我转而使用IntelliJ IDEA,因为它具有最好的Grails/Groovy支持


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

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

我写测试

他有一个很好的观点:如果你的代码有足够的单元和集成测试,你几乎不需要调试任何东西。另外,你还可以对你的开发伙伴说一些自鸣得意的话

对于Grails:

  • 非常优秀的grails应用程序测试

我不确定这是否可以开箱即用,但在webapps中,我发现在各种视图文件中设置“我是谁?”功能很有用

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

在Grails中,我使用一个自定义标记来实现这一点。例如,考虑一个学生的List.gSP:

<g:debug msg="student list" />

使用GrailsUtil记录异常

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

查看源代码!这救了我很多次!现在代码托管在GitHub上,比以往任何时候都简单。只需按“t”并开始键入即可找到您要查找的类


将此代码添加到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


            }
        }
...
}
希望对某人有所帮助:)

(我知道它不是很干)


ref:

我很高兴看到我们终于有了一颗银弹。WTF?那么,当他的测试失败时,他是如何调试代码的呢?还是他的代码从来没有通过测试?在这种情况下,他只是测试他知道会起作用的东西?这是一个非常奇怪的说法,我觉得这是重复的。更不用说你说的自鸣得意了。西蒙&WTF对写作测试的反应。。。您可以尝试将日志添加到测试中。@如果您可以一次测试一个组件而不是整个应用程序,则Simon调试会容易得多。最近记忆中的最佳问题…@MichaelEaster seconded。因此认为这些知识库文章没有建设性,这真是一个遗憾。答案投票系统提供了一个优秀的系统,可以将提示从最有用到最不有用进行集体排序,这比维基风格的知识库要有用得多。saveClosure(x)真的那么groovy吗?当然重写save()方法会更好吗?不要再麻烦p6spy了。使用SpringInsight。它具有p6spy的所有功能,无需c
try{
   ...
}catch (Exception e){
   log.error("some message", GrailsUtil.sanitize(e))
   ...
}
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


            }
        }
...
}