6

JBossAS7.1.1.FinalにデプロイされたSpring3.1.1.RELEASEアプリケーションでlog4j1.2.15を使用しています。log4jに書き込まれた出力を応答出力ストリームにルーティングしようとしています。私はこのように書かれた出力を持っています

private static final Logger LOG = Logger.getLogger(TrainingSessionServiceImpl.class);
…
LOG.info("Creating/updating training session associated with order #:" + order.getId());

そして、私はそれを私の出力ストリームにルーティングしようとしています…</ p>

@RequestMapping(value = "/refreshPd", method = RequestMethod.GET)
public void refreshPD(final HttpServletResponse response) throws IOException
{
    ...        
    final WriterAppender appender = new WriterAppender(new PatternLayout("%d{ISO8601} %p - %m%n"),response.getWriter());
    appender.setName("CONSOLE_APPENDER");
    appender.setThreshold(org.apache.log4j.Level.DEBUG);
    Logger.getRootLogger().addAppender(appender);

    worker.work();

    Logger.getRootLogger().removeAppender("CONSOLE_APPENDER");

しかし悲しいことに、ロギングステートメントが呼び出されていることを(デバッグを通じて)知っていても、ブラウザに何も出力されません。セットアップを調整して機能させる方法を知っている人はいますか?以下は、wARのWEB-INF/classesディレクトリにデプロイされたlog4j.propertiesファイルです。

log4j.rootLogger=DEBUG, CA, FA

#Console Appender
log4j.appender.CA=org.apache.log4j.ConsoleAppender
log4j.appender.CA.layout=org.apache.log4j.PatternLayout
log4j.appender.CA.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n

#File Appender
log4j.appender.FA=org.apache.log4j.FileAppender
log4j.appender.FA.File=/usr/java/jboss/server/default/log/log4j.log
log4j.appender.FA.layout=org.apache.log4j.PatternLayout
log4j.appender.FA.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n

# Set the logger level of File Appender to WARN
log4j.appender.FA.Threshold = DEBUG

ありがとう、-デイブ

4

4 に答える 4

7

これは興味深い問題でした。 重要なことは、独自の appender を作成することです。インスピレーションを得るために、組み込みの org.apache.log4j.ConsoleAppender コードを調べました。Tomcat でこれをテストし、動作することを確認しました。私は log4j-1.2.17 を使用しました(問題にならないことを願っています)

1) 最初に独自のアペンダーを実装します。このアペンダーは、すべてのログ イベントを現在のスレッドの出力ストリームに書き込みます。

package com.tstwbprj.log;

import org.apache.log4j.Layout;
import org.apache.log4j.WriterAppender;

import java.io.IOException;
import java.io.OutputStream;

public class HttpLogAppender extends WriterAppender {

    static ThreadLocal<OutputStream> streamPerHttpThread = new ThreadLocal<OutputStream>();

    public HttpLogAppender() {

    }

    public HttpLogAppender(Layout layout) {
        setLayout(layout);       //super-class method
        activateOptions();
    }

    public void setCurrentHttpStream(OutputStream stream) {
        streamPerHttpThread.set(stream);
    }


    public void activateOptions() {
        setWriter(createWriter(new CurrentHttpThreadOutStream()));
    }


    /**
     * An implementation of OutputStream that redirects to the
     * current http threads servlet output stream
     */
    private static class CurrentHttpThreadOutStream extends OutputStream {
        public CurrentHttpThreadOutStream() {
        }

        public void close() {
        }

        public void flush() throws IOException {
            OutputStream stream = streamPerHttpThread.get();
            if (stream != null) {
                stream.flush();
            }
        }

        public void write(final byte[] b) throws IOException {
            OutputStream stream = streamPerHttpThread.get();
            if (stream != null) {
                stream.write(b);
            }
        }

        public void write(final byte[] b, final int off, final int len)
                throws IOException {
            OutputStream stream = streamPerHttpThread.get();
            if (stream != null) {
                stream.write(b, off, len);
            }
        }

        public void write(final int b) throws IOException {
            OutputStream stream = streamPerHttpThread.get();
            if (stream != null) {
                stream.write(b);
            }
        }
    }
}

2) 他の設定と同様に、このアペンダーを log4j 構成ファイルに追加します。

log4j.rootLogger=DEBUG、CA、FA、HA
..
log4j.appender.HA= com.tstwbprj.log.HttpLogAppender log4j.appender.HA.layout=org.apache.log4j.PatternLayout log4j.appender.HA.layout.ConversionPattern =%-4r [%t] %-5p %c %x - %m%n

3) このアペンダーが正しく動作するように、サーブレットに小さなコードを追加します。これが私のサーブレットです。

import org.apache.log4j.Category;
import org.apache.log4j.Logger;
import javax.servlet.ServletOutputStream;
import java.io.IOException;

public class LogServlet extends javax.servlet.http.HttpServlet {

    private static final Logger LOG = Logger.getLogger(LogServlet.class);

    protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {

    }

    protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
        ServletOutputStream outstream = response.getOutputStream();
        configureLogForCurrentRequest(outstream);

        LOG.info("Got request");//this is now send to the servlet output stream !!
        LOG.info("Hello!!");
        LOG.info("Done!!");
    }

    private void configureLogForCurrentRequest(ServletOutputStream outstream) {

        HttpLogAppender appender = (HttpLogAppender) LOG.getAppender("HA");
        while (appender == null) {
            Category parent = LOG.getParent();
            if (parent == null) {
                break; //This ideally shouldn't happen. Navigated all the way to root logger and still did not find appender !!..something wrong with log4j configuration setup
            }
            appender = (HttpLogAppender) parent.getAppender("HA");

        }
        appender.setCurrentHttpStream(outstream);
    }
}

注意: これは、特に複数のサーブレット リクエストなどで十分にテストされていません。また、なぜこれを行う必要があるのか​​もわかりません。ログメッセージをブラウザーにパイプするのは一般的ではありません。注意して進んでください..:)-

于 2013-01-25T11:06:53.913 に答える
1

次のようなものを試してください:

Logger logger = Logger.getRootLogger();
String name = "myAppender";

Appender servletAppender = logger.getAppender(appenderName);
OutputStream out = response.getOutputStream();

if (servletAppender == null) {
    servletAppender = new WriterAppender(new PatternLayout("%d{ISO8601} %p - %m%n"), out);
    servletAppender.setName(appenderName);
    appender.setThreshold(org.apache.log4j.Level.DEBUG);
    logger.addAppender(servletAppender);
}

try {
    // Your work
    worker.work();
} finally {
    logger.removeAppender(appenderName);
    out.flush();
}
于 2013-01-23T19:10:10.993 に答える
0

別のアプローチを取り、ログ ファイルの内容を別のブラウザ タブにフェッチすることをお勧めします。

これは、メイン コードの変更を必要とせず、元のページの書式設定を破壊しません。

いくつかの Web ベースのログ ファイル ビューアー リンク:

于 2013-01-23T18:58:39.287 に答える
0

それ自体は正確な答えではありませんが、これが処理されるのを見たより良い方法は、.log でログを収集する独自の Appender を作成することThreadLocalです。サーブレット リクエストが完了すると、必要に応じて のコンテンツを排出ThreadLocalし、レスポンス ストリームに出力できます。

これは、スレッド セーフの (明示されていない) 要件を満たし、log4j (または他のロギング フレームワーク) の実装コード (この手法を使用すると小さくする必要があります) を の操作からかなりきれいに分離できますThreadLocal。コードの領域。

このタイプの手法は、ColdFusion などの多くのサーバー側スクリプト言語で使用されています。

アプリサーバーでの不適切な使用によって発生する可能性のある潜在的なバグについては説明しません。これを管理する手法と、SO や他のサイトの関連する回答があります。ThreadLocal

この答えがあなたの考えを少し違う方向に向けてくれることを願っています!

于 2013-01-24T17:12:20.383 に答える