把在程序中的System.out.print()的信息自动转成log4j日志信息

摘要:
问题:在旧系统中,程序不使用log4j,而是使用system。outPrintln()将信息打印到tomcat。现在,客户建议将打印的日志信息保存到tomcat。虽然有必要引入log4j,但代码修改和后续测试的工作量和风险也是巨大的。测试显示,当天的日志将临时存储为stdout。在日志的日志文件中,只有在日期更改后,才会自动更改为符合格式的文件名。原因是当tomcat启动时,B程序中的log4j包使用System。出来println()和系统。outPrintln()将被A的StdoutListener监听,并导致无休止的调用。临时解决方案:在B中进行上述配置,引入StdoutListener,并编写log4j.prop
问题:老的系统中,程序未使用log4j,而是使用System.out.println()将信息打印到了tomcat。现在客户提出要保存打印到tomcat的日志信息,引入log4j固然需要,但修改代码及后续测试的工作量与风险也让人头大。如何解决这样的问题呢? 

回答:System.setOut(PrintStream ps)方法允许程序员自行定义System.out输出流,我们可以将我们改造好的PrintStream替换java原来的System.out对象。

为了能在web服务器启动以后完成这个替换的过程,我们定义一个ServletContextListener监听器,在web服务器启动时完成替换。

package com;

import java.io.PrintStream;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.commons.logging.impl.LogFactoryImpl;
/**
 * 把在程序中的System.out.print()的信息自动转成日志信息
 */
public class StdoutListener implements ServletContextListener {
    public void contextDestroyed(ServletContextEvent event) {
    }
    private void log(Object info) {
        LogFactoryImpl.getLog(getClass()).info(info);
    }
    public void contextInitialized(ServletContextEvent event) {
        PrintStream printStream = new PrintStream(System.out) {
            public void println(boolean x) {
                log(Boolean.valueOf(x));
            }
            public void println(char x) {
                log(Character.valueOf(x));
            }
            public void println(char[] x) {
                log(x == null ? null : new String(x));
            }
            public void println(double x) {
                log(Double.valueOf(x));
            }
            public void println(float x) {
                log(Float.valueOf(x));
            }
            public void println(int x) {
                log(Integer.valueOf(x));
            }
            public void println(long x) {
                log(x);
            }
            public void println(Object x) {
                log(x);
            }
            public void println(String x) {
                log(x);
            }
        };
        System.setOut(printStream);
        System.setErr(printStream);
    }
}
 

在web.xml里配置这个监听器,完善log4j.properties文件。搞定!

附:

web.xml中配置监听器:

 <listener>
<listener-class>com.bettersoft.filters.StdoutListener</listener-class>

 </listener> 

我的 log4j.properties文件:

log4j.rootLogger=INFO,Stdout,R
log4j.appender.Stdout=org.apache.log4j.ConsoleAppender
log4j.appender.Stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.Stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %m%n
log4j.appender.R=org.apache.log4j.DailyRollingFileAppender
log4j.appender.R.File=../logs/stdout.log
log4j.appender.R.datePattern='.'yyyy-MM-dd'.txt'
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %m%n

说明: 

log4j.rootLogger=INFO,Stdout,R  指定INFO及以上级别的日志会被输出到Stdout 和 R 两个终端

log4j.appender.Stdout=org.apache.log4j.ConsoleAppender 输出到控制台

log4j.appender.R=org.apache.log4j.DailyRollingFileAppender 指定了每天产出一个日志文件(R是自定义的)。

log4j.appender.R.File=../logs/stdout.log 指定了日志文件的路径和文件名,这样配置以后,我的日志文件就在D:\tomcat5\logs目录下。

log4j.appender.R.datePattern='.'yyyy-MM-dd'.txt' 指定了日志文件名的格式,比如8月6日的文件名就是stdout.log.2011-08-06.txt。

                                                         经过测试发现,当天的日志会被暂存在名为 stdout.log的日志文件中,只有日期更迭以后才会自动变更为符合

                                                         格式的文件名。

续:

经过试验, 如果在tomcat下有两个应用A和B,A如上述一般配置,B中未配置,但B的lib中有log4j的jar包,那么在tomcat启动时可能会报一个堆栈溢出的异常。

原因是在tomcat启动时,B程序中的log4j包会用到System.out.println(),而这个System.out.println()会被A的StdoutListener监听到而引发死循环调用。至于为什么A中的监听器会监听到B中的调用,还不清楚。

暂时的解决办法:在B中也做上述配置,引入StdoutListener,编写log4j.properties。

免责声明:文章转载自《把在程序中的System.out.print()的信息自动转成log4j日志信息》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇PELCOD与PELCOP协议介绍综合概括-中国制造 2025下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Android 关机问题快速定位

极力推荐文章:欢迎收藏Android 干货分享 本篇文章主要介绍 Android 开发中的 关机 部分知识点,通过阅读本篇文章,您将收获以下内容: 1 . 确认是亮屏关机还是灭屏关机?关机时是否有播放关机动画? 2 . 是直接关机还是关机后会自动重启? 3.异常关机时,连上uart线是否可以吐log?插上usb后是否能显示关机充电动画? 4 . 如果按...

2018-2019-2 20175126谢文航 实验三《敏捷开发与XP实践》实验报告

一、实验报告封面 课程:Java程序设计 班级:1751 班 姓名:谢文航 学号:20175126 指导教师:娄嘉鹏 实验日期:2019年5月2日 实验时间:--- 实验序号:实验三 实验名称:敏捷开发与XP实践 实验内容 1. XP基础 2. XP核心实践 3. 相关工具 实验要求 1.没有Linux基础的同学建议先学习《Linux基础入门(新版)》...

TR2021_0000偶发数据库连接异常问题排查

【问题描述】 数据库连接异常是很难排查的一类问题。因为它牵涉到应用端,网络层和服务器端。任何一个组件异常,都会导致数据库连接失败。开发遇到数据库连接不上的问题,都会第一时间找DBA来协助查看,DBA除了需要懂得数据库以外,还需要对应用,对网络有所了解,知道在哪里看应用程序的日志,以及看网络交换机性能指标,才能清晰的定位问题。下面是一个数据库偶发连接不上的例...

.net连接SAP的几种方式

  .net连接SAP的几种方式 一、 SAP .net connector 这是SAP专为.net连接开发的一个工具,简单方便,但是只支持VS2003.当然想在VS2003以上的版本使用可以选择在VS2003上包装下再用。 使用方法: 1.首先安装SAP .net connector,一路next即可 2.打开VS2003,新建一个项目,打开s...

android adb push 与 adb install 区别(两种安装APK的方法)

一般的,Android 应用程序有两种安装方法:1. 将应用程序的apk文件push到手机中,用如下命令:adb push xxxx.apk /system/app.2. 用adb install xxxx.apk进行安装3. 二者的比较以及注意事项:1) 用第一种方式的弊端:a. 会将原来系统中的对应的apk覆盖掉,所以,最好先备份出来一份,用如下命令:...

C# 编写Windows Service(windows服务程序)(摘抄)

  C# 编写Windows Service(windows服务程序)   Windows Service简介: 一个Windows服务程序是在Windows操作系统下能完成特定功能的可执行的应用程序。Windows服务程序虽然是可执行的,但是它不像一般的可执行文件通过双击就能开始运行了,它必须有特定的启动方式。这些启动方式包括了自动启动和手动启动两...