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