5

私はGrailsを初めて使用し、ログ呼び出しが発生した正確なファイルと行を記録するようにLog4jを構成しようとしています。!として機能するパターンはありません。conversionPatternGrails は、Log4j が実際の呼び出し元を認識しないようにロガーをラップしているようです。

このスレッドは知っていますが、カスタム アペンダーを作成する方法がわかりません。この問題を解決するために誰もまだ何かを開発していないとは信じられません!

私はどんな提案にもオープンです:

  • Log4j以外のものを使用してGrailsで実際のファイル+行(Logback?)を取得できますか?
  • 彼が喜んで共有したい既存の「カスタムアペンダー」を持っている人はいますか?

前もって感謝します!

4

1 に答える 1

8

実際に自分でやりました。適切な Grails プラグインを作成する必要があると思いますが、コードが常に機能することを確認するには、まだ Grails に慣れていません。Grails 2.2.4 を使用して、Controller と Service からログを記録してテストしましたが、うまく機能しているようです。

スタックトレースをチェックして、呼び出しが発生した実際のファイルと行を見つけ、この情報をMDCスレッド コンテキストに追加します。追加された値MDCは、トークンを使用して (他の) アペンダーで使用でき%X{fileAndLine}ます。

これがコードとjavadocです(読んでください!):

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");
        }
    }
}

何かが明確でない場合、またはそれを改善する方法を見つけた場合はお知らせください。

于 2013-08-12T23:43:37.177 に答える