001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements. See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache license, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License. You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the license for the specific language governing permissions and
015     * limitations under the license.
016     */
017    package org.apache.logging.log4j.core.appender.db.jdbc;
018    
019    import org.apache.logging.log4j.core.Filter;
020    import org.apache.logging.log4j.core.appender.db.AbstractDatabaseAppender;
021    import org.apache.logging.log4j.core.config.plugins.Plugin;
022    import org.apache.logging.log4j.core.config.plugins.PluginAttr;
023    import org.apache.logging.log4j.core.config.plugins.PluginElement;
024    import org.apache.logging.log4j.core.config.plugins.PluginFactory;
025    
026    /**
027     * This Appender writes logging events to a relational database using standard JDBC mechanisms. It takes a list of
028     * {@link ColumnConfig}s with which it determines how to save the event data into the appropriate columns in the table.
029     * A {@link ConnectionSource} plugin instance instructs the appender (and {@link JDBCDatabaseManager}) how to connect to
030     * the database. This appender can be reconfigured at run time.
031     * 
032     * @see ColumnConfig
033     * @see ConnectionSource
034     */
035    @Plugin(name = "Jdbc", category = "Core", elementType = "appender", printObject = true)
036    public final class JDBCAppender extends AbstractDatabaseAppender<JDBCDatabaseManager> {
037        private final String description;
038    
039        private JDBCAppender(final String name, final Filter filter, final boolean handleException,
040                             final JDBCDatabaseManager manager) {
041            super(name, filter, handleException, manager);
042            this.description = this.getName() + "{ manager=" + this.getManager() + " }";
043        }
044    
045        @Override
046        public String toString() {
047            return this.description;
048        }
049    
050        /**
051         * Factory method for creating a JDBC appender within the plugin manager.
052         *
053         * @param name The name of the appender.
054         * @param suppressExceptions {@code "true"} (default) if logging exceptions should be hidden from the application,
055         *                           {@code "false"} otherwise.
056         * @param filter The filter, if any, to use.
057         * @param connectionSource The connections source from which database connections should be retrieved.
058         * @param bufferSize If an integer greater than 0, this causes the appender to buffer log events and flush whenever
059         *                   the buffer reaches this size.
060         * @param tableName The name of the database table to insert log events into.
061         * @param columnConfigs Information about the columns that log event data should be inserted into and how to insert
062         *                      that data.
063         * @return a new JDBC appender.
064         */
065        @PluginFactory
066        public static JDBCAppender createAppender(@PluginAttr("name") final String name,
067                                                  @PluginAttr("suppressExceptions") final String suppressExceptions,
068                                                  @PluginElement("filter") final Filter filter,
069                                                  @PluginElement("connectionSource") final ConnectionSource
070                                                          connectionSource,
071                                                  @PluginAttr("bufferSize") final String bufferSize,
072                                                  @PluginAttr("tableName") final String tableName,
073                                                  @PluginElement("columnConfigs") final ColumnConfig[] columnConfigs) {
074            int bufferSizeInt;
075            try {
076                bufferSizeInt = bufferSize == null || bufferSize.length() == 0 ? 0 : Integer.parseInt(bufferSize);
077            } catch (final NumberFormatException e) {
078                LOGGER.warn("Buffer size [" + bufferSize + "] not an integer, using no buffer.");
079                bufferSizeInt = 0;
080            }
081    
082            final boolean handleExceptions = suppressExceptions == null || !Boolean.parseBoolean(suppressExceptions);
083    
084            final StringBuilder managerName = new StringBuilder("jdbcManager{ description=").append(name)
085                    .append(", bufferSize=").append(bufferSizeInt).append(", connectionSource=")
086                    .append(connectionSource.toString()).append(", tableName=").append(tableName).append(", columns=[ ");
087    
088            int i = 0;
089            for (final ColumnConfig column : columnConfigs) {
090                if (i++ > 0) {
091                    managerName.append(", ");
092                }
093                managerName.append(column.toString());
094            }
095    
096            managerName.append(" ] }");
097    
098            final JDBCDatabaseManager manager = JDBCDatabaseManager.getJDBCDatabaseManager(
099                    managerName.toString(), bufferSizeInt, connectionSource, tableName, columnConfigs
100            );
101            if (manager == null) {
102                return null;
103            }
104    
105            return new JDBCAppender(name, filter, handleExceptions, manager);
106        }
107    }