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.util.HashMap;
020    import java.util.Map;
021    
022    import org.apache.logging.log4j.core.Filter;
023    import org.apache.logging.log4j.core.Layout;
024    import org.apache.logging.log4j.core.LogEvent;
025    import org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy;
026    import org.apache.logging.log4j.core.appender.rolling.FastRollingFileManager;
027    import org.apache.logging.log4j.core.appender.rolling.RollingFileManager;
028    import org.apache.logging.log4j.core.appender.rolling.RolloverStrategy;
029    import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
030    import org.apache.logging.log4j.core.config.Configuration;
031    import org.apache.logging.log4j.core.config.plugins.Plugin;
032    import org.apache.logging.log4j.core.config.plugins.PluginAttr;
033    import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
034    import org.apache.logging.log4j.core.config.plugins.PluginElement;
035    import org.apache.logging.log4j.core.config.plugins.PluginFactory;
036    import org.apache.logging.log4j.core.layout.PatternLayout;
037    import org.apache.logging.log4j.core.net.Advertiser;
038    
039    /**
040     * An appender that writes to random access files and can roll over at
041     * intervals.
042     */
043    @Plugin(name = "FastRollingFile", type = "Core", elementType = "appender", printObject = true)
044    public final class FastRollingFileAppender extends AbstractOutputStreamAppender {
045    
046        private final String fileName;
047        private final String filePattern;
048        private Object advertisement;
049        private final Advertiser advertiser;
050    
051        private FastRollingFileAppender(String name, Layout<?> layout,
052                Filter filter, RollingFileManager manager, String fileName,
053                String filePattern, boolean handleException,
054                boolean immediateFlush, Advertiser advertiser) {
055            super(name, layout, filter, handleException, immediateFlush, manager);
056            if (advertiser != null) {
057                Map<String, String> configuration = new HashMap<String, String>(
058                        layout.getContentFormat());
059                configuration.put("contentType", layout.getContentType());
060                configuration.put("name", name);
061                advertisement = advertiser.advertise(configuration);
062            }
063            this.fileName = fileName;
064            this.filePattern = filePattern;
065            this.advertiser = advertiser;
066        }
067    
068        @Override
069        public void stop() {
070            super.stop();
071            if (advertiser != null) {
072                advertiser.unadvertise(advertisement);
073            }
074        }
075    
076        /**
077         * Write the log entry rolling over the file when required.
078         * 
079         * @param event The LogEvent.
080         */
081        @Override
082        public void append(final LogEvent event) {
083            FastRollingFileManager manager = (FastRollingFileManager) getManager();
084            manager.checkRollover(event);
085    
086            // Leverage the nice batching behaviour of async Loggers/Appenders:
087            // we can signal the file manager that it needs to flush the buffer
088            // to disk at the end of a batch.
089            // From a user's point of view, this means that all log events are
090            // _always_ available in the log file, without incurring the overhead
091            // of immediateFlush=true.
092            manager.setEndOfBatch(event.isEndOfBatch());
093            super.append(event);
094        }
095    
096        /**
097         * Returns the File name for the Appender.
098         * 
099         * @return The file name.
100         */
101        public String getFileName() {
102            return fileName;
103        }
104    
105        /**
106         * Returns the file pattern used when rolling over.
107         * 
108         * @return The file pattern.
109         */
110        public String getFilePattern() {
111            return filePattern;
112        }
113    
114        /**
115         * Create a FastRollingFileAppender.
116         * 
117         * @param fileName The name of the file that is actively written to.
118         *            (required).
119         * @param filePattern The pattern of the file name to use on rollover.
120         *            (required).
121         * @param append If true, events are appended to the file. If false, the
122         *            file is overwritten when opened. Defaults to "true"
123         * @param name The name of the Appender (required).
124         * @param immediateFlush When true, events are immediately flushed. Defaults
125         *            to "true".
126         * @param policy The triggering policy. (required).
127         * @param strategy The rollover strategy. Defaults to
128         *            DefaultRolloverStrategy.
129         * @param layout The layout to use (defaults to the default PatternLayout).
130         * @param filter The Filter or null.
131         * @param suppress "true" if exceptions should be hidden from the
132         *            application, "false" otherwise. The default is "true".
133         * @param advertise "true" if the appender configuration should be
134         *            advertised, "false" otherwise.
135         * @param advertiseURI The advertised URI which can be used to retrieve the
136         *            file contents.
137         * @param config The Configuration.
138         * @return A FastRollingFileAppender.
139         */
140        @PluginFactory
141        public static FastRollingFileAppender createAppender(
142                @PluginAttr("fileName") final String fileName,
143                @PluginAttr("filePattern") final String filePattern,
144                @PluginAttr("append") final String append,
145                @PluginAttr("name") final String name,
146                @PluginAttr("immediateFlush") final String immediateFlush,
147                @PluginElement("policy") final TriggeringPolicy policy,
148                @PluginElement("strategy") RolloverStrategy strategy,
149                @PluginElement("layout") Layout<?> layout,
150                @PluginElement("filter") final Filter filter,
151                @PluginAttr("suppressExceptions") final String suppress,
152                @PluginAttr("advertise") final String advertise,
153                @PluginAttr("advertiseURI") final String advertiseURI,
154                @PluginConfiguration final Configuration config) {
155    
156            final boolean isAppend = append == null ? true : Boolean
157                    .valueOf(append);
158            final boolean handleExceptions = suppress == null ? true : Boolean
159                    .valueOf(suppress);
160            final boolean isFlush = immediateFlush == null ? true : Boolean
161                    .valueOf(immediateFlush);
162            boolean isAdvertise = advertise == null ? false : Boolean
163                    .valueOf(advertise);
164    
165            if (name == null) {
166                LOGGER.error("No name provided for FileAppender");
167                return null;
168            }
169    
170            if (fileName == null) {
171                LOGGER.error("No filename was provided for FileAppender with name "
172                        + name);
173                return null;
174            }
175    
176            if (filePattern == null) {
177                LOGGER.error("No filename pattern provided for FileAppender with name "
178                        + name);
179                return null;
180            }
181    
182            if (policy == null) {
183                LOGGER.error("A TriggeringPolicy must be provided");
184                return null;
185            }
186    
187            if (strategy == null) {
188                strategy = DefaultRolloverStrategy.createStrategy(null, null,
189                        "true", config);
190            }
191    
192            final FastRollingFileManager manager = FastRollingFileManager
193                    .getFastRollingFileManager(fileName, filePattern, isAppend,
194                            isFlush, policy, strategy, advertiseURI);
195            if (manager == null) {
196                return null;
197            }
198    
199            if (layout == null) {
200                layout = PatternLayout.createLayout(null, null, null, null);
201            }
202    
203            return new FastRollingFileAppender(name, layout, filter, manager,
204                    fileName, filePattern, handleExceptions, isFlush,
205                    isAdvertise ? config.getAdvertiser() : null);
206        }
207    }