web-dev-qa-db-ja.com

System.outとSystem.errをslf4jにリダイレクトします

System.out /err.printlnの出力をslf4jにリダイレクトする必要がありました。

これが適切にログを記録する方法ではないことを私は知っていますしかし、System.outにログを記録する外部ライブラリがあります

25
itshorty

sysout-over-slf4j を使用できます。

Sysout-over-slf4jモジュールを使用すると、ユーザーはSystem.outおよびSystem.errへのすべての呼び出しを、System.out.println(または同様の)呼び出しが行われた完全修飾クラスの名前を持つSLF4J定義のロガーにリダイレクトできます。 、構成可能なレベルで。

Mavenを使用していない場合は、 ダウンロード jarを使用してクラスパスに追加します。

または、Maven依存関係として追加します。

<dependency>
    <groupId>uk.org.lidalia</groupId>
    <artifactId>sysout-over-slf4j</artifactId>
    <version>1.0.2</version>
</dependency>

次に、アプリケーションの起動時に、 call

SysOutOverSLF4J.sendSystemOutAndErrToSLF4J();
17
flavio.donze

Log4jでは LoggingOutputStream を使用して問題を解決し、slf4jでは少し変更しました。

_import Java.io.IOException;
import Java.io.PrintStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SysStreamsLogger {
private static Logger sysOutLogger = LoggerFactory.getLogger("SYSOUT");
private static Logger sysErrLogger = LoggerFactory.getLogger("SYSERR");

public static final PrintStream sysout = System.out;
public static final PrintStream syserr = System.err;

protected static final String LINE_SEPERATOR = System.getProperty("line.separator");

public static void bindSystemStreams() {
    // Enable autoflush
    System.setOut(new PrintStream(new LoggingOutputStream(sysOutLogger, false), true));
    System.setErr(new PrintStream(new LoggingOutputStream(sysErrLogger, true), true));
}

public static void unbindSystemStreams() {
    System.setOut(sysout);
    System.setErr(syserr);
}

private static class LoggingOutputStream extends Java.io.OutputStream {

    protected Logger log;
    protected boolean isError;

    /**
     * Used to maintain the contract of {@link #close()}.
     */
    protected boolean hasBeenClosed = false;

    /**
     * The internal buffer where data is stored.
     */
    protected byte[] buf;

    /**
     * The number of valid bytes in the buffer. This value is always in the
     * range <tt>0</tt> through <tt>buf.length</tt>; elements
     * <tt>buf[0]</tt> through <tt>buf[count-1]</tt> contain valid byte
     * data.
     */
    protected int count;

    /**
     * Remembers the size of the buffer for speed.
     */
    private int bufLength;

    /**
     * The default number of bytes in the buffer. =2048
     */
    public static final int DEFAULT_BUFFER_LENGTH = 2048;

    private LoggingOutputStream() {
        // illegal
    }

    /**
     * Creates the LoggingOutputStream to flush to the given Category.
     * 
     * @param log
     *            the Logger to write to
     * 
     * @param isError
     *            the if true write to error, else info
     * 
     * @exception IllegalArgumentException
     *                if cat == null or priority == null
     */
    public LoggingOutputStream(Logger log, boolean isError) throws IllegalArgumentException {
        if (log == null) {
            throw new IllegalArgumentException("log == null");
        }

        this.isError = isError;
        this.log = log;
        bufLength = DEFAULT_BUFFER_LENGTH;
        buf = new byte[DEFAULT_BUFFER_LENGTH];
        count = 0;
    }

    /**
     * Closes this output stream and releases any system resources
     * associated with this stream. The general contract of
     * <code>close</code> is that it closes the output stream. A closed
     * stream cannot perform output operations and cannot be reopened.
     */
    @Override
    public void close() {
        flush();
        hasBeenClosed = true;
    }

    /**
     * Writes the specified byte to this output stream. The general contract
     * for <code>write</code> is that one byte is written to the output
     * stream. The byte to be written is the eight low-order bits of the
     * argument <code>b</code>. The 24 high-order bits of <code>b</code> are
     * ignored.
     * 
     * @param b
     *            the <code>byte</code> to write
     */
    @Override
    public void write(final int b) throws IOException {
        if (hasBeenClosed) {
            throw new IOException("The stream has been closed.");
        }

        // don't log nulls
        if (b == 0) {
            return;
        }

        // would this be writing past the buffer?
        if (count == bufLength) {
            // grow the buffer
            final int newBufLength = bufLength + DEFAULT_BUFFER_LENGTH;
            final byte[] newBuf = new byte[newBufLength];

            System.arraycopy(buf, 0, newBuf, 0, bufLength);

            buf = newBuf;
            bufLength = newBufLength;
        }

        buf[count] = (byte) b;
        count++;
    }

    /**
     * Flushes this output stream and forces any buffered output bytes to be
     * written out. The general contract of <code>flush</code> is that
     * calling it is an indication that, if any bytes previously written
     * have been buffered by the implementation of the output stream, such
     * bytes should immediately be written to their intended destination.
     */
    @Override
    public void flush() {

        if (count == 0) {
            return;
        }

        // don't print out blank lines; flushing from PrintStream puts out
        // these
        if (count == LINE_SEPERATOR.length()) {
            if (((char) buf[0]) == LINE_SEPERATOR.charAt(0) && ((count == 1) || // <-
                                                                                // Unix
                                                                                // &
                                                                                // Mac,
                                                                                // ->
                                                                                // Windows
                    ((count == 2) && ((char) buf[1]) == LINE_SEPERATOR.charAt(1)))) {
                reset();
                return;
            }
        }

        final byte[] theBytes = new byte[count];

        System.arraycopy(buf, 0, theBytes, 0, count);

        if (isError) {
            log.error(new String(theBytes));
        } else {
            log.info(new String(theBytes));
        }

        reset();
    }

    private void reset() {
        // not resetting the buffer -- assuming that if it grew that it
        // will likely grow similarly again
        count = 0;
    }
}
}
_

これで、アプリケーションの開始時にSysStreamsLogger.bindSystemStreams()を呼び出すことにより、Sytem.out/errをリダイレクトすることができます。

ロギング出力は次のようになります(OpenEJBスタートアップから)

_2012-06-27 13:44:12,792  INFO [main:] SYSOUT:181 - Apache OpenEJB 3.1.4    build: 20101112-03:32
2012-06-27 13:44:12,793  INFO [main:] SYSOUT:181 - http://openejb.Apache.org/
_
22
itshorty