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.db;
    18
    19  import java.util.concurrent.locks.Lock;
    20  import java.util.concurrent.locks.ReadWriteLock;
    21  import java.util.concurrent.locks.ReentrantReadWriteLock;
    22
    23  import org.apache.logging.log4j.LoggingException;
    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  import org.apache.logging.log4j.core.appender.AbstractAppender;
    28  import org.apache.logging.log4j.core.appender.AppenderLoggingException;
    29
    30  /**
    31   * An abstract Appender for writing events to a database of some type, be it relational or NoSQL. All database appenders
    32   * should inherit from this base appender. Three implementations are currently provided:
    33   * {@link org.apache.logging.log4j.core.appender.db.jdbc JDBC}, {@link org.apache.logging.log4j.core.appender.db.jpa
    34   * JPA}, and <a href="/log4j/2.x/log4j-nosql/apidocs/">NoSQL</a>.
    35   *
    36   * @param <T> Specifies which type of {@link AbstractDatabaseManager} this Appender requires.
    37   */
    38  public abstract class AbstractDatabaseAppender<T extends AbstractDatabaseManager> extends AbstractAppender {
    39      private static final long serialVersionUID = 1L;
    40
    41      private final ReadWriteLock lock = new ReentrantReadWriteLock();
    42      private final Lock readLock = lock.readLock();
    43      private final Lock writeLock = lock.writeLock();
    44
    45      private T manager;
    46
    47      /**
    48       * Instantiates the base appender.
    49       *
    50       * @param name The appender name.
    51       * @param filter The filter, if any, to use.
    52       * @param ignoreExceptions If {@code true} exceptions encountered when appending events are logged; otherwise
    53       *                         they are propagated to the caller.
    54       * @param manager The matching {@link AbstractDatabaseManager} implementation.
    55       */
    56      protected AbstractDatabaseAppender(final String name, final Filter filter, final boolean ignoreExceptions,
    57                                         final T manager) {
    58          super(name, filter, null, ignoreExceptions);
    59          this.manager = manager;
    60      }
    61
    62      /**
    63       * This always returns {@code null}, as database appenders do not use a single layout. The JPA and NoSQL appenders
    64       * do not use a layout at all. The JDBC appender has a layout-per-column pattern.
    65       *
    66       * @return {@code null}.
    67       */
    68      @Override
    69      public final Layout<LogEvent> getLayout() {
    70          return null;
    71      }
    72
    73      /**
    74       * Returns the underlying manager in use within this appender.
    75       *
    76       * @return the manager.
    77       */
    78      public final T getManager() {
    79          return this.manager;
    80      }
    81
    82      @Override
    83      public final void start() {
    84          if (this.getManager() == null) {
    85              LOGGER.error("No AbstractDatabaseManager set for the appender named [{}].", this.getName());
    86          }
    87          super.start();
    88          if (this.getManager() != null) {
    89              this.getManager().startup();
    90          }
    91      }
    92
    93      @Override
    94      public final void stop() {
    95          super.stop();
    96          if (this.getManager() != null) {
    97              this.getManager().release();
    98          }
    99      }
    100
    101     @Override
    102     public final void append(final LogEvent event) {
    103         this.readLock.lock();
    104         try {
    105             this.getManager().write(event);
    106         } catch (final LoggingException e) {
    107             LOGGER.error("Unable to write to database [{}] for appender [{}].", this.getManager().getName(),
    108                     this.getName(), e);
    109             throw e;
    110         } catch (final Exception e) {
    111             LOGGER.error("Unable to write to database [{}] for appender [{}].", this.getManager().getName(),
    112                     this.getName(), e);
    113             throw new AppenderLoggingException("Unable to write to database in appender: " + e.getMessage(), e);
    114         } finally {
    115             this.readLock.unlock();
    116         }
    117     }
    118
    119     /**
    120      * Replaces the underlying manager in use within this appender. This can be useful for manually changing the way log
    121      * events are written to the database without losing buffered or in-progress events. The existing manager is
    122      * released only after the new manager has been installed. This method is thread-safe.
    123      *
    124      * @param manager The new manager to install.
    125      */
    126     protected final void replaceManager(final T manager) {
    127         this.writeLock.lock();
    128         try {
    129             final T old = this.getManager();
    130             if (!manager.isRunning()) {
    131                 manager.startup();
    132             }
    133             this.manager = manager;
    134             old.release();
    135         } finally {
    136             this.writeLock.unlock();
    137         }
    138     }
    139 }