我有一个使用log4j Java应用程序。
配置:
log4j.rootLogger=info, file
log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.File=${user.home}/logs/app.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d [%t] %c %p %m%n
因此,所有的日志语句正确添加到文件,但我失去了输出和错误。 我怎么重定向异常堆栈跟踪和sysouts日常冷轧文件?
Answer 1:
// I set up a ConsoleAppender in Log4J to format Stdout/Stderr
log4j.rootLogger=DEBUG, CONSOLE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[%t] %-5p %c - %m%n
// And I call this StdOutErrLog.tieSystemOutAndErrToLog() on startup
public class StdOutErrLog {
private static final Logger logger = Logger.getLogger(StdOutErrLog.class);
public static void tieSystemOutAndErrToLog() {
System.setOut(createLoggingProxy(System.out));
System.setErr(createLoggingProxy(System.err));
}
public static PrintStream createLoggingProxy(final PrintStream realPrintStream) {
return new PrintStream(realPrintStream) {
public void print(final String string) {
realPrintStream.print(string);
logger.info(string);
}
};
}
}
Answer 2:
在Skaffman代码:要删除空行中log4j的日志,只需添加“的println”的方法来createLoggingProxy的为PrintStream
public static PrintStream createLoggingProxy(final PrintStream realPrintStream) {
return new PrintStream(realPrintStream) {
public void print(final String string) {
logger.warn(string);
}
public void println(final String string) {
logger.warn(string);
}
};
}
Answer 3:
我从迈克尔S拿起想法,但像在一个评论中提到,它也存在一些问题:它不会捕捉一切,和它打印一些空行。
此外,我想分开System.out
和System.err
,这样System.out
得到记录与日志级别'INFO'
和System.err
获取与记录的'ERROR'
(或'WARN'
,如果你喜欢)。
所以这是我的解决方案:第一类扩展OutputStream
(它更容易覆盖所有方法OutputStream
比PrintStream
)。 它记录与指定的日志级别,也都复制到另一个OutputStream
。 并且还检测到“空”字符串(空格只含),不记录他们。
import java.io.IOException;
import java.io.OutputStream;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
public class LoggerStream extends OutputStream
{
private final Logger logger;
private final Level logLevel;
private final OutputStream outputStream;
public LoggerStream(Logger logger, Level logLevel, OutputStream outputStream)
{
super();
this.logger = logger;
this.logLevel = logLevel;
this.outputStream = outputStream;
}
@Override
public void write(byte[] b) throws IOException
{
outputStream.write(b);
String string = new String(b);
if (!string.trim().isEmpty())
logger.log(logLevel, string);
}
@Override
public void write(byte[] b, int off, int len) throws IOException
{
outputStream.write(b, off, len);
String string = new String(b, off, len);
if (!string.trim().isEmpty())
logger.log(logLevel, string);
}
@Override
public void write(int b) throws IOException
{
outputStream.write(b);
String string = String.valueOf((char) b);
if (!string.trim().isEmpty())
logger.log(logLevel, string);
}
}
然后,一个非常简单的工具类,设置out
和err
:
import java.io.PrintStream;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
public class OutErrLogger
{
public static void setOutAndErrToLog()
{
setOutToLog();
setErrToLog();
}
public static void setOutToLog()
{
System.setOut(new PrintStream(new LoggerStream(Logger.getLogger("out"), Level.INFO, System.out)));
}
public static void setErrToLog()
{
System.setErr(new PrintStream(new LoggerStream(Logger.getLogger("err"), Level.ERROR, System.err)));
}
}
Answer 4:
如果您使用的是应用服务器,servlet容器或类似的东西,看到kgiannakakis的答案 。
对于独立的应用程序见本 。 您可以reassing 标准输入 , 标准输出和标准错误使用java.lang.System中的类。 基本上你创建PrintStream的一个新的子类和实例设置到System.out。
沿着你的应用程序(未经测试)的开始几行内容。
// PrintStream object that prints stuff to log4j logger
public class Log4jStream extends PrintStream {
public void write(byte buf[], int off, int len) {
try {
// write stuff to Log4J logger
} catch (Exception e) {
}
}
}
// reassign standard output to go to log4j
System.setOut(new Log4jStream());
Answer 5:
以上这些问题的答案给出一个很好的主意,使用代理服务器的标准输出/ ERR记录。 但是提供的实现例子并不适用于所有情况很好地工作。 例如,尝试
System.out.printf( “测试%S \ n”, “ABC”);
从以上实施例中的代码将削减在控制台上,并在多个不可读的Log4j条目的输出分成单独的块。
解决的办法是缓冲输出直到触发“\ n”为在缓冲器的末端发现。 有时缓冲带“\ r \ n”结束。 下面地址的类此问题。 它是功能齐全。 调用静态方法绑定()来激活它。
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
// Based on
// http://stackoverflow.com/questions/1200175/log4j-redirect-stdout-to-dailyrollingfileappender
public class Log4jStdOutErrProxy {
public static void bind() {
bind(Logger.getLogger("STDOUT"), Logger.getLogger("STDERR"));
}
@SuppressWarnings("resource")
public static void bind(Logger loggerOut, Logger loggerErr) {
System.setOut(new PrintStream(new LoggerStream(loggerOut, Level.INFO, System.out), true));
System.setErr(new PrintStream(new LoggerStream(loggerErr, Level.ERROR, System.err), true));
}
private static class LoggerStream extends OutputStream {
private final Logger logger;
private final Level logLevel;
private final OutputStream outputStream;
private StringBuilder sbBuffer;
public LoggerStream(Logger logger, Level logLevel, OutputStream outputStream) {
this.logger = logger;
this.logLevel = logLevel;
this.outputStream = outputStream;
sbBuffer = new StringBuilder();
}
@Override
public void write(byte[] b) throws IOException {
doWrite(new String(b));
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
doWrite(new String(b, off, len));
}
@Override
public void write(int b) throws IOException {
doWrite(String.valueOf((char)b));
}
private void doWrite(String str) throws IOException {
sbBuffer.append(str);
if (sbBuffer.charAt(sbBuffer.length() - 1) == '\n') {
// The output is ready
sbBuffer.setLength(sbBuffer.length() - 1); // remove '\n'
if (sbBuffer.charAt(sbBuffer.length() - 1) == '\r') {
sbBuffer.setLength(sbBuffer.length() - 1); // remove '\r'
}
String buf = sbBuffer.toString();
sbBuffer.setLength(0);
outputStream.write(buf.getBytes());
outputStream.write('\n');
logger.log(logLevel, buf);
}
}
} // inner class LoggerStream
}
Answer 6:
我相信您是通过登录踪迹e.printStackTrace()
你可以传递一个异常对象到Log4j的记录方法和那些会出现在你的日志(请参阅Logger.error(obj对象,Throwable的T) )
请注意,你可以改变System.out和System.err的另一个PrintStream的一个重定向到的Log4j。 这将是一个简单的变化,并节省您将所有System.out.println()
语句。
Answer 7:
标准输出和错误流从容器管理。 例如Tomcat使用巨力以记录输出和错误流。
我的建议是要离开这些,因为它是。 避免在您的应用程序是System.out.print使用。 见这里的堆栈跟踪。
Answer 8:
@迈克尔的雁是一个很好的点。 但延长的PrintStream是不是很好,因为它采用的是内部方法void write(String)
,以万物写入的OutputStream。
我更喜欢使用LoggingOutputStream
类从Log4J的包的Contrib。
然后,我重定向这样的系统流:
public class SysStreamsLogger {
private static Logger sysOutLogger = Logger.getLogger("SYSOUT");
private static Logger sysErrLogger = Logger.getLogger("SYSERR");
public static final PrintStream sysout = System.out;
public static final PrintStream syserr = System.err;
public static void bindSystemStreams() {
// Enable autoflush
System.setOut(new PrintStream(new LoggingOutputStream(sysOutLogger, LogLevel.INFO), true));
System.setErr(new PrintStream(new LoggingOutputStream(sysErrLogger, LogLevel.ERROR), true));
}
public static void unbindSystemStreams() {
System.setOut(sysout);
System.setErr(syserr);
}
}
Answer 9:
使用System.setOut还是System.setErr方法之前,我们应该使用reset()方法重置java.util.logging.LogManager中的对象。
public static void tieSystemOutAndErrToLog() {
try{
// initialize logging to go to rolling log file
LogManager logManager = LogManager.getLogManager();
logManager.reset();
// and output on the original stdout
System.out.println("Hello on old stdout");
System.setOut(createLoggingProxy(System.out));
System.setErr(createLoggingProxy(System.err));
//Following is to make sure whether system.out and system.err is redirecting to the stdlog.log file
System.out.println("Hello world!");
try {
throw new RuntimeException("Test");
} catch (Exception e) {
e.printStackTrace();
}
}catch(Exception e){
logger.error("Caught exception at StdOutErrLog ",e);
e.printStackTrace();
}
}
文章来源: log4j redirect stdout to DailyRollingFileAppender