+++ /dev/null
-/*
- * 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.
- */
-
-package org.apache.log4j;
-
-import java.io.IOException;
-import java.io.InterruptedIOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-
-import org.apache.log4j.helpers.LogLog;
-import org.apache.log4j.helpers.QuietWriter;
-import org.apache.log4j.spi.ErrorHandler;
-import org.apache.log4j.spi.LoggingEvent;
-
-// Contibutors: Jens Uwe Pipka <jens.pipka@gmx.de>
-// Ben Sandee
-
-/**
- WriterAppender appends log events to a {@link java.io.Writer} or an
- {@link java.io.OutputStream} depending on the user's choice.
-
- @author Ceki Gülcü
- @since 1.1 */
-public class WriterAppender extends AppenderSkeleton {
-
-
- /**
- Immediate flush means that the underlying writer or output stream
- will be flushed at the end of each append operation unless shouldFlush()
- is overridden. Immediate
- flush is slower but ensures that each append request is actually
- written. If <code>immediateFlush</code> is set to
- <code>false</code>, 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.
-
- <p>The <code>immediateFlush</code> variable is set to
- <code>true</code> by default.
-
- */
- protected boolean immediateFlush = true;
-
- /**
- The encoding to use when writing. <p>The
- <code>encoding</code> variable is set to <code>null</null> by
- default which results in the utilization of the system's default
- encoding. */
- protected String encoding;
-
- /**
- This is the {@link QuietWriter quietWriter} where we will write
- to.
- */
- protected QuietWriter qw;
-
-
- /**
- This default constructor does nothing. */
- public
- WriterAppender() {
- }
-
- /**
- Instantiate a WriterAppender and set the output destination to a
- new {@link OutputStreamWriter} initialized with <code>os</code>
- as its {@link OutputStream}. */
- public
- WriterAppender(Layout layout, OutputStream os) {
- this(layout, new OutputStreamWriter(os));
- }
-
- /**
- Instantiate a WriterAppender and set the output destination to
- <code>writer</code>.
-
- <p>The <code>writer</code> must have been previously opened by
- the user. */
- public
- WriterAppender(Layout layout, Writer writer) {
- this.layout = layout;
- this.setWriter(writer);
- }
-
- /**
- If the <b>ImmediateFlush</b> option is set to
- <code>true</code>, the appender will flush at the end of each
- write. This is the default behavior. If the option is set to
- <code>false</code>, then the underlying stream can defer writing
- to physical medium to a later time.
-
- <p>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 <b>ImmediateFlush</b> option.
- */
- public
- boolean getImmediateFlush() {
- return immediateFlush;
- }
-
- /**
- Does nothing.
- */
- public
- void activateOptions() {
- }
-
-
- /**
- This method is called by the {@link AppenderSkeleton#doAppend}
- method.
-
- <p>If the output stream exists and is writable then write a log
- statement to the output stream. Otherwise, write a single warning
- message to <code>System.err</code>.
-
- <p>The format of the output will depend on this appender's
- layout.
-
- */
- public
- void append(LoggingEvent event) {
-
- // Reminder: the nesting of calls is:
- //
- // doAppend()
- // - check threshold
- // - filter
- // - append();
- // - checkEntryConditions();
- // - subAppend();
-
- if(!checkEntryConditions()) {
- return;
- }
- subAppend(event);
- }
-
- /**
- This method determines if there is a sense in attempting to append.
-
- <p>It checks whether there is a set output target and also if
- there is a set layout. If these checks fail, then the boolean
- value <code>false</code> is returned. */
- protected
- boolean checkEntryConditions() {
- if(this.closed) {
- LogLog.warn("Not allowed to write to a closed appender.");
- return false;
- }
-
- if(this.qw == null) {
- errorHandler.error("No output stream or file set for the appender named ["+
- name+"].");
- return false;
- }
-
- if(this.layout == null) {
- errorHandler.error("No layout set for the appender named ["+ name+"].");
- return false;
- }
- return true;
- }
-
-
- /**
- Close this appender instance. The underlying stream or writer is
- also closed.
-
- <p>Closed appenders cannot be reused.
-
- @see #setWriter
- @since 0.8.4 */
- public
- synchronized
- void close() {
- if(this.closed) {
- return;
- }
- this.closed = true;
- writeFooter();
- reset();
- }
-
- /**
- * Close the underlying {@link java.io.Writer}.
- * */
- protected void closeWriter() {
- if(qw != null) {
- try {
- qw.close();
- } catch(IOException e) {
- if (e instanceof InterruptedIOException) {
- Thread.currentThread().interrupt();
- }
- // There is do need to invoke an error handler at this late
- // stage.
- LogLog.error("Could not close " + qw, e);
- }
- }
- }
-
- /**
- Returns an OutputStreamWriter when passed an OutputStream. The
- encoding used will depend on the value of the
- <code>encoding</code> 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();
- if(enc != null) {
- try {
- retval = new OutputStreamWriter(os, enc);
- } catch(IOException e) {
- if (e instanceof InterruptedIOException) {
- Thread.currentThread().interrupt();
- }
- LogLog.warn("Error initializing output writer.");
- LogLog.warn("Unsupported encoding?");
- }
- }
- if(retval == null) {
- retval = new OutputStreamWriter(os);
- }
- return retval;
- }
-
- public String getEncoding() {
- return encoding;
- }
-
- public void setEncoding(String value) {
- encoding = value;
- }
-
-
-
-
- /**
- Set the {@link ErrorHandler} for this WriterAppender and also the
- underlying {@link QuietWriter} if any. */
- public synchronized void setErrorHandler(ErrorHandler eh) {
- if(eh == null) {
- LogLog.warn("You have tried to set a null error-handler.");
- } else {
- this.errorHandler = eh;
- if(this.qw != null) {
- this.qw.setErrorHandler(eh);
- }
- }
- }
-
- /**
- <p>Sets the Writer where the log output will go. The
- specified Writer must be opened by the user and be
- writable.
-
- <p>The <code>java.io.Writer</code> will be closed when the
- appender instance is closed.
-
-
- <p><b>WARNING:</b> Logging to an unopened Writer will fail.
- <p>
- @param writer An already opened Writer. */
- public synchronized void setWriter(Writer writer) {
- reset();
- this.qw = new QuietWriter(writer, errorHandler);
- //this.tp = new TracerPrintWriter(qw);
- writeHeader();
- }
-
-
- /**
- Actual writing occurs here.
-
- <p>Most subclasses of <code>WriterAppender</code> will need to
- override this method.
-
- @since 0.9.0 */
- protected
- void subAppend(LoggingEvent event) {
- this.qw.write(this.layout.format(event));
-
- if(layout.ignoresThrowable()) {
- String[] s = event.getThrowableStrRep();
- if (s != null) {
- int len = s.length;
- for(int i = 0; i < len; i++) {
- this.qw.write(s[i]);
- this.qw.write(Layout.LINE_SEP);
- }
- }
- }
-
- if(shouldFlush(event)) {
- this.qw.flush();
- }
- }
-
-
-
- /**
- The WriterAppender requires a layout. Hence, this method returns
- <code>true</code>.
- */
- public
- boolean requiresLayout() {
- return true;
- }
-
- /**
- Clear internal references to the writer and other variables.
-
- Subclasses can override this method for an alternate closing
- behavior. */
- protected
- void reset() {
- closeWriter();
- this.qw = null;
- //this.tp = null;
- }
-
-
- /**
- Write a footer as produced by the embedded layout's {@link
- Layout#getFooter} method. */
- protected
- void writeFooter() {
- if(layout != null) {
- String f = layout.getFooter();
- if(f != null && this.qw != null) {
- this.qw.write(f);
- this.qw.flush();
- }
- }
- }
-
- /**
- Write a header as produced by the embedded layout's {@link
- Layout#getHeader} method. */
- protected
- void writeHeader() {
- if(layout != null) {
- String h = layout.getHeader();
- if(h != null && this.qw != null) {
- this.qw.write(h);
- }
- }
- }
-
- /**
- * Determines whether the writer should be flushed after
- * this event is written.
- *
- * @since 1.2.16
- */
- protected boolean shouldFlush(final LoggingEvent event) {
- return immediateFlush;
- }
-}