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

ch.qos.logback.core.WriterAppender Maven / Gradle / Ivy

The newest version!
/**
 * Logback: the reliable, generic, fast and flexible logging framework.
 * Copyright (C) 1999-2009, QOS.ch. All rights reserved.
 *
 * This program and the accompanying materials are dual-licensed under
 * either the terms of the Eclipse Public License v1.0 as published by
 * the Eclipse Foundation
 *
 *   or (per the licensee's choosing)
 *
 * under the terms of the GNU Lesser General Public License version 2.1
 * as published by the Free Software Foundation.
 */
package ch.qos.logback.core;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;

import ch.qos.logback.core.status.ErrorStatus;

/**
 * WriterAppender appends events to a hava.io.Writer. This class provides basic
 * services that other appenders build upon.
 * 
 * For more information about this appender, please refer to the online manual
 * at http://logback.qos.ch/manual/appenders.html#WriterAppender
 * 
 * @author Ceki Gülcü
 */
public class WriterAppender extends UnsynchronizedAppenderBase {

  /**
   * Immediate flush means that the underlying writer or output stream will be
   * flushed at the end of each append operation. Immediate flush is slower but
   * ensures that each append request is actually written. If
   * immediateFlush is set to false, then there
   * is a good chance that the last few logs events are not actually written to
   * persistent media if and when the application crashes.
   * 
   * 

* The immediateFlush variable is set to true by * default. */ private boolean immediateFlush = true; /** * The encoding to use when opening an InputStream. *

* The encoding variable is set to null by default * which results in the use of the system's default encoding. */ private String encoding; /** * This is the {@link Writer Writer} where we will write to. */ private Writer writer; /** * The default constructor does nothing. */ public WriterAppender() { } /** * If the ImmediateFlush option is set to true, the * appender will flush at the end of each write. This is the default behavior. * If the option is set to false, then the underlying stream * can defer writing to physical medium to a later time. *

* Avoiding the flush operation at the end of each append results in a * performance gain of 10 to 20 percent. However, there is safety tradeoff * involved in skipping flushing. Indeed, when flushing is skipped, then it is * likely that the last few log events will not be recorded on disk when the * application exits. This is a high price to pay even for a 20% performance * gain. */ public void setImmediateFlush(boolean value) { immediateFlush = value; } /** * Returns value of the ImmediateFlush option. */ public boolean getImmediateFlush() { return immediateFlush; } /** * Checks that requires parameters are set and if everything is in order, * activates this appender. */ public void start() { int errors = 0; if (this.layout == null) { addStatus(new ErrorStatus("No layout set for the appender named \"" + name + "\".", this)); errors++; } if (this.writer == null) { addStatus(new ErrorStatus("No writer set for the appender named \"" + name + "\".", this)); errors++; } // only error free appenders should be activated if (errors == 0) { super.start(); } } @Override protected void append(E eventObject) { if (!isStarted()) { return; } subAppend(eventObject); } /** * Stop this appender instance. The underlying stream or writer is also * closed. * *

* Stopped appenders cannot be reused. */ public synchronized void stop() { closeWriter(); super.stop(); } /** * Close the underlying {@link java.io.Writer}. */ protected void closeWriter() { if (this.writer != null) { try { // before closing we have to output out layout's footer writeFooter(); this.writer.close(); this.writer = null; } catch (IOException e) { addStatus(new ErrorStatus("Could not close writer for WriterAppener.", this, e)); } } } /** * Returns an OutputStreamWriter when passed an OutputStream. The encoding * used will depend on the value of the encoding property. If * the encoding value is specified incorrectly the writer will be opened using * the default system encoding (an error message will be printed to the * loglog. */ protected OutputStreamWriter createWriter(OutputStream os) { OutputStreamWriter retval = null; String enc = getEncoding(); try { if (enc != null) { retval = new OutputStreamWriter(os, enc); } else { retval = new OutputStreamWriter(os); } } catch (IOException e) { addStatus(new ErrorStatus("Error initializing output writer.", this, e)); if (enc != null) { addStatus(new ErrorStatus("Unsupported encoding?", this)); } } return retval; } public String getEncoding() { return encoding; } public void setEncoding(String value) { encoding = value; } void writeHeader() { if (layout != null && (this.writer != null)) { try { StringBuilder sb = new StringBuilder(); appendIfNotNull(sb, layout.getFileHeader()); appendIfNotNull(sb, layout.getPresentationHeader()); if (sb.length() > 0) { sb.append(CoreConstants.LINE_SEPARATOR); // If at least one of file header or presentation header were not // null, then append a line separator. // This should be useful in most cases and should not hurt. writerWrite(sb.toString(), true); } } catch (IOException ioe) { this.started = false; addStatus(new ErrorStatus("Failed to write header for appender named [" + name + "].", this, ioe)); } } } private void appendIfNotNull(StringBuilder sb, String s) { if (s != null) { sb.append(s); } } void writeFooter() { if (layout != null && this.writer != null) { try { StringBuilder sb = new StringBuilder(); appendIfNotNull(sb, layout.getPresentationFooter()); appendIfNotNull(sb, layout.getFileFooter()); if (sb.length() > 0) { writerWrite(sb.toString(), true); // force flush } } catch (IOException ioe) { this.started = false; addStatus(new ErrorStatus("Failed to write footer for appender named [" + name + "].", this, ioe)); } } } /** *

* Sets the Writer where the log output will go. The specified Writer must be * opened by the user and be writable. The java.io.Writer will * be closed when the appender instance is closed. * * @param writer * An already opened Writer. */ public synchronized void setWriter(Writer writer) { // close any previously opened writer closeWriter(); this.writer = writer; writeHeader(); } protected void writerWrite(String s, boolean flush) throws IOException { this.writer.write(s); if (flush) { this.writer.flush(); } } /** * Actual writing occurs here. *

* Most subclasses of WriterAppender will need to override this * method. * * @since 0.9.0 */ protected void subAppend(E event) { if (!isStarted()) { return; } try { String output = this.layout.doLayout(event); synchronized (this) { writerWrite(output, this.immediateFlush); } } catch (IOException ioe) { // as soon as an exception occurs, move to non-started state // and add a single ErrorStatus to the SM. this.started = false; addStatus(new ErrorStatus("IO failure in appender", this, ioe)); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy