View Javadoc

    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  package org.apache.logging.log4j.core.appender;
    18
    19  import java.io.Serializable;
    20  import java.util.concurrent.locks.Lock;
    21  import java.util.concurrent.locks.ReadWriteLock;
    22  import java.util.concurrent.locks.ReentrantReadWriteLock;
    23
    24  import org.apache.logging.log4j.core.Filter;
    25  import org.apache.logging.log4j.core.Layout;
    26  import org.apache.logging.log4j.core.LogEvent;
    27
    28  /**
    29   * Appends log events as bytes to a byte output stream. The stream encoding is defined in the layout.
    30   *
    31   * @param <M> The kind of {@link OutputStreamManager} under management
    32   */
    33  public abstract class AbstractOutputStreamAppender<M extends OutputStreamManager> extends AbstractAppender {
    34
    35      private static final long serialVersionUID = 1L;
    36
    37      /**
    38       * Immediate flush means that the underlying writer or output stream
    39       * will be flushed at the end of each append operation. Immediate
    40       * flush is slower but ensures that each append request is actually
    41       * written. If <code>immediateFlush</code> is set to
    42       * {@code false}, then there is a good chance that the last few
    43       * logs events are not actually written to persistent media if and
    44       * when the application crashes.
    45       */
    46      protected final boolean immediateFlush;
    47
    48      private final M manager;
    49
    50      private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
    51      private final Lock readLock = rwLock.readLock();
    52
    53      /**
    54       * Instantiate a WriterAppender and set the output destination to a
    55       * new {@link java.io.OutputStreamWriter} initialized with <code>os</code>
    56       * as its {@link java.io.OutputStream}.
    57       * @param name The name of the Appender.
    58       * @param layout The layout to format the message.
    59       * @param manager The OutputStreamManager.
    60       */
    61      protected AbstractOutputStreamAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter,
    62                                             final boolean ignoreExceptions, final boolean immediateFlush,
    63                                             final M manager) {
    64          super(name, filter, layout, ignoreExceptions);
    65          this.manager = manager;
    66          this.immediateFlush = immediateFlush;
    67      }
    68
    69      /**
    70       * Gets the manager.
    71       *
    72       * @return the manager.
    73       */
    74      public M getManager() {
    75          return manager;
    76      }
    77
    78      @Override
    79      public void start() {
    80          if (getLayout() == null) {
    81              LOGGER.error("No layout set for the appender named [" + getName() + "].");
    82          }
    83          if (manager == null) {
    84              LOGGER.error("No OutputStreamManager set for the appender named [" + getName() + "].");
    85          }
    86          super.start();
    87      }
    88
    89      @Override
    90      public void stop() {
    91          super.stop();
    92          manager.release();
    93      }
    94
    95      /**
    96       * Actual writing occurs here.
    97       * <p>
    98       * Most subclasses of <code>AbstractOutputStreamAppender</code> will need to override this method.
    99       * </p>
    100      *
    101      * @param event
    102      *        The LogEvent.
    103      */
    104     @Override
    105     public void append(final LogEvent event) {
    106         readLock.lock();
    107         try {
    108             final byte[] bytes = getLayout().toByteArray(event);
    109             if (bytes.length > 0) {
    110                 manager.write(bytes);
    111                 if (this.immediateFlush || event.isEndOfBatch()) {
    112                     manager.flush();
    113                 }
    114             }
    115         } catch (final AppenderLoggingException ex) {
    116             error("Unable to write to stream " + manager.getName() + " for appender " + getName());
    117             throw ex;
    118         } finally {
    119             readLock.unlock();
    120         }
    121     }
    122 }