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;
18  
19  import java.io.Serializable;
20  import java.util.HashMap;
21  import java.util.Map;
22  import java.util.concurrent.TimeUnit;
23  
24  import org.apache.logging.log4j.core.Appender;
25  import org.apache.logging.log4j.core.Core;
26  import org.apache.logging.log4j.core.Filter;
27  import org.apache.logging.log4j.core.Layout;
28  import org.apache.logging.log4j.core.config.Configuration;
29  import org.apache.logging.log4j.core.config.plugins.Plugin;
30  import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
31  import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
32  import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
33  import org.apache.logging.log4j.core.net.Advertiser;
34  import org.apache.logging.log4j.core.util.Booleans;
35  import org.apache.logging.log4j.core.util.Integers;
36  
37  /**
38   * File Appender.
39   */
40  @Plugin(name = FileAppender.PLUGIN_NAME, category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE, printObject = true)
41  public final class FileAppender extends AbstractOutputStreamAppender<FileManager> {
42  
43      public static final String PLUGIN_NAME = "File";
44  
45      /**
46       * Builds FileAppender instances.
47       * 
48       * @param <B>
49       *            The type to build
50       */
51      public static class Builder<B extends Builder<B>> extends AbstractOutputStreamAppender.Builder<B>
52              implements org.apache.logging.log4j.core.util.Builder<FileAppender> {
53  
54          @PluginBuilderAttribute
55          @Required
56          private String fileName;
57  
58          @PluginBuilderAttribute
59          private boolean append = true;
60  
61          @PluginBuilderAttribute
62          private boolean locking;
63  
64          @PluginBuilderAttribute
65          private boolean advertise;
66  
67          @PluginBuilderAttribute
68          private String advertiseUri;
69  
70          @PluginBuilderAttribute
71          private boolean createOnDemand;
72  
73          @PluginBuilderAttribute
74          private String filePermissions;
75  
76          @PluginBuilderAttribute
77          private String fileOwner;
78  
79          @PluginBuilderAttribute
80          private String fileGroup;
81  
82          @Override
83          public FileAppender build() {
84              boolean bufferedIo = isBufferedIo();
85              final int bufferSize = getBufferSize();
86              if (locking && bufferedIo) {
87                  LOGGER.warn("Locking and buffering are mutually exclusive. No buffering will occur for {}", fileName);
88                  bufferedIo = false;
89              }
90              if (!bufferedIo && bufferSize > 0) {
91                  LOGGER.warn("The bufferSize is set to {} but bufferedIo is false: {}", bufferSize, bufferedIo);
92              }
93              final Layout<? extends Serializable> layout = getOrCreateLayout();
94  
95              final FileManager manager = FileManager.getFileManager(fileName, append, locking, bufferedIo, createOnDemand,
96                      advertiseUri, layout, bufferSize, filePermissions, fileOwner, fileGroup, getConfiguration());
97              if (manager == null) {
98                  return null;
99              }
100 
101             return new FileAppender(getName(), layout, getFilter(), manager, fileName, isIgnoreExceptions(),
102                     !bufferedIo || isImmediateFlush(), advertise ? getConfiguration().getAdvertiser() : null);
103         }
104 
105         public String getAdvertiseUri() {
106             return advertiseUri;
107         }
108 
109         public String getFileName() {
110             return fileName;
111         }
112 
113         public boolean isAdvertise() {
114             return advertise;
115         }
116 
117         public boolean isAppend() {
118             return append;
119         }
120 
121         public boolean isCreateOnDemand() {
122             return createOnDemand;
123         }
124 
125         public boolean isLocking() {
126             return locking;
127         }
128 
129         public String getFilePermissions() {
130             return filePermissions;
131         }
132 
133         public String getFileOwner() {
134             return fileOwner;
135         }
136 
137         public String getFileGroup() {
138             return fileGroup;
139         }
140 
141         public B withAdvertise(final boolean advertise) {
142             this.advertise = advertise;
143             return asBuilder();
144         }
145 
146         public B withAdvertiseUri(final String advertiseUri) {
147             this.advertiseUri = advertiseUri;
148             return asBuilder();
149         }
150 
151         public B withAppend(final boolean append) {
152             this.append = append;
153             return asBuilder();
154         }
155 
156         public B withFileName(final String fileName) {
157             this.fileName = fileName;
158             return asBuilder();
159         }
160 
161         public B withCreateOnDemand(final boolean createOnDemand) {
162             this.createOnDemand = createOnDemand;
163             return asBuilder();
164         }
165 
166         public B withLocking(final boolean locking) {
167             this.locking = locking;
168             return asBuilder();
169         }
170 
171         public B withFilePermissions(final String filePermissions) {
172             this.filePermissions = filePermissions;
173             return asBuilder();
174         }
175 
176         public B withFileOwner(final String fileOwner) {
177             this.fileOwner = fileOwner;
178             return asBuilder();
179         }
180 
181         public B withFileGroup(final String fileGroup) {
182             this.fileGroup = fileGroup;
183             return asBuilder();
184         }
185 
186     }
187     
188     private static final int DEFAULT_BUFFER_SIZE = 8192;
189     
190     /**
191      * Create a File Appender.
192      * @param fileName The name and path of the file.
193      * @param append "True" if the file should be appended to, "false" if it should be overwritten.
194      * The default is "true".
195      * @param locking "True" if the file should be locked. The default is "false".
196      * @param name The name of the Appender.
197      * @param immediateFlush "true" if the contents should be flushed on every write, "false" otherwise. The default
198      * is "true".
199      * @param ignoreExceptions If {@code "true"} (default) exceptions encountered when appending events are logged; otherwise
200      *               they are propagated to the caller.
201      * @param bufferedIo "true" if I/O should be buffered, "false" otherwise. The default is "true".
202      * @param bufferSizeStr buffer size for buffered IO (default is 8192).
203      * @param layout The layout to use to format the event. If no layout is provided the default PatternLayout
204      * will be used.
205      * @param filter The filter, if any, to use.
206      * @param advertise "true" if the appender configuration should be advertised, "false" otherwise.
207      * @param advertiseUri The advertised URI which can be used to retrieve the file contents.
208      * @param config The Configuration
209      * @return The FileAppender.
210      * @deprecated Use {@link #newBuilder()}
211      */
212     @Deprecated
213     public static <B extends Builder<B>> FileAppender createAppender(
214             // @formatter:off
215             final String fileName,
216             final String append,
217             final String locking,
218             final String name,
219             final String immediateFlush,
220             final String ignoreExceptions,
221             final String bufferedIo,
222             final String bufferSizeStr,
223             final Layout<? extends Serializable> layout,
224             final Filter filter,
225             final String advertise,
226             final String advertiseUri,
227             final Configuration config) {
228         return FileAppender.<B>newBuilder()
229             .withAdvertise(Boolean.parseBoolean(advertise))
230             .withAdvertiseUri(advertiseUri)
231             .withAppend(Booleans.parseBoolean(append, true))
232             .withBufferedIo(Booleans.parseBoolean(bufferedIo, true))
233             .withBufferSize(Integers.parseInt(bufferSizeStr, DEFAULT_BUFFER_SIZE))
234             .setConfiguration(config)
235             .withFileName(fileName)
236             .withFilter(filter)
237             .withIgnoreExceptions(Booleans.parseBoolean(ignoreExceptions, true))
238             .withImmediateFlush(Booleans.parseBoolean(immediateFlush, true))
239             .withLayout(layout)
240             .withLocking(Boolean.parseBoolean(locking))
241             .withName(name)
242             .build();
243         // @formatter:on
244     }
245     
246     @PluginBuilderFactory
247     public static <B extends Builder<B>> B newBuilder() {
248         return new Builder<B>().asBuilder();
249     }
250     
251     private final String fileName;
252 
253     private final Advertiser advertiser;
254 
255     private final Object advertisement;
256 
257     private FileAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter,
258             final FileManager manager, final String filename, final boolean ignoreExceptions,
259             final boolean immediateFlush, final Advertiser advertiser) {
260 
261         super(name, layout, filter, ignoreExceptions, immediateFlush, manager);
262         if (advertiser != null) {
263             final Map<String, String> configuration = new HashMap<>(layout.getContentFormat());
264             configuration.putAll(manager.getContentFormat());
265             configuration.put("contentType", layout.getContentType());
266             configuration.put("name", name);
267             advertisement = advertiser.advertise(configuration);
268         } else {
269             advertisement = null;
270         }
271         this.fileName = filename;
272         this.advertiser = advertiser;
273     }
274 
275     /**
276      * Returns the file name this appender is associated with.
277      * @return The File name.
278      */
279     public String getFileName() {
280         return this.fileName;
281     }
282 
283     @Override
284     public boolean stop(final long timeout, final TimeUnit timeUnit) {
285         setStopping();
286         super.stop(timeout, timeUnit, false);
287         if (advertiser != null) {
288             advertiser.unadvertise(advertisement);
289         }
290         setStopped();
291         return true;
292     }
293 }