如何将sysout和syserr重定向到java中的自定义记录器?
我有一个自定义记录器,我想将所有sysout和syserr从控制台重定向到该自定义记录器。因此,我想通过以下方式重定向sysout和syserr:如何将sysout和syserr重定向到java中的自定义记录器?,java,logging,Java,Logging,我有一个自定义记录器,我想将所有sysout和syserr从控制台重定向到该自定义记录器。因此,我想通过以下方式重定向sysout和syserr: 通过扩展ByteArrayOutputStream 然后设置System.setErr和System.setOut public class ServerLoggingPrintStream extends ByteArrayOutputStream { public ServerLoggingPrintStream() {
- 通过扩展ByteArrayOutputStream
- 然后设置System.setErr和System.setOut
public class ServerLoggingPrintStream extends ByteArrayOutputStream { public ServerLoggingPrintStream() { super(); } public void write(byte[] originalBytes, int originalOffset, int originalLength) { synchronized(this) { String str = new String(originalBytes); if (str.length() == 0 || str.equals(System.getProperty("line.separator")) ) { return; } //using my custom logger named TRACE_LOGGER TRACE_LOGGER.log(LogLevel.INFO, this, "write", str); } } } ServerLoggingPrintStream serverLoggingPrintStreamStdOut_ = null; ServerLoggingPrintStream serverLoggingPrintStreamStdErr_ = null; serverLoggingPrintStreamStdErr_ = new ServerLoggingPrintStream(); System.setErr(new PrintStream(serverLoggingPrintStreamStdErr_)); serverLoggingPrintStreamStdOut_ = new ServerLoggingPrintStream(); System.setOut(new PrintStream(serverLoggingPrintStreamStdOut_));
你认为有更好的方法吗?要把它做好比这更复杂。也就是说,有一些开源项目已经做到了这一点,所以您可以从那里借用一些代码。这里有一个例子:
我会使用一个OutputStream重定向到您使用的日志框架。它相当容易实现(我假设字符集是ISO的,所以编码时没有特别的处理):
这是它的要点,但是对于日志框架,细节可能会有所不同。主要的问题是,记录器通常希望记录字符串,而您从重定向流中获得原始的编码字节,因此您必须反转编码(在本例中,通过原始转换,技术上这应该使用读取器完成).更好的方法是首先避免使用System.err和System.out。更好的方法是使用Java可用的众多健壮且经验证的日志框架之一,而不是使用自己的。例如,如果要使用
slf4j
,则存在一个。您使用的解决方案已经足够好了。已经有了一个日志框架。这个框架没有提供重定向sysout和syserr的方法。目前,我没有选择替换现有的日志框架。它是什么框架?嗨,这种方法的优势是什么?它通过实现一个流来收集数据,直到行馈送,然后将数据转发给日志记录器。关键是它需要最少的实现(通过直接从OutputStream继承,您已经为所有方法获得了正常工作的默认实现)。它和你的没有太大的不同,只是它覆盖了漏洞(有3种不同的写方法,你只实现了一种)。它比我提出的方法有什么优势?Hi Yishai,需要处理什么情况?@Baishak,你可以在链接上看到代码(或者寻找类的更高版本)。代码处理的一个问题是PrintStream希望您发送自己的新行,而日志框架通常不这样做,导致到处都是空行。我可以理解这一点。但我不明白的是,为什么他们需要使用ThreadLocalRecursiveCheck。我们可以检查是否有一个字符串,它是新行还是空行,我们就完成了。是吗?@baishak,我想象的递归检查是防御性的,以防注册码被调用两次(因此,当您传入当前System.out或System.err时,您实际上传入了这个类)。您必须测试您的实现,但是使用这样一个项目中的现有代码的优点是它经过了良好的测试。
final class RedirectionOutputStream extends OutputStream {
StringBuilder buffer = new StringBuilder();
@Override
public synchronized void write(final int b) throws IOException {
final char c = (char) (b & 0xFF);
buffer.append(c);
if (c == '\n') {
// send buffered data to logging framework (its a complete line now)
// reset buffer
buffer.setLength(0);
}
}
}