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.LogEvent;
29  import org.apache.logging.log4j.core.config.Configuration;
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.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 = "RandomAccessFile", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE, printObject = true)
41  public final class RandomAccessFileAppender extends AbstractOutputStreamAppender<RandomAccessFileManager> {
42  
43      /**
44       * Builds RandomAccessFileAppender instances.
45       * 
46       * @param <B>
47       *            The type to build
48       */
49      public static class Builder<B extends Builder<B>> extends AbstractOutputStreamAppender.Builder<B>
50              implements org.apache.logging.log4j.core.util.Builder<RandomAccessFileAppender> {
51  
52          @PluginBuilderAttribute("fileName")
53          private String fileName;
54  
55          @PluginBuilderAttribute("append")
56          private boolean append = true;
57  
58          @PluginBuilderAttribute("advertise")
59          private boolean advertise;
60  
61          @PluginBuilderAttribute("advertiseURI")
62          private String advertiseURI;
63  
64          @Override
65          public RandomAccessFileAppender build() {
66              final String name = getName();
67              if (name == null) {
68                  LOGGER.error("No name provided for FileAppender");
69                  return null;
70              }
71  
72              if (fileName == null) {
73                  LOGGER.error("No filename provided for FileAppender with name " + name);
74                  return null;
75              }
76              final Layout<? extends Serializable> layout = getOrCreateLayout();
77              final boolean immediateFlush = isImmediateFlush();
78              final RandomAccessFileManager manager = RandomAccessFileManager.getFileManager(fileName, append,
79                      immediateFlush, getBufferSize(), advertiseURI, layout, null);
80              if (manager == null) {
81                  return null;
82              }
83  
84              return new RandomAccessFileAppender(name, layout, getFilter(), manager, fileName, isIgnoreExceptions(),
85                      immediateFlush, advertise ? getConfiguration().getAdvertiser() : null);
86          }
87  
88          public B setFileName(final String fileName) {
89              this.fileName = fileName;
90              return asBuilder();
91          }
92  
93          public B setAppend(final boolean append) {
94              this.append = append;
95              return asBuilder();
96          }
97  
98          public B setAdvertise(final boolean advertise) {
99              this.advertise = advertise;
100             return asBuilder();
101         }
102 
103         public B setAdvertiseURI(final String advertiseURI) {
104             this.advertiseURI = advertiseURI;
105             return asBuilder();
106         }
107 
108     }
109     
110     private final String fileName;
111     private Object advertisement;
112     private final Advertiser advertiser;
113 
114     private RandomAccessFileAppender(final String name, final Layout<? extends Serializable> layout,
115             final Filter filter, final RandomAccessFileManager manager, final String filename,
116             final boolean ignoreExceptions, final boolean immediateFlush, final Advertiser advertiser) {
117 
118         super(name, layout, filter, ignoreExceptions, immediateFlush, manager);
119         if (advertiser != null) {
120             final Map<String, String> configuration = new HashMap<>(
121                     layout.getContentFormat());
122             configuration.putAll(manager.getContentFormat());
123             configuration.put("contentType", layout.getContentType());
124             configuration.put("name", name);
125             advertisement = advertiser.advertise(configuration);
126         }
127         this.fileName = filename;
128         this.advertiser = advertiser;
129     }
130 
131     @Override
132     public boolean stop(final long timeout, final TimeUnit timeUnit) {
133         setStopping();
134         super.stop(timeout, timeUnit, false);
135         if (advertiser != null) {
136             advertiser.unadvertise(advertisement);
137         }
138         setStopped();
139         return true;
140     }
141 
142     /**
143      * Write the log entry rolling over the file when required.
144      *
145      * @param event The LogEvent.
146      */
147     @Override
148     public void append(final LogEvent event) {
149 
150         // Leverage the nice batching behaviour of async Loggers/Appenders:
151         // we can signal the file manager that it needs to flush the buffer
152         // to disk at the end of a batch.
153         // From a user's point of view, this means that all log events are
154         // _always_ available in the log file, without incurring the overhead
155         // of immediateFlush=true.
156         getManager().setEndOfBatch(event.isEndOfBatch()); // FIXME manager's EndOfBatch threadlocal can be deleted
157 
158         // LOG4J2-1292 utilize gc-free Layout.encode() method: taken care of in superclass
159         super.append(event);
160     }
161 
162     /**
163      * Returns the file name this appender is associated with.
164      *
165      * @return The File name.
166      */
167     public String getFileName() {
168         return this.fileName;
169     }
170 
171     /**
172      * Returns the size of the file manager's buffer.
173      * @return the buffer size
174      */
175     public int getBufferSize() {
176         return getManager().getBufferSize();
177     }
178 
179     // difference from standard File Appender:
180     // locking is not supported and buffering cannot be switched off
181     /**
182      * Create a File Appender.
183      *
184      * @param fileName The name and path of the file.
185      * @param append "True" if the file should be appended to, "false" if it
186      *            should be overwritten. The default is "true".
187      * @param name The name of the Appender.
188      * @param immediateFlush "true" if the contents should be flushed on every
189      *            write, "false" otherwise. The default is "true".
190      * @param bufferSizeStr The buffer size, defaults to {@value RandomAccessFileManager#DEFAULT_BUFFER_SIZE}.
191      * @param ignore If {@code "true"} (default) exceptions encountered when appending events are logged; otherwise
192      *               they are propagated to the caller.
193      * @param layout The layout to use to format the event. If no layout is
194      *            provided the default PatternLayout will be used.
195      * @param filter The filter, if any, to use.
196      * @param advertise "true" if the appender configuration should be
197      *            advertised, "false" otherwise.
198      * @param advertiseURI The advertised URI which can be used to retrieve the
199      *            file contents.
200      * @param configuration The Configuration.
201      * @return The FileAppender.
202      * @deprecated Use {@link #newBuilder()}.
203      */
204     @Deprecated
205     public static <B extends Builder<B>> RandomAccessFileAppender createAppender(
206             final String fileName,
207             final String append,
208             final String name,
209             final String immediateFlush,
210             final String bufferSizeStr,
211             final String ignore,
212             final Layout<? extends Serializable> layout,
213             final Filter filter,
214             final String advertise,
215             final String advertiseURI,
216             final Configuration configuration) {
217 
218         final boolean isAppend = Booleans.parseBoolean(append, true);
219         final boolean isFlush = Booleans.parseBoolean(immediateFlush, true);
220         final boolean ignoreExceptions = Booleans.parseBoolean(ignore, true);
221         final boolean isAdvertise = Boolean.parseBoolean(advertise);
222         final int bufferSize = Integers.parseInt(bufferSizeStr, RandomAccessFileManager.DEFAULT_BUFFER_SIZE);
223 
224         return RandomAccessFileAppender.<B>newBuilder()
225             .setAdvertise(isAdvertise)
226             .setAdvertiseURI(advertiseURI)
227             .setAppend(isAppend)
228             .withBufferSize(bufferSize)
229             .setConfiguration(configuration)
230             .setFileName(fileName)
231             .withFilter(filter)
232             .withIgnoreExceptions(ignoreExceptions)
233             .withImmediateFlush(isFlush)
234             .withLayout(layout)
235             .withName(name)
236             .build();
237     }
238     
239     /**
240      * Creates a builder for a RandomAccessFileAppender.
241      * @return a builder for a RandomAccessFileAppender.
242      */
243     @PluginBuilderFactory
244     public static <B extends Builder<B>> B newBuilder() {
245         return new Builder<B>().asBuilder();
246     }
247 
248 }