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