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