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

56 debugging grails

通过长堆栈转储,Grails可能有点像熊一样调试.找到问题的根源可能很棘手.我在BootStrap.groovy中做过几次烧伤,例如"def foo = new Foo(a:a,b:b).save()".您最喜欢调试Grails应用程序的技巧是什么?

Chr*_*ing 33

一些一般提示:

  • 清除stacktrace.log,做grails run-app,然后在查看器中打开stacktrace.log(我更喜欢less stacktrace.loglinux)...一旦在你的查看器中,搜索.groovy和.gsp ...这通常会带你到你的东西实在在意.
  • 当堆栈跟踪引用GSP文件中的行号时,您应该在浏览器?showSource中使用查询字符串打开该视图,即http://localhost:8080/myProject/myController/myAction?showSource...这显示已编译的GSP源,并且堆栈跟踪中的所有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()
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 一些最难理解的错误是因为你没有运行grails cleangrails upgrade...为了避免这些问题,我总是在命令行上使用以下命令来运行grails:grails clean; yes | grails upgrade; grails run-app
  • 如果错误与类的重复定义有关,请确保在类的文件顶部声明类所属的包
  • 如果错误与架构元数据,连接,套接字或类似的内容有关,请确保您的数据库连接器已插入,请lib/确保您DataSource.groovy的用户名,密码和主机的数据库内和数据库中的权限都是正确的,并确保你知道你的连接器版本的来龙去脉(即mysql连接器版本5.1.X有一个奇怪的问题,别名,可能需要你useOldAliasMetadataBehavior=true在网址上设置DataSource.groovy)

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


Jea*_*ash 16

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

     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
                  }
          }
       }
    
    Run Code Online (Sandbox Code Playgroud)

然后你可以在任何地方使用它,它将负责错误报告:

  def book = new Book(authorName:"Mark Twain")
  saveClosure(book)
Run Code Online (Sandbox Code Playgroud)
  • 另外,我使用调试插件 - 它允许额外的日志记录,我将标签添加到我的主要底部 - 这使我可以查看会话/请求中的所有变量.

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

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

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

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

  • 不要再打扰p6spy了.使用Spring Insight.它具有p6spy的所有功能,没有配置问题.另外,您可以将其用于性能调整.查看Peter Ledbrook的视频.http://www.youtube.com/watch?v=rR-8EMKzduA (3认同)
  • saveClosure(x)真的很时髦吗?当然,覆盖save()方法会更好吗? (2认同)

小智 14

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

我写测试!

他有一个非常好的观点:如果你的代码有足够的单元和集成测试,你几乎不需要调试任何东西.另外,你可以向你的开发人员说出类似的东西......

对于Grails:

  • WTF?那么当他的测试失败时他是如何调试代码的呢?或者他的代码从未失败过他的测试?在哪种情况下他只测试他知道会起作用的东西?这是一个非常奇怪的事情,并且反复告诉我.更不用说你正确地说的自鸣得意. (14认同)
  • 我很高兴看到我们终于有了一颗银弹. (4认同)

use*_*427 7

使用GrailsUtil记录异常.

try{
   ...
}catch (Exception e){
   log.error("some message", GrailsUtil.sanitize(e))
   ...
}
Run Code Online (Sandbox Code Playgroud)

有关sanitize的更多信息.


Mic*_*ter 5

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

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

在 Grails 中,我使用自定义标记来完成此操作。例如,考虑一个学生的 list.gsp:

<g:debug msg="student list" />
Run Code Online (Sandbox Code Playgroud)

这是代码:

class MiscTagLib {
    def debug = { map ->
        if (grailsApplication.config.grails.views.debug.mode == true) {
            def msg = map['msg']
            out << "<h2>${msg}</h2><br/>"
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

grails.views.debug.mode=true
Run Code Online (Sandbox Code Playgroud)


nil*_*ohn 5

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


            }
        }
...
}
Run Code Online (Sandbox Code Playgroud)

希望有人帮助:)

(我知道它不是真的干)

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