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