我们使用apache log4j实现项目中的日志功能,在项目中我们通常有这样的需求,一般情况System.out.println()是输出到控制台,但我们希望System.out的输出也记录到log中,还有System.err同样也记录到log中,一些runtime的exception会通过System.err打出到控制台,我们同样希望把这些也都输出到log。在网上查了些参考之后,自己整理并实现了下面的方法。

System类有setOut方法,可以设置output stream,进行output重定向,所以我们可以传入一个新的PrintStream对象,重写PrintStream的print方法,把要print的值都通过log4j写入到log,因此我们实现一个这样的类:

Java代码 log4j重定向stdout和stderr到log文件_xml


  1. import java.io.PrintStream;

  2. import org.apache.commons.logging.Log;
  3. import org.apache.commons.logging.LogFactory;


  4. public class StdOutErrRedirect {
  5. private final static Log logger = LogFactory.getLog(StdOutErrRedirect.class);

  6. public static void redirectSystemOutAndErrToLog() {
  7. PrintStream printStreamForOut = createLoggingWrapper(System.out, false);
  8. PrintStream printStreamForErr = createLoggingWrapper(System.out, true);
  9. System.setOut(printStreamForOut);
  10. System.setErr(printStreamForErr);
  11. }

  12. public static PrintStream createLoggingWrapper(final PrintStream printStream, final boolean isErr) {
  13. return new PrintStream(printStream) {
  14. @Override
  15. public void print(final String string) {
  16. if (!isErr){
  17. logger.debug(string);
  18. }else{
  19. logger.error(string);
  20. }
  21. }
  22. @Override
  23. public void print(boolean b) {
  24. if (!isErr){
  25. logger.debug(Boolean.valueOf(b));
  26. }else{
  27. logger.error(Boolean.valueOf(b));
  28. }
  29. }
  30. @Override
  31. public void print(char c) {
  32. if (!isErr){
  33. logger.debug(Character.valueOf(c));
  34. }else{
  35. logger.error(Character.valueOf(c));
  36. }
  37. }
  38. @Override
  39. public void print(int i) {
  40. if (!isErr){
  41. logger.debug(String.valueOf(i));
  42. }else{
  43. logger.error(String.valueOf(i));
  44. }
  45. }
  46. @Override
  47. public void print(long l) {
  48. if (!isErr){
  49. logger.debug(String.valueOf(l));
  50. }else{
  51. logger.error(String.valueOf(l));
  52. }
  53. }
  54. @Override
  55. public void print(float f) {
  56. if (!isErr){
  57. logger.debug(String.valueOf(f));
  58. }else{
  59. logger.error(String.valueOf(f));
  60. }
  61. }
  62. @Override
  63. public void print(double d) {
  64. if (!isErr){
  65. logger.debug(String.valueOf(d));
  66. }else{
  67. logger.error(String.valueOf(d));
  68. }
  69. }
  70. @Override
  71. public void print(char[] x) {
  72. if (!isErr){
  73. logger.debug(x == null ? null : new String(x));
  74. }else{
  75. logger.error(x == null ? null : new String(x));
  76. }
  77. }
  78. @Override
  79. public void print(Object obj) {
  80. if (!isErr){
  81. logger.debug(obj);
  82. }else{
  83. logger.error(obj);
  84. }
  85. }
  86. };
  87. }
  88. }


这个类里面我们重定向了System.out和Syste.err


如果是standalone的应用程序,我们可以在刚进入main方法的地方调用这个类的redirectSystemOutAndErrToLog()静态方法。


如果是web应用,我们可以实现一个servlet的listener,在初始化的时候调用这个类的redirectSystemOutAndErrToLog()静态方法。

例如:


Java代码 log4j重定向stdout和stderr到log文件_xml


  1. import javax.servlet.ServletContextEvent;
  2. import javax.servlet.ServletContextListener;

  3. public class StdOutErrInitializer implements ServletContextListener {

  4. @Override
  5. public void contextDestroyed(ServletContextEvent arg0) {

  6. }

  7. @Override
  8. public void contextInitialized(ServletContextEvent arg0) {
  9. StdOutErrRedirect.redirectSystemOutAndErrToLog();
  10. }

  11. }


然后在web.xml文件中注册这个listener


Xml代码 log4j重定向stdout和stderr到log文件_xml


  1. <listener>
  2. <listener-class>com.polyvirtual.webapp.util.StdOutErrInitializer</listener-class>
  3. </listener>



log4j.xml的配置文件,举个例子可以简单的配置成这样:

Xml代码 log4j重定向stdout和stderr到log文件_xml


  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

  3. <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

  4. <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
  5. <layout class="org.apache.log4j.PatternLayout">
  6. <param name="ConversionPattern"
  7. value="%p [%t] %c{1}.%M(%L) | %m%n"/>
  8. </layout>
  9. </appender>

  10. <appender name="FILE" class="org.apache.log4j.RollingFileAppender">
  11. <param name="File" value="polyvirtual_logs/polyvirtual_portal.log"/>
  12. <param name="MaxFileSize" value="512KB" />
  13. <layout class="org.apache.log4j.PatternLayout">
  14. <param name="ConversionPattern" value="%d - %c -%-4r [%t] %-5p %x - %m%n" />
  15. </layout>
  16. </appender>

  17. <logger name="my.test">
  18. <level value="DEBUG"/>
  19. </logger>

  20. <root>
  21. <level value="WARN"/>
  22. <appender-ref ref="CONSOLE"/>
  23. <appender-ref ref="FILE"/>
  24. </root>

  25. </log4j:configuration>



这样System.out和System.err的输入都重定向写入到log文件里了,同时也输出到了Console,便于在IDE里开发时查看。