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