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 import java.util.zip.Deflater;
023
024 import org.apache.logging.log4j.core.Filter;
025 import org.apache.logging.log4j.core.Layout;
026 import org.apache.logging.log4j.core.LogEvent;
027 import org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy;
028 import org.apache.logging.log4j.core.appender.rolling.RollingFileManager;
029 import org.apache.logging.log4j.core.appender.rolling.RolloverStrategy;
030 import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
031 import org.apache.logging.log4j.core.config.Configuration;
032 import org.apache.logging.log4j.core.config.plugins.Plugin;
033 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
034 import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
035 import org.apache.logging.log4j.core.config.plugins.PluginElement;
036 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
037 import org.apache.logging.log4j.core.layout.PatternLayout;
038 import org.apache.logging.log4j.core.net.Advertiser;
039 import org.apache.logging.log4j.core.util.Booleans;
040 import org.apache.logging.log4j.core.util.Integers;
041
042 /**
043 * An appender that writes to files and can roll over at intervals.
044 */
045 @Plugin(name = "RollingFile", category = "Core", elementType = "appender", printObject = true)
046 public final class RollingFileAppender extends AbstractOutputStreamAppender<RollingFileManager> {
047
048 private static final int DEFAULT_BUFFER_SIZE = 8192;
049 private static final long serialVersionUID = 1L;
050
051 private final String fileName;
052 private final String filePattern;
053 private Object advertisement;
054 private final Advertiser advertiser;
055
056
057 private RollingFileAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter,
058 final RollingFileManager manager, final String fileName, final String filePattern,
059 final boolean ignoreExceptions, final boolean immediateFlush, final Advertiser advertiser) {
060 super(name, layout, filter, ignoreExceptions, immediateFlush, manager);
061 if (advertiser != null) {
062 final Map<String, String> configuration = new HashMap<String, String>(layout.getContentFormat());
063 configuration.put("contentType", layout.getContentType());
064 configuration.put("name", name);
065 advertisement = advertiser.advertise(configuration);
066 }
067 this.fileName = fileName;
068 this.filePattern = filePattern;
069 this.advertiser = advertiser;
070 }
071
072 @Override
073 public void stop() {
074 super.stop();
075 if (advertiser != null) {
076 advertiser.unadvertise(advertisement);
077 }
078 }
079
080 /**
081 * Write the log entry rolling over the file when required.
082
083 * @param event The LogEvent.
084 */
085 @Override
086 public void append(final LogEvent event) {
087 getManager().checkRollover(event);
088 super.append(event);
089 }
090
091 /**
092 * Returns the File name for the Appender.
093 * @return The file name.
094 */
095 public String getFileName() {
096 return fileName;
097 }
098
099 /**
100 * Returns the file pattern used when rolling over.
101 * @return The file pattern.
102 */
103 public String getFilePattern() {
104 return filePattern;
105 }
106
107 /**
108 * Create a RollingFileAppender.
109 * @param fileName The name of the file that is actively written to. (required).
110 * @param filePattern The pattern of the file name to use on rollover. (required).
111 * @param append If true, events are appended to the file. If false, the file
112 * is overwritten when opened. Defaults to "true"
113 * @param name The name of the Appender (required).
114 * @param bufferedIO When true, I/O will be buffered. Defaults to "true".
115 * @param bufferSizeStr buffer size for buffered IO (default is 8192).
116 * @param immediateFlush When true, events are immediately flushed. Defaults to "true".
117 * @param policy The triggering policy. (required).
118 * @param strategy The rollover strategy. Defaults to DefaultRolloverStrategy.
119 * @param layout The layout to use (defaults to the default PatternLayout).
120 * @param filter The Filter or null.
121 * @param ignore If {@code "true"} (default) exceptions encountered when appending events are logged; otherwise
122 * they are propagated to the caller.
123 * @param advertise "true" if the appender configuration should be advertised, "false" otherwise.
124 * @param advertiseURI The advertised URI which can be used to retrieve the file contents.
125 * @param config The Configuration.
126 * @return A RollingFileAppender.
127 */
128 @PluginFactory
129 public static RollingFileAppender createAppender(
130 @PluginAttribute("fileName") final String fileName,
131 @PluginAttribute("filePattern") final String filePattern,
132 @PluginAttribute("append") final String append,
133 @PluginAttribute("name") final String name,
134 @PluginAttribute("bufferedIO") final String bufferedIO,
135 @PluginAttribute("bufferSize") final String bufferSizeStr,
136 @PluginAttribute("immediateFlush") final String immediateFlush,
137 @PluginElement("Policy") final TriggeringPolicy policy,
138 @PluginElement("Strategy") RolloverStrategy strategy,
139 @PluginElement("Layout") Layout<? extends Serializable> layout,
140 @PluginElement("Filter") final Filter filter,
141 @PluginAttribute("ignoreExceptions") final String ignore,
142 @PluginAttribute("advertise") final String advertise,
143 @PluginAttribute("advertiseURI") final String advertiseURI,
144 @PluginConfiguration final Configuration config) {
145
146 final boolean isAppend = Booleans.parseBoolean(append, true);
147 final boolean ignoreExceptions = Booleans.parseBoolean(ignore, true);
148 final boolean isBuffered = Booleans.parseBoolean(bufferedIO, true);
149 final boolean isFlush = Booleans.parseBoolean(immediateFlush, true);
150 final boolean isAdvertise = Boolean.parseBoolean(advertise);
151 final int bufferSize = Integers.parseInt(bufferSizeStr, DEFAULT_BUFFER_SIZE);
152 if (!isBuffered && bufferSize > 0) {
153 LOGGER.warn("The bufferSize is set to {} but bufferedIO is not true: {}", bufferSize, bufferedIO);
154 }
155 if (name == null) {
156 LOGGER.error("No name provided for FileAppender");
157 return null;
158 }
159
160 if (fileName == null) {
161 LOGGER.error("No filename was provided for FileAppender with name " + name);
162 return null;
163 }
164
165 if (filePattern == null) {
166 LOGGER.error("No filename pattern provided for FileAppender with name " + name);
167 return null;
168 }
169
170 if (policy == null) {
171 LOGGER.error("A TriggeringPolicy must be provided");
172 return null;
173 }
174
175 if (strategy == null) {
176 strategy = DefaultRolloverStrategy.createStrategy(null, null, null,
177 String.valueOf(Deflater.DEFAULT_COMPRESSION), config);
178 }
179
180 if (layout == null) {
181 layout = PatternLayout.createDefaultLayout();
182 }
183
184 final RollingFileManager manager = RollingFileManager.getFileManager(fileName, filePattern, isAppend,
185 isBuffered, policy, strategy, advertiseURI, layout, bufferSize);
186 if (manager == null) {
187 return null;
188 }
189
190 return new RollingFileAppender(name, layout, filter, manager, fileName, filePattern,
191 ignoreExceptions, isFlush, isAdvertise ? config.getAdvertiser() : null);
192 }
193 }