1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
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 }