如何将log4j输出重定向到我的HttpServletResponse输出流?[英] How do I redirect log4j output to my HttpServletResponse output stream?

本文是小编为大家收集整理的关于如何将log4j输出重定向到我的HttpServletResponse输出流?的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

我正在使用log4j 1.2.15在弹簧3.1.1.Release应用程序中部署在JBOSS AS 7.1.1. -final上.我正在尝试将写入log4j的输出路由到我的响应输出流.我已经像这样写了输出

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

我正在尝试将其路由到我的输出流,例如……

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

,但可悲的是,即使我知道(通过调试)记录语句被调用了,我的浏览器也没有输出.有人知道如何调整设置以使其正常工作吗?以下是我的log4j.properties文件,已部署到我的战争的Web-Inf/class Directory.

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

谢谢, - 戴夫

推荐答案

这是一个有趣的问题. 关键是写自己的appender .我查找了内置的org.apache.log4j.consoleappender代码的灵感.我已经在tomcat中对此进行了测试,并证实了它是否有效.我使用了log4j-1.2.17(希望没关系)

1)首先实现自己的appender.该附录将将所有日志事件写入当前线程的outputStream

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配置文件中添加此appender

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)在您的servlet中添加一小部分代码,以便此应用程序正常工作.这是我的servlet.

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

小心:尤其是在多个servlet请求等方面,这不是经过彻底的测试.也不知道为什么要这样做.将日志消息传输到浏览器并不是典型的.谨慎行事..:) -

其他推荐答案

尝试这样的东西:

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

其他推荐答案

我建议采用替代方法,并获取日志文件内容来单独的浏览器选项卡.

这不需要主代码修改,也不会破坏原始页面的格式.

一些基于Web的日志文件查看器链接:

本文地址:https://www.itbaoku.cn/post/1574900.html

问题描述

I'm using log4j 1.2.15 in a Spring 3.1.1.RELEASE application deployed on JBoss AS 7.1.1.Final. I'm trying to route output written in log4j to my response output stream. I have output written like this

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

and I'm trying to route it to my output stream like so …

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

but sadly, nothing is getting output to my browser, even though I know (through debugging) that logging statements are getting called. Does anyone know how I can adjust my setup to make it work? Below is my log4j.properties file, deployed to my wAR's WEB-INF/classes directory.

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

Thanks, - Dave

推荐答案

This was an interesting problem. The key thing is to write your own appender. I looked up the in built org.apache.log4j.ConsoleAppender code for inspiration. I have tested this in my tomcat and verified that it works. I used log4j-1.2.17 (hopefully shouldn't matter)

1) First implement your own appender. This appender will write all log events to current thread's outputstream

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) Add this appender in your log4j configuration file just like the other settings

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) Add a small piece of code in your servlet so that this appender works correctly . Here's my servlet.

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

Caution : This is not thoroughly tested especially with multiple servlet requests etc. Also not sure why you want to do this. Its not typical to pipe log messages to browser. Proceed with caution..:)-

其他推荐答案

Try with something like this:

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

其他推荐答案

I suggest to take alternative approach and fetch log file contents to separate browser tab.

This would not require main code modification and would not destroy original page's formatting.

Some web-based log file viewers links: