【问题标题】:What are your favorite Grails debugging tricks? [closed]你最喜欢的 Grails 调试技巧是什么? [关闭]
【发布时间】:2010-10-06 21:37:53
【问题描述】:

Grails 的长堆栈转储可能有点难以调试。找到问题的根源可能很棘手。例如,我在 BootStrap.groovy 中多次执行“def foo = new Foo(a: a, b: b).save()”。您最喜欢调试 Grails 应用程序的技巧是什么?

【问题讨论】:

  • 最近记忆中最好的问题...
  • @MichaelEaster 附议。 SO认为这些知识库文章没有建设性,真是太可惜了。它们与它们一样具有建设性,并且答案投票系统提供了一个出色的系统,可以将提示从最有用到最不有用集中排序,这比在 wiki 风格的 KB 中要好得多。

标签: debugging grails


【解决方案1】:

一些一般提示:

  • 清除 stacktrace.log,执行 grails run-app,然后在查看器中打开 stacktrace.log(我更喜欢在 Linux 上使用 less stacktrace.log)...在查看器中搜索 .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()
    }
}

除此之外,很多事情都归结为识别堆栈跟踪和错误消息......很多时候,Grails 在它给你的错误消息方面毫无帮助,但你可以学习识别模式,比如以下:

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

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

【讨论】:

  • "t/myController/myAction?showSource" 这在生产模式下有效吗? :)
  • 对不起 - 仅开发模式,不是测试或生产模式
  • 我从来没有真正理解为什么 save 不会在默认情况下 failOnError —— 我发现这对于我认识的每个开发人员来说都是一个完全出乎意料的行为,这就是为什么我想grails.gorm.failOnError=true 在开始一个新项目。
【解决方案2】:
  • 为了补充 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)
    1234563
  • Runtime Logging plugin 允许在运行时启用日志记录。

  • 在编写此答案时,P6SPY plugin 似乎也很有用 - 它通过充当代理记录您的应用对数据库所做的所有语句。

  • Grails 控制台也很有用。我用它来交互地探索和试验一些代码,这在调试过程中也很方便。

  • 当然,能够单步调试 Debugger 是件好事。我改用 IntelliJ IDEA,因为它有最好的 Grails / Groovy 支持。

【讨论】:

  • saveClosure(x) 真的那么棒吗?重写 save() 方法肯定会更好吗?
  • 别再为 p6spy 烦恼了。使用 Spring Insight。它具有 p6spy 的所有功能,没有配置问题。另外,您可以将其用于性能调整。查看彼得·莱德布鲁克的视频。 youtube.com/watch?v=rR-8EMKzduA
【解决方案3】:

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

我写测试!

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

对于 Grails:

【讨论】:

  • 我很高兴看到我们终于有了灵丹妙药。
  • WTF?那么当他的测试失败时,他是如何调试代码的呢?或者他的代码从来没有通过他的测试?在这种情况下,他只是在测试他知道会起作用的东西吗?这是一件非常奇怪的事情,让我觉得是同义反复。更不用说你说得对的自鸣得意了。
  • Simon 和 WTF 对编写测试的回应...您可以尝试在测试中添加日志记录。
  • @Simon 调试要容易得多,因为您可以一次测试一个组件而不是整个应用程序。
【解决方案4】:

使用 GrailsUtil 记录异常。

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

More info about sanitize.

【讨论】:

    【解决方案5】:

    我不确定这是否可以开箱即用,但在 web 应用程序中,我发现“我是谁?”很有用。各种视图文件中的设施。

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

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

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

    代码如下:

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

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

    grails.views.debug.mode=true
    

    【讨论】:

      【解决方案6】:

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

      希望对某人有所帮助:)

      (我知道它不是很干)

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

      【讨论】:

        【解决方案7】:

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

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

        【讨论】:

          【解决方案8】:

          以下是@groovymag 从 Grails 人的推特上收集的一些技巧:

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

          【讨论】:

            【解决方案9】:

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

            【讨论】:

              猜你喜欢
              • 2010-10-25
              • 2010-09-12
              • 2010-09-13
              • 2010-09-06
              • 2010-09-05
              • 2010-11-29
              • 2010-10-08
              • 2011-07-18
              • 2010-09-13
              相关资源
              最近更新 更多