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.LogEvent;
27 import org.apache.logging.log4j.core.async.AsyncLoggerContextSelector;
28 import org.apache.logging.log4j.core.config.plugins.Plugin;
29 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
30 import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
31 import org.apache.logging.log4j.core.config.plugins.PluginElement;
32 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
33 import org.apache.logging.log4j.core.filter.AbstractFilterable;
34 import org.apache.logging.log4j.core.helpers.Booleans;
35 import org.apache.logging.log4j.core.helpers.Constants;
36 import org.apache.logging.log4j.core.helpers.Loader;
37 import org.apache.logging.log4j.core.helpers.Strings;
38 import org.apache.logging.log4j.core.impl.DefaultLogEventFactory;
39 import org.apache.logging.log4j.core.impl.LogEventFactory;
40 import org.apache.logging.log4j.core.lookup.StrSubstitutor;
41 import org.apache.logging.log4j.message.Message;
42 import org.apache.logging.log4j.status.StatusLogger;
43 import org.apache.logging.log4j.util.PropertiesUtil;
44
45 import java.util.ArrayList;
46 import java.util.Arrays;
47 import java.util.Collection;
48 import java.util.Collections;
49 import java.util.HashMap;
50 import java.util.Iterator;
51 import java.util.List;
52 import java.util.Map;
53 import java.util.concurrent.ConcurrentHashMap;
54 import java.util.concurrent.atomic.AtomicInteger;
55
56
57
58
59 @Plugin(name = "logger", category = "Core", printObject = true)
60 public class LoggerConfig extends AbstractFilterable {
61
62 protected static final Logger LOGGER = StatusLogger.getLogger();
63 private static final int MAX_RETRIES = 3;
64 private static final long WAIT_TIME = 1000;
65 private static LogEventFactory LOG_EVENT_FACTORY = null;
66
67 private List<AppenderRef> appenderRefs = new ArrayList<AppenderRef>();
68 private final Map<String, AppenderControl> appenders = new ConcurrentHashMap<String, AppenderControl>();
69 private final String name;
70 private LogEventFactory logEventFactory;
71 private Level level;
72 private boolean additive = true;
73 private boolean includeLocation = true;
74 private LoggerConfig parent;
75 private final AtomicInteger counter = new AtomicInteger();
76 private boolean shutdown = false;
77 private final Map<Property, Boolean> properties;
78 private final Configuration config;
79
80 static {
81 final String factory = PropertiesUtil.getProperties().getStringProperty(Constants.LOG4J_LOG_EVENT_FACTORY);
82 if (factory != null) {
83 try {
84 final Class<?> clazz = Loader.loadClass(factory);
85 if (clazz != null && LogEventFactory.class.isAssignableFrom(clazz)) {
86 LOG_EVENT_FACTORY = (LogEventFactory) clazz.newInstance();
87 }
88 } catch (final Exception ex) {
89 LOGGER.error("Unable to create LogEventFactory " + factory, ex);
90 }
91 }
92 if (LOG_EVENT_FACTORY == null) {
93 LOG_EVENT_FACTORY = new DefaultLogEventFactory();
94 }
95 }
96
97
98
99
100 public LoggerConfig() {
101 this.logEventFactory = LOG_EVENT_FACTORY;
102 this.level = Level.ERROR;
103 this.name = "";
104 this.properties = null;
105 this.config = null;
106 }
107
108
109
110
111
112
113
114
115 public LoggerConfig(final String name, final Level level,
116 final boolean additive) {
117 this.logEventFactory = LOG_EVENT_FACTORY;
118 this.name = name;
119 this.level = level;
120 this.additive = additive;
121 this.properties = null;
122 this.config = null;
123 }
124
125 protected LoggerConfig(final String name,
126 final List<AppenderRef> appenders, final Filter filter,
127 final Level level, final boolean additive,
128 final Property[] properties, final Configuration config,
129 final boolean includeLocation) {
130 super(filter);
131 this.logEventFactory = LOG_EVENT_FACTORY;
132 this.name = name;
133 this.appenderRefs = appenders;
134 this.level = level;
135 this.additive = additive;
136 this.includeLocation = includeLocation;
137 this.config = config;
138 if (properties != null && properties.length > 0) {
139 this.properties = new HashMap<Property, Boolean>(properties.length);
140 for (final Property prop : properties) {
141 final boolean interpolate = prop.getValue().contains("${");
142 this.properties.put(prop, interpolate);
143 }
144 } else {
145 this.properties = null;
146 }
147 }
148
149 @Override
150 public Filter getFilter() {
151 return super.getFilter();
152 }
153
154
155
156
157
158
159 public String getName() {
160 return name;
161 }
162
163
164
165
166
167
168 public void setParent(final LoggerConfig parent) {
169 this.parent = parent;
170 }
171
172
173
174
175
176
177 public LoggerConfig getParent() {
178 return this.parent;
179 }
180
181
182
183
184
185
186
187
188 public void addAppender(final Appender appender, final Level level,
189 final Filter filter) {
190 appenders.put(appender.getName(), new AppenderControl(appender, level,
191 filter));
192 }
193
194
195
196
197
198
199 public void removeAppender(final String name) {
200 final AppenderControl ctl = appenders.remove(name);
201 if (ctl != null) {
202 cleanupFilter(ctl);
203 }
204 }
205
206
207
208
209
210
211
212 public Map<String, Appender> getAppenders() {
213 final Map<String, Appender> map = new HashMap<String, Appender>();
214 for (final Map.Entry<String, AppenderControl> entry : appenders
215 .entrySet()) {
216 map.put(entry.getKey(), entry.getValue().getAppender());
217 }
218 return map;
219 }
220
221
222
223
224 protected void clearAppenders() {
225 waitForCompletion();
226 final Collection<AppenderControl> controls = appenders.values();
227 final Iterator<AppenderControl> iterator = controls.iterator();
228 while (iterator.hasNext()) {
229 final AppenderControl ctl = iterator.next();
230 iterator.remove();
231 cleanupFilter(ctl);
232 }
233 }
234
235 private void cleanupFilter(final AppenderControl ctl) {
236 final Filter filter = ctl.getFilter();
237 if (filter != null) {
238 ctl.removeFilter(filter);
239 if (filter instanceof LifeCycle) {
240 ((LifeCycle) filter).stop();
241 }
242 }
243 }
244
245
246
247
248
249
250 public List<AppenderRef> getAppenderRefs() {
251 return appenderRefs;
252 }
253
254
255
256
257
258
259 public void setLevel(final Level level) {
260 this.level = level;
261 }
262
263
264
265
266
267
268 public Level getLevel() {
269 return level;
270 }
271
272
273
274
275
276
277 public LogEventFactory getLogEventFactory() {
278 return logEventFactory;
279 }
280
281
282
283
284
285
286
287 public void setLogEventFactory(final LogEventFactory logEventFactory) {
288 this.logEventFactory = logEventFactory;
289 }
290
291
292
293
294
295
296 public boolean isAdditive() {
297 return additive;
298 }
299
300
301
302
303
304
305
306 public void setAdditive(final boolean additive) {
307 this.additive = additive;
308 }
309
310
311
312
313
314
315
316
317 public boolean isIncludeLocation() {
318 return includeLocation;
319 }
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335 public Map<Property, Boolean> getProperties() {
336 return properties == null ? null : Collections
337 .unmodifiableMap(properties);
338 }
339
340
341
342
343
344
345
346
347
348
349
350 public void log(final String loggerName, final Marker marker,
351 final String fqcn, final Level level, final Message data,
352 final Throwable t) {
353 List<Property> props = null;
354 if (properties != null) {
355 props = new ArrayList<Property>(properties.size());
356
357 for (final Map.Entry<Property, Boolean> entry : properties
358 .entrySet()) {
359 final Property prop = entry.getKey();
360 final String value = entry.getValue() ? config.getStrSubstitutor()
361 .replace(prop.getValue()) : prop.getValue();
362 props.add(Property.createProperty(prop.getName(), value));
363 }
364 }
365 final LogEvent event = logEventFactory.createEvent(loggerName, marker,
366 fqcn, level, data, props, t);
367 log(event);
368 }
369
370
371
372
373
374 private synchronized void waitForCompletion() {
375 if (shutdown) {
376 return;
377 }
378 shutdown = true;
379 int retries = 0;
380 while (counter.get() > 0) {
381 try {
382 wait(WAIT_TIME * (retries + 1));
383 } catch (final InterruptedException ie) {
384 if (++retries > MAX_RETRIES) {
385 break;
386 }
387 }
388 }
389 }
390
391
392
393
394
395
396 public void log(final LogEvent event) {
397
398 counter.incrementAndGet();
399 try {
400 if (isFiltered(event)) {
401 return;
402 }
403
404 event.setIncludeLocation(isIncludeLocation());
405
406 callAppenders(event);
407
408 if (additive && parent != null) {
409 parent.log(event);
410 }
411 } finally {
412 if (counter.decrementAndGet() == 0) {
413 synchronized (this) {
414 if (shutdown) {
415 notifyAll();
416 }
417 }
418
419 }
420 }
421 }
422
423 protected void callAppenders(final LogEvent event) {
424 for (final AppenderControl control : appenders.values()) {
425 control.callAppender(event);
426 }
427 }
428
429
430 @Override
431 public String toString() {
432 return Strings.isEmpty(name) ? "root" : name;
433 }
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448 @PluginFactory
449 public static LoggerConfig createLogger(
450 @PluginAttribute("additivity") final String additivity,
451 @PluginAttribute("level") final String levelName,
452 @PluginAttribute("name") final String loggerName,
453 @PluginAttribute("includeLocation") final String includeLocation,
454 @PluginElement("AppenderRef") final AppenderRef[] refs,
455 @PluginElement("Properties") final Property[] properties,
456 @PluginConfiguration final Configuration config,
457 @PluginElement("Filters") final Filter filter) {
458 if (loggerName == null) {
459 LOGGER.error("Loggers cannot be configured without a name");
460 return null;
461 }
462
463 final List<AppenderRef> appenderRefs = Arrays.asList(refs);
464 Level level;
465 try {
466 level = Level.toLevel(levelName, Level.ERROR);
467 } catch (final Exception ex) {
468 LOGGER.error(
469 "Invalid Log level specified: {}. Defaulting to Error",
470 levelName);
471 level = Level.ERROR;
472 }
473 final String name = loggerName.equals("root") ? "" : loggerName;
474 final boolean additive = Booleans.parseBoolean(additivity, true);
475
476 return new LoggerConfig(name, appenderRefs, filter, level, additive,
477 properties, config, includeLocation(includeLocation));
478 }
479
480
481
482 protected static boolean includeLocation(final String includeLocationConfigValue) {
483 if (includeLocationConfigValue == null) {
484 final boolean sync = !AsyncLoggerContextSelector.class.getName()
485 .equals(System.getProperty(Constants.LOG4J_CONTEXT_SELECTOR));
486 return sync;
487 }
488 return Boolean.parseBoolean(includeLocationConfigValue);
489 }
490
491
492
493
494 @Plugin(name = "root", category = "Core", printObject = true)
495 public static class RootLogger extends LoggerConfig {
496
497 @PluginFactory
498 public static LoggerConfig createLogger(
499 @PluginAttribute("additivity") final String additivity,
500 @PluginAttribute("level") final String levelName,
501 @PluginAttribute("includeLocation") final String includeLocation,
502 @PluginElement("AppenderRef") final AppenderRef[] refs,
503 @PluginElement("Properties") final Property[] properties,
504 @PluginConfiguration final Configuration config,
505 @PluginElement("Filters") final Filter filter) {
506 final List<AppenderRef> appenderRefs = Arrays.asList(refs);
507 Level level;
508 try {
509 level = Level.toLevel(levelName, Level.ERROR);
510 } catch (final Exception ex) {
511 LOGGER.error(
512 "Invalid Log level specified: {}. Defaulting to Error",
513 levelName);
514 level = Level.ERROR;
515 }
516 final boolean additive = Booleans.parseBoolean(additivity, true);
517
518 return new LoggerConfig(LogManager.ROOT_LOGGER_NAME, appenderRefs,
519 filter, level, additive, properties, config,
520 includeLocation(includeLocation));
521 }
522 }
523
524 }