Grails 日志记录 - 是否有任何现有的解决方案能够记录实际发生调用的文件 + 行? [英] Grails logging - Is there any existing solution to be able to log the File + Line where the call actually occured?

查看:12
本文介绍了Grails 日志记录 - 是否有任何现有的解决方案能够记录实际发生调用的文件 + 行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是 Grails 的新手,我正在尝试配置 Log4j,以便它记录发生日志调用的确切文件和行.没有 pattern 作为 conversionPattern!Grails 似乎以一种 Log4j 看不到调用的真正来源的方式包装了记录器.

I'm new to Grails and I'm trying to configure Log4j so it logs the exact file and line where the log call occured. No pattern works as the conversionPattern! It seems Grails wraps the logger in a way that Log4j doesn't see the real source of the call.

我知道这个 thread,但我不确定如何创建自定义 appender.我简直不敢相信没有人已经开发出解决此问题的方法!

I'm aware of this thread, but I'm not sure how to create a custom appender. I just can't believe nobody already developed something to fix this issue!

我愿意接受任何建议:

  • 在 Grails 中使用 Log4j 以外的其他东西是否可以获取实际的文件+行(Logback?)?
  • 有人愿意分享现有的自定义附加程序"吗?

提前致谢!

推荐答案

实际上是我自己做的.我想我应该为它做一个合适的 Grails 插件,但我对 Grails 仍然不够满意,无法确保代码始终有效.我使用 Grails 2.2.4 通过从控制器和服务登录来测试它,它似乎运行良好.

I actually did it by myself. I guess I should do a proper Grails plugin for it, but I'm still not comfortable enough with Grails to be sure the code will always work. I tested it by logging from a Controller and from a Service, using Grails 2.2.4, and it seems to work well.

它的工作原理是检查堆栈跟踪以找到调用发生的实际文件和行,然后将这些信息添加到 MDC 线程上下文.添加到 MDC 的值可以被(其他)appender 使用 %X{fileAndLine} 标记使用.

It works by checking the stacktrace to find the actual file and line where the call occurred and then it adds this information in the MDC thread context. Values added to MDC can be used by the (other) appenders using the %X{fileAndLine} token.

这是代码和 javadoc(阅读它!):

Here's the code and the javadoc (read it!) :

package logFileLineInjectorGrailsPlugin

import org.apache.log4j.Appender;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.Logger;
import java.lang.StackTraceElement;
import org.apache.log4j.MDC;

/**
 * Allows the log appenders to have access to the FILE and LINE where the log call actually occurred.
 * 
 * (1) Add this pseudo appender to your other appenders, in Config.groovy. Then you can use 
 * "%X{fileAndLine}" in the other appenders to output the file and line where the log call actually occurred.
 * 
 * ------------
 * log4j = {
 *     appenders {
 *      appender name:'fileAndLineInjector', new logFileLineInjectorGrailsPlugin.FileAndLineInjector()
 *      // example of a console appender using the "%X{fileAndLine}" token :
 *         console name:'stdout', layout:pattern(conversionPattern: '[%d{yyyy-MM-dd HH:mm:ss}] %-5p ~ %m ~ %c ~ %X{fileAndLine}%n')
 *     }
 *  (...)
 * ------------
 * 
 * (2) Then add it has the *first* appender reference in the declarations of the loggers in which you want to use the "%X{fileAndLine}" token.
 *  
 * For example :
 * 
 * ------------
 * root {
 *     error 'fileAndLineInjector', 'stdout'
 * }
 * ------------
 *  
 * With this setup in place, a call to log.error("test!") will result in something like :
 *  
 * [2013-08-12 19:16:15] ERROR ~ test! ~ grails.app.services.testProject.TestService ~ (TestService.groovy:8)
 * 
 * In Eclipse/STS/GGTS (I didn't try in other IDEs), when "%X{fileAndLine}" is outputed in the internal console, the text is clickable
 * and leads to the actual file/line.
 * 
 *
 */
class FileAndLineInjector extends AppenderSkeleton {

    @Override
    public void close() {
    }

    @Override
    public boolean requiresLayout() {
        return false;
    }

    @Override
    protected void append(LoggingEvent event) {

        StackTraceElement[] strackTraceElements = Thread.currentThread().getStackTrace();

        StackTraceElement targetStackTraceElement = null;
        for(int i = 0; i < strackTraceElements.length; i++) {
            StackTraceElement strackTraceElement = strackTraceElements[i];
            if(strackTraceElement != null &&
               strackTraceElement.declaringClass != null &&
               strackTraceElement.declaringClass.startsWith("org.apache.commons.logging.Log$") &&
               i < (strackTraceElements.length - 1)) {
                   targetStackTraceElement = strackTraceElements[++i];
                   while(targetStackTraceElement.declaringClass != null &&
                         targetStackTraceElement.declaringClass.startsWith("org.codehaus.groovy.runtime.callsite.") &&
                         i < (strackTraceElements.length - 1)) {
                       targetStackTraceElement = strackTraceElements[++i];
                   }
                   break;
            }
        }

        if(targetStackTraceElement != null) {
            MDC.put("fileAndLine", "(" + targetStackTraceElement.getFileName() + ":" + targetStackTraceElement.getLineNumber() + ")");
        } else {
            MDC.remove("fileAndLine");
        }
    }
}

如果有什么不清楚的地方或者您想办法改进它,请告诉我!

Let me know if something is not clear or if you find a way to improve it!

这篇关于Grails 日志记录 - 是否有任何现有的解决方案能够记录实际发生调用的文件 + 行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆