    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;
    018
    019    import java.io.Serializable;
    020    import java.util.HashMap;
    021    import java.util.Map;
    022
    023    import org.apache.logging.log4j.core.Filter;
    024    import org.apache.logging.log4j.core.Layout;
    025    import org.apache.logging.log4j.core.config.Configuration;
    026    import org.apache.logging.log4j.core.config.plugins.Plugin;
    027    import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
    028    import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
    029    import org.apache.logging.log4j.core.config.plugins.PluginElement;
    030    import org.apache.logging.log4j.core.config.plugins.PluginFactory;
    031    import org.apache.logging.log4j.core.layout.PatternLayout;
    032    import org.apache.logging.log4j.core.net.Advertiser;
    033    import org.apache.logging.log4j.core.util.Booleans;
    034    import org.apache.logging.log4j.core.util.Integers;
    035
    036    /**
    037     * File Appender.
    038     */
    039    @Plugin(name = "File", category = "Core", elementType = "appender", printObject = true)
    040    public final class FileAppender extends AbstractOutputStreamAppender<FileManager> {
    041
    042        private static final long serialVersionUID = 1L;
    043        private static final int DEFAULT_BUFFER_SIZE = 8192;
    044        private final String fileName;
    045        private final Advertiser advertiser;
    046        private Object advertisement;
    047
    048        private FileAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter, final FileManager manager,
    049                             final String filename, final boolean ignoreExceptions, final boolean immediateFlush,
    050                             final Advertiser advertiser) {
    051            super(name, layout, filter, ignoreExceptions, immediateFlush, manager);
    052            if (advertiser != null) {
    053                final Map<String, String> configuration = new HashMap<String, String>(layout.getContentFormat());
    054                configuration.putAll(manager.getContentFormat());
    055                configuration.put("contentType", layout.getContentType());
    056                configuration.put("name", name);
    057                advertisement = advertiser.advertise(configuration);
    058            }
    059            this.fileName = filename;
    060            this.advertiser = advertiser;
    061        }
    062
    063        @Override
    064        public void stop() {
    065            super.stop();
    066            if (advertiser != null) {
    067                advertiser.unadvertise(advertisement);
    068            }
    069        }
    070
    071        /**
    072         * Returns the file name this appender is associated with.
    073         * @return The File name.
    074         */
    075        public String getFileName() {
    076            return this.fileName;
    077        }
    078
    079        /**
    080         * Create a File Appender.
    081         * @param fileName The name and path of the file.
    082         * @param append "True" if the file should be appended to, "false" if it should be overwritten.
    083         * The default is "true".
    084         * @param locking "True" if the file should be locked. The default is "false".
    085         * @param name The name of the Appender.
    086         * @param immediateFlush "true" if the contents should be flushed on every write, "false" otherwise. The default
    087         * is "true".
    088         * @param ignore If {@code "true"} (default) exceptions encountered when appending events are logged; otherwise
    089         *               they are propagated to the caller.
    090         * @param bufferedIo "true" if I/O should be buffered, "false" otherwise. The default is "true".
    091         * @param bufferSizeStr buffer size for buffered IO (default is 8192).
    092         * @param layout The layout to use to format the event. If no layout is provided the default PatternLayout
    093         * will be used.
    094         * @param filter The filter, if any, to use.
    095         * @param advertise "true" if the appender configuration should be advertised, "false" otherwise.
    096         * @param advertiseUri The advertised URI which can be used to retrieve the file contents.
    097         * @param config The Configuration
    098         * @return The FileAppender.
    099         */
    100        @PluginFactory
    101        public static FileAppender createAppender(
    102                // @formatter:off
    103                @PluginAttribute("fileName") final String fileName,
    104                @PluginAttribute("append") final String append,
    105                @PluginAttribute("locking") final String locking,
    106                @PluginAttribute("name") final String name,
    107                @PluginAttribute("immediateFlush") final String immediateFlush,
    108                @PluginAttribute("ignoreExceptions") final String ignore,
    109                @PluginAttribute("bufferedIo") final String bufferedIo,
    110                @PluginAttribute("bufferSize") final String bufferSizeStr,
    111                @PluginElement("Layout") Layout<? extends Serializable> layout,
    112                @PluginElement("Filter") final Filter filter,
    113                @PluginAttribute("advertise") final String advertise,
    114                @PluginAttribute("advertiseUri") final String advertiseUri,
    115                @PluginConfiguration final Configuration config) {
    116            // @formatter:on
    117            final boolean isAppend = Booleans.parseBoolean(append, true);
    118            final boolean isLocking = Boolean.parseBoolean(locking);
    119            boolean isBuffered = Booleans.parseBoolean(bufferedIo, true);
    120            final boolean isAdvertise = Boolean.parseBoolean(advertise);
    121            if (isLocking && isBuffered) {
    122                if (bufferedIo != null) {
    123                    LOGGER.warn("Locking and buffering are mutually exclusive. No buffering will occur for " + fileName);
    124                }
    125                isBuffered = false;
    126            }
    127            final int bufferSize = Integers.parseInt(bufferSizeStr, DEFAULT_BUFFER_SIZE);
    128            if (!isBuffered && bufferSize > 0) {
    129                LOGGER.warn("The bufferSize is set to {} but bufferedIO is not true: {}", bufferSize, bufferedIo);
    130            }
    131            final boolean isFlush = Booleans.parseBoolean(immediateFlush, true);
    132            final boolean ignoreExceptions = Booleans.parseBoolean(ignore, true);
    133
    134            if (name == null) {
    135                LOGGER.error("No name provided for FileAppender");
    136                return null;
    137            }
    138
    139            if (fileName == null) {
    140                LOGGER.error("No filename provided for FileAppender with name "  + name);
    141                return null;
    142            }
    143            if (layout == null) {
    144                layout = PatternLayout.createDefaultLayout();
    145            }
    146
    147            final FileManager manager = FileManager.getFileManager(fileName, isAppend, isLocking, isBuffered, advertiseUri,
    148                layout, bufferSize);
    149            if (manager == null) {
    150                return null;
    151            }
    152
    153            return new FileAppender(name, layout, filter, manager, fileName, ignoreExceptions, isFlush,
    154                    isAdvertise ? config.getAdvertiser() : null);
    155        }
    156    }