1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.config;
18
19 import org.apache.logging.log4j.Level;
20 import org.apache.logging.log4j.LogManager;
21 import org.apache.logging.log4j.Logger;
22 import org.apache.logging.log4j.Marker;
23 import org.apache.logging.log4j.core.Appender;
24 import org.apache.logging.log4j.core.Filter;
25 import org.apache.logging.log4j.core.LifeCycle;
26 import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
27 import org.apache.logging.log4j.core.filter.AbstractFilterable;
28 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
29 import org.apache.logging.log4j.core.LogEvent;
30 import org.apache.logging.log4j.core.impl.LogEventFactory;
31 import org.apache.logging.log4j.core.config.plugins.Plugin;
32 import org.apache.logging.log4j.core.config.plugins.PluginAttr;
33 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
34 import org.apache.logging.log4j.core.config.plugins.PluginElement;
35 import org.apache.logging.log4j.status.StatusLogger;
36 import org.apache.logging.log4j.message.Message;
37
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.Collection;
41 import java.util.HashMap;
42 import java.util.Iterator;
43 import java.util.List;
44 import java.util.Locale;
45 import java.util.Map;
46 import java.util.concurrent.ConcurrentHashMap;
47 import java.util.concurrent.atomic.AtomicInteger;
48
49
50
51
52 @Plugin(name = "logger", type = "Core", printObject = true)
53 public class LoggerConfig extends AbstractFilterable implements LogEventFactory {
54
55 private static final Logger LOGGER = StatusLogger.getLogger();
56 private static final int MAX_RETRIES = 3;
57 private static final long WAIT_TIME = 1000;
58
59 private List<AppenderRef> appenderRefs = new ArrayList<AppenderRef>();
60 private Map<String, AppenderControl> appenders = new ConcurrentHashMap<String, AppenderControl>();
61 private final String name;
62 private LogEventFactory logEventFactory;
63 private Level level;
64 private boolean additive = true;
65 private LoggerConfig parent;
66 private AtomicInteger counter = new AtomicInteger();
67 private boolean shutdown = false;
68 private final Map<Property, Boolean> properties;
69 private final Configuration config;
70
71
72
73
74
75 public LoggerConfig() {
76 this.logEventFactory = this;
77 this.level = Level.ERROR;
78 this.name = "";
79 this.properties = null;
80 this.config = null;
81 }
82
83
84
85
86
87
88
89 public LoggerConfig(String name, Level level, boolean additive) {
90 this.logEventFactory = this;
91 this.name = name;
92 this.level = level;
93 this.additive = additive;
94 this.properties = null;
95 this.config = null;
96 }
97
98 protected LoggerConfig(String name, List<AppenderRef> appenders, Filter filter, Level level,
99 boolean additive, Property[] properties, Configuration config) {
100 super(filter);
101 this.logEventFactory = this;
102 this.name = name;
103 this.appenderRefs = appenders;
104 this.level = level;
105 this.additive = additive;
106 this.config = config;
107 if (properties != null && properties.length > 0) {
108 this.properties = new HashMap<Property, Boolean>(properties.length);
109 for (Property prop : properties) {
110 boolean interpolate = prop.getValue().contains("${");
111 this.properties.put(prop, interpolate);
112 }
113 } else {
114 this.properties = null;
115 }
116 }
117
118 @Override
119 public Filter getFilter() {
120 return super.getFilter();
121 }
122
123
124
125
126
127 public String getName() {
128 return name;
129 }
130
131
132
133
134
135 public void setParent(LoggerConfig parent) {
136 this.parent = parent;
137 }
138
139
140
141
142
143 public LoggerConfig getParent() {
144 return this.parent;
145 }
146
147
148
149
150
151
152
153 public void addAppender(Appender appender, Level level, Filter filter) {
154 appenders.put(appender.getName(), new AppenderControl(appender, level, filter));
155 }
156
157
158
159
160
161 public void removeAppender(String name) {
162 AppenderControl ctl = appenders.remove(name);
163 if (ctl != null) {
164 cleanupFilter(ctl);
165 }
166 }
167
168
169
170
171
172 public Map<String, Appender> getAppenders() {
173 Map<String, Appender> map = new HashMap<String, Appender>();
174 for (Map.Entry<String, AppenderControl> entry : appenders.entrySet()) {
175 map.put(entry.getKey(), entry.getValue().getAppender());
176 }
177 return map;
178 }
179
180
181
182
183 protected void clearAppenders() {
184 waitForCompletion();
185 Collection<AppenderControl> controls = appenders.values();
186 Iterator<AppenderControl> iterator = controls.iterator();
187 while (iterator.hasNext()) {
188 AppenderControl ctl = iterator.next();
189 iterator.remove();
190 cleanupFilter(ctl);
191 }
192 }
193
194 private void cleanupFilter(AppenderControl ctl) {
195 Filter filter = ctl.getFilter();
196 if (filter != null) {
197 ctl.removeFilter(filter);
198 if (filter instanceof LifeCycle) {
199 ((LifeCycle) filter).stop();
200 }
201 }
202 }
203
204
205
206
207
208 public List<AppenderRef> getAppenderRefs() {
209 return appenderRefs;
210 }
211
212
213
214
215
216 public void setLevel(Level level) {
217 this.level = level;
218 }
219
220
221
222
223
224 public Level getLevel() {
225 return level;
226 }
227
228
229
230
231
232 public LogEventFactory getLogEventFactory() {
233 return logEventFactory;
234 }
235
236
237
238
239
240 public void setLogEventFactory(LogEventFactory logEventFactory) {
241 this.logEventFactory = logEventFactory;
242 }
243
244
245
246
247
248 public boolean isAdditive() {
249 return additive;
250 }
251
252
253
254
255
256 public void setAdditive(boolean additive) {
257 this.additive = additive;
258 }
259
260
261
262
263
264
265
266
267
268
269 public void log(String loggerName, Marker marker, String fqcn, Level level, Message data, Throwable t) {
270 List<Property> props = null;
271 if (properties != null) {
272 props = new ArrayList<Property>(properties.size());
273
274 for (Map.Entry<Property, Boolean> entry : properties.entrySet()) {
275 Property prop = entry.getKey();
276 String value = entry.getValue() ? config.getSubst().replace(prop.getValue()) : prop.getValue();
277 props.add(Property.createProperty(prop.getName(), value));
278 }
279 }
280 LogEvent event = logEventFactory.createEvent(loggerName, marker, fqcn, level, data, props, t);
281 log(event);
282 }
283
284
285
286
287 private synchronized void waitForCompletion() {
288 if (shutdown) {
289 return;
290 }
291 shutdown = true;
292 int retries = 0;
293 while (counter.get() > 0) {
294 try {
295 wait(WAIT_TIME * (retries + 1));
296 } catch (InterruptedException ie) {
297 if (++retries > MAX_RETRIES) {
298 break;
299 }
300 }
301 }
302 }
303
304
305
306
307
308 public void log(LogEvent event) {
309
310 counter.incrementAndGet();
311 try {
312 if (isFiltered(event)) {
313 return;
314 }
315
316 callAppenders(event);
317
318 if (additive && parent != null) {
319 parent.log(event);
320 }
321 } finally {
322 if (counter.decrementAndGet() == 0) {
323 synchronized (this) {
324 if (shutdown) {
325 notifyAll();
326 }
327 }
328
329 }
330 }
331 }
332
333 private void callAppenders(LogEvent event) {
334 for (AppenderControl control : appenders.values()) {
335 control.callAppender(event);
336 }
337 }
338
339
340
341
342
343
344
345
346
347
348
349 public LogEvent createEvent(String loggerName, Marker marker, String fqcn, Level level, Message data,
350 List<Property> properties, Throwable t) {
351 return new Log4jLogEvent(loggerName, marker, fqcn, level, data, properties, t);
352 }
353
354 @Override
355 public String toString() {
356 return name == null || name.length() == 0 ? "root" : name;
357 }
358
359
360
361
362
363
364
365
366
367
368 @PluginFactory
369 public static LoggerConfig createLogger(@PluginAttr("additivity") String additivity,
370 @PluginAttr("level") String levelName,
371 @PluginAttr("name") String loggerName,
372 @PluginElement("appender-ref") AppenderRef[] refs,
373 @PluginElement("properties") Property[] properties,
374 @PluginConfiguration Configuration config,
375 @PluginElement("filters") Filter filter) {
376 if (loggerName == null) {
377 LOGGER.error("Loggers cannot be configured without a name");
378 return null;
379 }
380
381 List<AppenderRef> appenderRefs = Arrays.asList(refs);
382 Level level;
383 try {
384 level = Level.toLevel(levelName, Level.ERROR);
385 } catch (Exception ex) {
386 LOGGER.error("Invalid Log level specified: {}. Defaulting to Error", levelName);
387 level = Level.ERROR;
388 }
389 String name = loggerName.equals("root") ? "" : loggerName;
390 boolean additive = additivity == null ? true : Boolean.parseBoolean(additivity);
391
392 return new LoggerConfig(name, appenderRefs, filter, level, additive, properties, config);
393 }
394
395
396
397
398 @Plugin(name = "root", type = "Core", printObject = true)
399 public static class RootLogger extends LoggerConfig {
400
401 @PluginFactory
402 public static LoggerConfig createLogger(@PluginAttr("additivity") String additivity,
403 @PluginAttr("level") String levelName,
404 @PluginElement("appender-ref") AppenderRef[] refs,
405 @PluginElement("properties") Property[] properties,
406 @PluginConfiguration Configuration config,
407 @PluginElement("filters") Filter filter) {
408 List<AppenderRef> appenderRefs = Arrays.asList(refs);
409 Level level;
410 try {
411 level = Level.toLevel(levelName, Level.ERROR);
412 } catch (Exception ex) {
413 LOGGER.error("Invalid Log level specified: {}. Defaulting to Error", levelName);
414 level = Level.ERROR;
415 }
416 boolean additive = additivity == null ? true : Boolean.parseBoolean(additivity);
417
418 return new LoggerConfig(LogManager.ROOT_LOGGER_NAME, appenderRefs, filter, level, additive, properties,
419 config);
420 }
421 }
422
423 }