Save This Page
Home » slf4j-1.5.5 » org.apache » log4j » [javadoc | source]
    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    * 
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    * 
   11    * Unless required by applicable law or agreed to in writing, software
   12    * distributed under the License is distributed on an "AS IS" BASIS,
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    * See the License for the specific language governing permissions and
   15    * limitations under the License.
   16    */
   17   
   18   package org.apache.log4j;
   19   
   20   import java.io.IOException;
   21   import java.io.Writer;
   22   import java.io.OutputStream;
   23   import java.io.OutputStreamWriter;
   24   
   25   import org.apache.log4j.spi.ErrorHandler;
   26   import org.apache.log4j.spi.LoggingEvent;
   27   import org.apache.log4j.helpers.QuietWriter;
   28   import org.apache.log4j.helpers.LogLog;
   29   
   30   // Contibutors: Jens Uwe Pipka <jens.pipka@gmx.de>
   31   //              Ben Sandee
   32   
   33   /**
   34      WriterAppender appends log events to a {@link java.io.Writer} or an
   35      {@link java.io.OutputStream} depending on the user's choice.
   36   
   37      @author Ceki G&uuml;lc&uuml;
   38      @since 1.1 */
   39   public class WriterAppender extends AppenderSkeleton {
   40   
   41   
   42     /**
   43        Immediate flush means that the underlying writer or output stream
   44        will be flushed at the end of each append operation. Immediate
   45        flush is slower but ensures that each append request is actually
   46        written. If <code>immediateFlush</code> is set to
   47        <code>false</code>, then there is a good chance that the last few
   48        logs events are not actually written to persistent media if and
   49        when the application crashes.
   50   
   51        <p>The <code>immediateFlush</code> variable is set to
   52        <code>true</code> by default.
   53   
   54     */
   55     protected boolean immediateFlush = true;
   56   
   57     /**
   58        The encoding to use when writing.  <p>The
   59        <code>encoding</code> variable is set to <code>null</null> by
   60        default which results in the utilization of the system's default
   61        encoding.  */
   62     protected String encoding;
   63   
   64     /**
   65        This is the {@link QuietWriter quietWriter} where we will write
   66        to.
   67     */
   68     protected QuietWriter qw;
   69   
   70   
   71     /**
   72        This default constructor does nothing.  */
   73     public
   74     WriterAppender() {
   75     }
   76   
   77     /**
   78        Instantiate a WriterAppender and set the output destination to a
   79        new {@link OutputStreamWriter} initialized with <code>os</code>
   80        as its {@link OutputStream}.  */
   81     public
   82     WriterAppender(Layout layout, OutputStream os) {
   83       this(layout, new OutputStreamWriter(os));
   84     }
   85   
   86     /**
   87        Instantiate a WriterAppender and set the output destination to
   88        <code>writer</code>.
   89   
   90        <p>The <code>writer</code> must have been previously opened by
   91        the user.  */
   92     public
   93     WriterAppender(Layout layout, Writer writer) {
   94       this.layout = layout;
   95       this.setWriter(writer);
   96     }
   97   
   98     /**
   99        If the <b>ImmediateFlush</b> option is set to
  100        <code>true</code>, the appender will flush at the end of each
  101        write. This is the default behavior. If the option is set to
  102        <code>false</code>, then the underlying stream can defer writing
  103        to physical medium to a later time.
  104   
  105        <p>Avoiding the flush operation at the end of each append results in
  106        a performance gain of 10 to 20 percent. However, there is safety
  107        tradeoff involved in skipping flushing. Indeed, when flushing is
  108        skipped, then it is likely that the last few log events will not
  109        be recorded on disk when the application exits. This is a high
  110        price to pay even for a 20% performance gain.
  111      */
  112     public
  113     void setImmediateFlush(boolean value) {
  114       immediateFlush = value;
  115     }
  116   
  117     /**
  118        Returns value of the <b>ImmediateFlush</b> option.
  119      */
  120     public
  121     boolean getImmediateFlush() {
  122       return immediateFlush;
  123     }
  124   
  125     /**
  126        Does nothing.
  127     */
  128     public
  129     void activateOptions() {
  130     }
  131   
  132   
  133     /**
  134        This method is called by the {@link AppenderSkeleton#doAppend}
  135        method.
  136   
  137        <p>If the output stream exists and is writable then write a log
  138        statement to the output stream. Otherwise, write a single warning
  139        message to <code>System.err</code>.
  140   
  141        <p>The format of the output will depend on this appender's
  142        layout.
  143   
  144     */
  145     public
  146     void append(LoggingEvent event) {
  147   
  148       // Reminder: the nesting of calls is:
  149       //
  150       //    doAppend()
  151       //      - check threshold
  152       //      - filter
  153       //      - append();
  154       //        - checkEntryConditions();
  155       //        - subAppend();
  156   
  157       if(!checkEntryConditions()) {
  158         return;
  159       }
  160       subAppend(event);
  161      }
  162   
  163     /**
  164        This method determines if there is a sense in attempting to append.
  165   
  166        <p>It checks whether there is a set output target and also if
  167        there is a set layout. If these checks fail, then the boolean
  168        value <code>false</code> is returned. */
  169     protected
  170     boolean checkEntryConditions() {
  171       if(this.closed) {
  172         LogLog.warn("Not allowed to write to a closed appender.");
  173         return false;
  174       }
  175   
  176       if(this.qw == null) {
  177         errorHandler.error("No output stream or file set for the appender named ["+
  178   			name+"].");
  179         return false;
  180       }
  181   
  182       if(this.layout == null) {
  183         errorHandler.error("No layout set for the appender named ["+ name+"].");
  184         return false;
  185       }
  186       return true;
  187     }
  188   
  189   
  190     /**
  191        Close this appender instance. The underlying stream or writer is
  192        also closed.
  193   
  194        <p>Closed appenders cannot be reused.
  195   
  196        @see #setWriter
  197        @since 0.8.4 */
  198     public
  199     synchronized
  200     void close() {
  201       if(this.closed)
  202         return;
  203       this.closed = true;
  204       writeFooter();
  205       reset();
  206     }
  207   
  208     /**
  209      * Close the underlying {@link java.io.Writer}.
  210      * */
  211     protected void closeWriter() {
  212       if(qw != null) {
  213         try {
  214   	qw.close();
  215         } catch(IOException e) {
  216   	// There is do need to invoke an error handler at this late
  217   	// stage.
  218   	LogLog.error("Could not close " + qw, e);
  219         }
  220       }
  221     }
  222   
  223     /**
  224        Returns an OutputStreamWriter when passed an OutputStream.  The
  225        encoding used will depend on the value of the
  226        <code>encoding</code> property.  If the encoding value is
  227        specified incorrectly the writer will be opened using the default
  228        system encoding (an error message will be printed to the loglog.  */
  229     protected
  230     OutputStreamWriter createWriter(OutputStream os) {
  231       OutputStreamWriter retval = null;
  232   
  233       String enc = getEncoding();
  234       if(enc != null) {
  235         try {
  236   	retval = new OutputStreamWriter(os, enc);
  237         } catch(IOException e) {
  238   	LogLog.warn("Error initializing output writer.");
  239   	LogLog.warn("Unsupported encoding?");
  240         }
  241       }
  242       if(retval == null) {
  243         retval = new OutputStreamWriter(os);
  244       }
  245       return retval;
  246     }
  247   
  248     public String getEncoding() {
  249       return encoding;
  250     }
  251   
  252     public void setEncoding(String value) {
  253       encoding = value;
  254     }
  255   
  256   
  257   
  258   
  259     /**
  260        Set the {@link ErrorHandler} for this WriterAppender and also the
  261        underlying {@link QuietWriter} if any. */
  262     public synchronized void setErrorHandler(ErrorHandler eh) {
  263       if(eh == null) {
  264         LogLog.warn("You have tried to set a null error-handler.");
  265       } else {
  266         this.errorHandler = eh;
  267         if(this.qw != null) {
  268   	this.qw.setErrorHandler(eh);
  269         }
  270       }
  271     }
  272   
  273     /**
  274       <p>Sets the Writer where the log output will go. The
  275       specified Writer must be opened by the user and be
  276       writable.
  277   
  278       <p>The <code>java.io.Writer</code> will be closed when the
  279       appender instance is closed.
  280   
  281   
  282       <p><b>WARNING:</b> Logging to an unopened Writer will fail.
  283       <p>
  284       @param writer An already opened Writer.  */
  285     public synchronized void setWriter(Writer writer) {
  286       reset();
  287       this.qw = new QuietWriter(writer, errorHandler);
  288       //this.tp = new TracerPrintWriter(qw);
  289       writeHeader();
  290     }
  291   
  292   
  293     /**
  294        Actual writing occurs here.
  295   
  296        <p>Most subclasses of <code>WriterAppender</code> will need to
  297        override this method.
  298   
  299        @since 0.9.0 */
  300     protected
  301     void subAppend(LoggingEvent event) {
  302       this.qw.write(this.layout.format(event));
  303   
  304       if(layout.ignoresThrowable()) {
  305         String[] s = event.getThrowableStrRep();
  306         if (s != null) {
  307   	int len = s.length;
  308   	for(int i = 0; i < len; i++) {
  309   	  this.qw.write(s[i]);
  310   	  this.qw.write(Layout.LINE_SEP);
  311   	}
  312         }
  313       }
  314   
  315       if(this.immediateFlush) {
  316         this.qw.flush();
  317       }
  318     }
  319   
  320   
  321   
  322     /**
  323        The WriterAppender requires a layout. Hence, this method returns
  324        <code>true</code>.
  325     */
  326     public
  327     boolean requiresLayout() {
  328       return true;
  329     }
  330   
  331     /**
  332        Clear internal references to the writer and other variables.
  333   
  334        Subclasses can override this method for an alternate closing
  335        behavior.  */
  336     protected
  337     void reset() {
  338       closeWriter();
  339       this.qw = null;
  340       //this.tp = null;
  341     }
  342   
  343   
  344     /**
  345        Write a footer as produced by the embedded layout's {@link
  346        Layout#getFooter} method.  */
  347     protected
  348     void writeFooter() {
  349       if(layout != null) {
  350         String f = layout.getFooter();
  351         if(f != null && this.qw != null) {
  352   	this.qw.write(f);
  353   	this.qw.flush();
  354         }
  355       }
  356     }
  357   
  358     /**
  359        Write a header as produced by the embedded layout's {@link
  360        Layout#getHeader} method.  */
  361     protected
  362     void writeHeader() {
  363       if(layout != null) {
  364         String h = layout.getHeader();
  365         if(h != null && this.qw != null)
  366   	this.qw.write(h);
  367       }
  368     }
  369   }

Save This Page
Home » slf4j-1.5.5 » org.apache » log4j » [javadoc | source]