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.log4j.builders.appender;
18  
19  import static org.apache.log4j.builders.BuilderManager.CATEGORY;
20  import static org.apache.log4j.config.Log4j1Configuration.THRESHOLD_PARAM;
21  import static org.apache.log4j.xml.XmlConfiguration.FILTER_TAG;
22  import static org.apache.log4j.xml.XmlConfiguration.LAYOUT_TAG;
23  import static org.apache.log4j.xml.XmlConfiguration.NAME_ATTR;
24  import static org.apache.log4j.xml.XmlConfiguration.PARAM_TAG;
25  import static org.apache.log4j.xml.XmlConfiguration.VALUE_ATTR;
26  import static org.apache.log4j.xml.XmlConfiguration.forEachElement;
27  
28  import java.util.Properties;
29  import java.util.concurrent.atomic.AtomicBoolean;
30  import java.util.concurrent.atomic.AtomicInteger;
31  import java.util.concurrent.atomic.AtomicReference;
32  
33  import org.apache.log4j.Appender;
34  import org.apache.log4j.Layout;
35  import org.apache.log4j.bridge.AppenderWrapper;
36  import org.apache.log4j.bridge.LayoutAdapter;
37  import org.apache.log4j.bridge.LayoutWrapper;
38  import org.apache.log4j.builders.AbstractBuilder;
39  import org.apache.log4j.config.Log4j1Configuration;
40  import org.apache.log4j.config.PropertiesConfiguration;
41  import org.apache.log4j.spi.Filter;
42  import org.apache.log4j.xml.XmlConfiguration;
43  import org.apache.logging.log4j.Logger;
44  import org.apache.logging.log4j.core.appender.RollingFileAppender;
45  import org.apache.logging.log4j.core.appender.rolling.CompositeTriggeringPolicy;
46  import org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy;
47  import org.apache.logging.log4j.core.appender.rolling.RolloverStrategy;
48  import org.apache.logging.log4j.core.appender.rolling.SizeBasedTriggeringPolicy;
49  import org.apache.logging.log4j.core.appender.rolling.TimeBasedTriggeringPolicy;
50  import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
51  import org.apache.logging.log4j.core.config.plugins.Plugin;
52  import org.apache.logging.log4j.status.StatusLogger;
53  import org.w3c.dom.Element;
54  
55  
56  /**
57   * Build a File Appender
58   */
59  @Plugin(name = "org.apache.log4j.RollingFileAppender", category = CATEGORY)
60  public class RollingFileAppenderBuilder extends AbstractBuilder implements AppenderBuilder {
61  
62      private static final Logger LOGGER = StatusLogger.getLogger();
63  
64      public RollingFileAppenderBuilder() {
65      }
66  
67      public RollingFileAppenderBuilder(String prefix, Properties props) {
68          super(prefix, props);
69      }
70  
71      @Override
72      public Appender parseAppender(Element appenderElement, XmlConfiguration config) {
73          String name = appenderElement.getAttribute(NAME_ATTR);
74          AtomicReference<Layout> layout = new AtomicReference<>();
75          AtomicReference<Filter> filter = new AtomicReference<>();
76          AtomicReference<String> fileName = new AtomicReference<>();
77          AtomicBoolean immediateFlush = new AtomicBoolean();
78          AtomicBoolean append = new AtomicBoolean();
79          AtomicBoolean bufferedIo = new AtomicBoolean();
80          AtomicInteger bufferSize = new AtomicInteger(8192);
81          AtomicReference<String> maxSize = new AtomicReference<>();
82          AtomicReference<String> maxBackups = new AtomicReference<>();
83          AtomicReference<String> level = new AtomicReference<>();
84          forEachElement(appenderElement.getChildNodes(), currentElement -> {
85              switch (currentElement.getTagName()) {
86                  case LAYOUT_TAG:
87                      layout.set(config.parseLayout(currentElement));
88                      break;
89                  case FILTER_TAG:
90                      filter.set(config.parseFilters(currentElement));
91                      break;
92                  case PARAM_TAG: {
93                      switch (currentElement.getAttribute(NAME_ATTR)) {
94                          case FILE_PARAM:
95                              fileName.set(currentElement.getAttribute(VALUE_ATTR));
96                              break;
97                          case APPEND_PARAM: {
98                              String bool = currentElement.getAttribute(VALUE_ATTR);
99                              if (bool != null) {
100                                 append.set(Boolean.parseBoolean(bool));
101                             } else {
102                                 LOGGER.warn("No value provided for append parameter");
103                             }
104                             break;
105                         }
106                         case BUFFERED_IO_PARAM: {
107                             String bool = currentElement.getAttribute(VALUE_ATTR);
108                             if (bool != null) {
109                                 bufferedIo.set(Boolean.parseBoolean(bool));
110                             } else {
111                                 LOGGER.warn("No value provided for bufferedIo parameter");
112                             }
113                             break;
114                         }
115                         case BUFFER_SIZE_PARAM: {
116                             String size = currentElement.getAttribute(VALUE_ATTR);
117                             if (size != null) {
118                                 bufferSize.set(Integer.parseInt(size));
119                             } else {
120                                 LOGGER.warn("No value provide for bufferSize parameter");
121                             }
122                             break;
123                         }
124                         case MAX_BACKUP_INDEX: {
125                             String size = currentElement.getAttribute(VALUE_ATTR);
126                             if (size != null) {
127                                 maxBackups.set(size);
128                             } else {
129                                 LOGGER.warn("No value provide for maxBackupIndex parameter");
130                             }
131                             break;
132                         }
133                         case MAX_SIZE_PARAM: {
134                             String size = currentElement.getAttribute(VALUE_ATTR);
135                             if (size != null) {
136                                 maxSize.set(size);
137                             } else {
138                                 LOGGER.warn("No value provide for bufferSize parameter");
139                             }
140                             break;
141                         }
142                         case THRESHOLD_PARAM: {
143                             String value = currentElement.getAttribute(VALUE_ATTR);
144                             if (value == null) {
145                                 LOGGER.warn("No value supplied for Threshold parameter, ignoring.");
146                             } else {
147                                 level.set(value);
148                             }
149                             break;
150                         }
151                     }
152                     break;
153                 }
154             }
155         });
156         return createAppender(name, config, layout.get(), filter.get(), bufferedIo.get(), immediateFlush.get(),
157                 fileName.get(), level.get(), maxSize.get(), maxBackups.get());
158     }
159 
160 
161     @Override
162     public Appender parseAppender(final String name, final String appenderPrefix, final String layoutPrefix,
163             final String filterPrefix, final Properties props, final PropertiesConfiguration configuration) {
164         Layout layout = configuration.parseLayout(layoutPrefix, name, props);
165         Filter filter = configuration.parseAppenderFilters(props, filterPrefix, name);
166         String fileName = getProperty(FILE_PARAM);
167         String level = getProperty(THRESHOLD_PARAM);
168         boolean immediateFlush = false;
169         boolean bufferedIo = getBooleanProperty(BUFFERED_IO_PARAM);
170         String maxSize = getProperty(MAX_SIZE_PARAM);
171         String maxBackups = getProperty(MAX_BACKUP_INDEX);
172         return createAppender(name, configuration, layout, filter, bufferedIo, immediateFlush, fileName, level, maxSize,
173                 maxBackups);
174     }
175 
176     private Appender createAppender(final String name, final Log4j1Configuration config, final Layout layout,
177             final Filter filter, final boolean bufferedIo, boolean immediateFlush, final String fileName,
178             final String level, final String maxSize, final String maxBackups) {
179         org.apache.logging.log4j.core.Layout<?> fileLayout = null;
180         if (!bufferedIo) {
181             immediateFlush = true;
182         }
183         if (layout instanceof LayoutWrapper) {
184             fileLayout = ((LayoutWrapper) layout).getLayout();
185         } else if (layout != null) {
186             fileLayout = new LayoutAdapter(layout);
187         }
188         org.apache.logging.log4j.core.Filter fileFilter = buildFilters(level, filter);
189         if (fileName == null) {
190             LOGGER.warn("Unable to create File Appender, no file name provided");
191             return null;
192         }
193         String filePattern = fileName +"%d{yyy-MM-dd}";
194         TriggeringPolicy timePolicy = TimeBasedTriggeringPolicy.newBuilder().withModulate(true).build();
195         SizeBasedTriggeringPolicy sizePolicy = SizeBasedTriggeringPolicy.createPolicy(maxSize);
196         CompositeTriggeringPolicy policy = CompositeTriggeringPolicy.createPolicy(sizePolicy, timePolicy);
197         RolloverStrategy strategy = DefaultRolloverStrategy.newBuilder()
198                 .withConfig(config)
199                 .withMax(maxBackups)
200                 .build();
201         return new AppenderWrapper(RollingFileAppender.newBuilder()
202                 .setName(name)
203                 .setConfiguration(config)
204                 .setLayout(fileLayout)
205                 .setFilter(fileFilter)
206                 .withBufferedIo(bufferedIo)
207                 .withImmediateFlush(immediateFlush)
208                 .withFileName(fileName)
209                 .withFilePattern(filePattern)
210                 .withPolicy(policy)
211                 .withStrategy(strategy)
212                 .build());
213     }
214 }