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          @Override
74          public FileAppender build() {
75              boolean bufferedIo = isBufferedIo();
76              final int bufferSize = getBufferSize();
77              if (locking && bufferedIo) {
78                  LOGGER.warn("Locking and buffering are mutually exclusive. No buffering will occur for {}", fileName);
79                  bufferedIo = false;
80              }
81              if (!bufferedIo && bufferSize > 0) {
82                  LOGGER.warn("The bufferSize is set to {} but bufferedIo is false: {}", bufferSize, bufferedIo);
83              }
84              final Layout<? extends Serializable> layout = getOrCreateLayout();
85  
86              final FileManager manager = FileManager.getFileManager(fileName, append, locking, bufferedIo, createOnDemand,
87                      advertiseUri, layout, bufferSize, getConfiguration());
88              if (manager == null) {
89                  return null;
90              }
91  
92              return new FileAppender(getName(), layout, getFilter(), manager, fileName, isIgnoreExceptions(),
93                      !bufferedIo || isImmediateFlush(), advertise ? getConfiguration().getAdvertiser() : null);
94          }
95  
96          public String getAdvertiseUri() {
97              return advertiseUri;
98          }
99  
100         public String getFileName() {
101             return fileName;
102         }
103 
104         public boolean isAdvertise() {
105             return advertise;
106         }
107 
108         public boolean isAppend() {
109             return append;
110         }
111 
112         public boolean isCreateOnDemand() {
113             return createOnDemand;
114         }
115 
116         public boolean isLocking() {
117             return locking;
118         }
119 
120         public B withAdvertise(final boolean advertise) {
121             this.advertise = advertise;
122             return asBuilder();
123         }
124 
125         public B withAdvertiseUri(final String advertiseUri) {
126             this.advertiseUri = advertiseUri;
127             return asBuilder();
128         }
129 
130         public B withAppend(final boolean append) {
131             this.append = append;
132             return asBuilder();
133         }
134 
135         public B withFileName(final String fileName) {
136             this.fileName = fileName;
137             return asBuilder();
138         }
139 
140         public B withCreateOnDemand(final boolean createOnDemand) {
141             this.createOnDemand = createOnDemand;
142             return asBuilder();
143         }
144 
145         public B withLocking(final boolean locking) {
146             this.locking = locking;
147             return asBuilder();
148         }
149 
150     }
151     
152     private static final int DEFAULT_BUFFER_SIZE = 8192;
153     
154     /**
155      * Create a File Appender.
156      * @param fileName The name and path of the file.
157      * @param append "True" if the file should be appended to, "false" if it should be overwritten.
158      * The default is "true".
159      * @param locking "True" if the file should be locked. The default is "false".
160      * @param name The name of the Appender.
161      * @param immediateFlush "true" if the contents should be flushed on every write, "false" otherwise. The default
162      * is "true".
163      * @param ignoreExceptions If {@code "true"} (default) exceptions encountered when appending events are logged; otherwise
164      *               they are propagated to the caller.
165      * @param bufferedIo "true" if I/O should be buffered, "false" otherwise. The default is "true".
166      * @param bufferSizeStr buffer size for buffered IO (default is 8192).
167      * @param layout The layout to use to format the event. If no layout is provided the default PatternLayout
168      * will be used.
169      * @param filter The filter, if any, to use.
170      * @param advertise "true" if the appender configuration should be advertised, "false" otherwise.
171      * @param advertiseUri The advertised URI which can be used to retrieve the file contents.
172      * @param config The Configuration
173      * @return The FileAppender.
174      * @deprecated Use {@link #newBuilder()}
175      */
176     @Deprecated
177     public static <B extends Builder<B>> FileAppender createAppender(
178             // @formatter:off
179             final String fileName,
180             final String append,
181             final String locking,
182             final String name,
183             final String immediateFlush,
184             final String ignoreExceptions,
185             final String bufferedIo,
186             final String bufferSizeStr,
187             final Layout<? extends Serializable> layout,
188             final Filter filter,
189             final String advertise,
190             final String advertiseUri,
191             final Configuration config) {
192         return FileAppender.<B>newBuilder()
193             .withAdvertise(Boolean.parseBoolean(advertise))
194             .withAdvertiseUri(advertiseUri)
195             .withAppend(Booleans.parseBoolean(append, true))
196             .withBufferedIo(Booleans.parseBoolean(bufferedIo, true))
197             .withBufferSize(Integers.parseInt(bufferSizeStr, DEFAULT_BUFFER_SIZE))
198             .setConfiguration(config)
199             .withFileName(fileName)
200             .withFilter(filter)
201             .withIgnoreExceptions(Booleans.parseBoolean(ignoreExceptions, true))
202             .withImmediateFlush(Booleans.parseBoolean(immediateFlush, true))
203             .withLayout(layout)
204             .withLocking(Boolean.parseBoolean(locking))
205             .withName(name)
206             .build();
207         // @formatter:on
208     }
209     
210     @PluginBuilderFactory
211     public static <B extends Builder<B>> B newBuilder() {
212         return new Builder<B>().asBuilder();
213     }
214     
215     private final String fileName;
216 
217     private final Advertiser advertiser;
218 
219     private final Object advertisement;
220 
221     private FileAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter,
222             final FileManager manager, final String filename, final boolean ignoreExceptions,
223             final boolean immediateFlush, final Advertiser advertiser) {
224 
225         super(name, layout, filter, ignoreExceptions, immediateFlush, manager);
226         if (advertiser != null) {
227             final Map<String, String> configuration = new HashMap<>(layout.getContentFormat());
228             configuration.putAll(manager.getContentFormat());
229             configuration.put("contentType", layout.getContentType());
230             configuration.put("name", name);
231             advertisement = advertiser.advertise(configuration);
232         } else {
233             advertisement = null;
234         }
235         this.fileName = filename;
236         this.advertiser = advertiser;
237     }
238 
239     /**
240      * Returns the file name this appender is associated with.
241      * @return The File name.
242      */
243     public String getFileName() {
244         return this.fileName;
245     }
246 
247     @Override
248     public boolean stop(final long timeout, final TimeUnit timeUnit) {
249         setStopping();
250         super.stop(timeout, timeUnit, false);
251         if (advertiser != null) {
252             advertiser.unadvertise(advertisement);
253         }
254         setStopped();
255         return true;
256     }
257 }