All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.nitorcreations.willow.utils.LoggingOutputStream Maven / Gradle / Ivy

There is a newer version: 2.0.2
Show newest version
package com.nitorcreations.willow.utils;

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * An OutputStream that flushes out to a Logger.

* * Note that no data is written out to the Category until the stream is * flushed or closed.

* * Example:

 * // make sure everything sent to System.err is logged
 * System.setErr(new PrintStream(new LoggingOutputStream(Logger.getLogger(""), Level.WARNING), true));
 *
 * // make sure everything sent to System.out is also logged
 * System.setOut(new PrintStream(new LoggingOutputStream(Logger.getLogger(""), Level.INFO), true));
 * 
* * @author Jim Moore * @see Logger */ public class LoggingOutputStream extends OutputStream { protected static final String LINE_SEPERATOR = System.getProperty("line.separator"); /** * 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 0 through buf.length; elements * buf[0] through buf[count-1] 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. */ public static final int DEFAULT_BUFFER_LENGTH = 512; /** * The logger to write to. */ protected final Logger logger; /** * The log level to use when writing to the Category. */ protected final Level level; /** * The charset to use for strings written to this stream */ protected final Charset charset; public LoggingOutputStream() { this(Logger.getAnonymousLogger(), Level.INFO); } /** * Creates the LoggingOutputStream to flush to the given Category with the default charset * * @param logger the Logger to write to * @param level the Level to use when writing to the logger * @exception IllegalArgumentException if logger == null or level == null */ public LoggingOutputStream(Logger logger, Level level) throws IllegalArgumentException { this(logger, level, Charset.defaultCharset()); } /** * Creates the LoggingOutputStream to flush to the given Category. * * @param logger the Logger to write to * @param level the Level to use when writing to the logger * @param charset the Charset to use when interpreting written bytes * @exception IllegalArgumentException if logger == null or level == null */ public LoggingOutputStream(Logger logger, Level level, Charset charset) throws IllegalArgumentException { if (logger == null) { throw new IllegalArgumentException("logger == null"); } if (level == null) { throw new IllegalArgumentException("level == null"); } this.level = level; this.logger = logger; this.charset = charset; 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 close * 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 write is that one byte is written * to the output stream. The byte to be written is the eight * low-order bits of the argument b. The 24 * high-order bits of b are ignored. * * @param b the byte to write * * @exception IOException * if an I/O error occurs. In particular, * an IOException may be thrown if the * output stream has been closed. */ @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++; if (count >= LINE_SEPERATOR.length()) { checkLine(); } } /** * Checks if the end of the buffer contains a newline and if so, flushes the stream */ private void checkLine() { String endStr = new String(buf, count - LINE_SEPERATOR.length(), LINE_SEPERATOR.length(), charset); if (LINE_SEPERATOR.equals(endStr)) { flush(); } } /** * Flushes this output stream and forces any buffered output bytes * to be written out. The general contract of flush 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 @SuppressWarnings("PMD.UselessParentheses") public void flush() { if (count == 0) { return; } // don't print out blank lines; flushing from PrintStream puts out these if ((count == LINE_SEPERATOR.length()) && ((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); String message = new String(theBytes, charset); if (message.endsWith(LINE_SEPERATOR)) { message = message.substring(0, message.length() - LINE_SEPERATOR.length()); } logger.log(level, message); reset(); } private void reset() { // not resetting the buffer -- assuming that if it grew that it // will likely grow similarly again count = 0; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy