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
2) Add this appender in your log4j configuration file just like the other settings
3) Add a small piece of code in your servlet so that this appender works correctly . Here's my servlet.
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..:)-
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:
Try with something like this:
Not a precise answer as such, but a better way that I have seen this handled is to write your own Appender that will collect logs in a
ThreadLocal
. At the time your servlet request completes, you can drain the contents of theThreadLocal
and output to the response stream however you wish.This satisfies the (unstated) requirement of thread safety, and can fairly cleanly isolate the log4j (or other logging framework) implementation code (which should be small, using this technique) from the manipulation of the
ThreadLocal
, which could in theory be reused in other areas of your code.This type of technique is used by many server-side scripting languages such as ColdFusion and others.
I won't go into the potential bugs you could cause with inappropriate use of
ThreadLocal
in an app server, there are techniques to manage this, along with relevant answers on SO and other sites.Hope this answer might redirect your thinking in a slightly different direction!