1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core;
18
19 import java.beans.PropertyChangeEvent;
20 import java.beans.PropertyChangeListener;
21 import java.io.File;
22 import java.net.URI;
23 import java.util.HashMap;
24 import java.util.Map;
25 import java.util.concurrent.ConcurrentHashMap;
26 import java.util.concurrent.ConcurrentMap;
27 import java.util.concurrent.CopyOnWriteArrayList;
28 import java.util.concurrent.locks.Lock;
29 import java.util.concurrent.locks.ReentrantLock;
30
31 import org.apache.logging.log4j.LogManager;
32 import org.apache.logging.log4j.core.config.Configuration;
33 import org.apache.logging.log4j.core.config.ConfigurationFactory;
34 import org.apache.logging.log4j.core.config.ConfigurationListener;
35 import org.apache.logging.log4j.core.config.DefaultConfiguration;
36 import org.apache.logging.log4j.core.config.NullConfiguration;
37 import org.apache.logging.log4j.core.config.Reconfigurable;
38 import org.apache.logging.log4j.core.helpers.Assert;
39 import org.apache.logging.log4j.core.helpers.NetUtils;
40 import org.apache.logging.log4j.message.MessageFactory;
41 import org.apache.logging.log4j.spi.AbstractLogger;
42 import org.apache.logging.log4j.status.StatusLogger;
43
44
45
46
47
48
49
50
51 public class LoggerContext implements org.apache.logging.log4j.spi.LoggerContext, ConfigurationListener, LifeCycle {
52
53 public static final String PROPERTY_CONFIG = "config";
54 private static final StatusLogger LOGGER = StatusLogger.getLogger();
55
56 private final ConcurrentMap<String, Logger> loggers = new ConcurrentHashMap<String, Logger>();
57 private final CopyOnWriteArrayList<PropertyChangeListener> propertyChangeListeners = new CopyOnWriteArrayList<PropertyChangeListener>();
58
59
60
61
62
63 private volatile Configuration config = new DefaultConfiguration();
64 private Object externalContext;
65 private final String name;
66 private URI configLocation;
67
68 private ShutdownThread shutdownThread = null;
69
70
71
72
73 public enum Status {
74
75 INITIALIZED,
76
77 STARTING,
78
79 STARTED,
80
81 STOPPING,
82
83 STOPPED
84 }
85
86 private volatile Status status = Status.INITIALIZED;
87
88 private final Lock configLock = new ReentrantLock();
89
90
91
92
93
94 public LoggerContext(final String name) {
95 this(name, null, (URI) null);
96 }
97
98
99
100
101
102
103 public LoggerContext(final String name, final Object externalContext) {
104 this(name, externalContext, (URI) null);
105 }
106
107
108
109
110
111
112
113 public LoggerContext(final String name, final Object externalContext, final URI configLocn) {
114 this.name = name;
115 this.externalContext = externalContext;
116 this.configLocation = configLocn;
117 }
118
119
120
121
122
123
124
125
126
127 public LoggerContext(final String name, final Object externalContext, final String configLocn) {
128 this.name = name;
129 this.externalContext = externalContext;
130 if (configLocn != null) {
131 URI uri;
132 try {
133 uri = new File(configLocn).toURI();
134 } catch (final Exception ex) {
135 uri = null;
136 }
137 configLocation = uri;
138 } else {
139 configLocation = null;
140 }
141 }
142
143 @Override
144 public void start() {
145 if (configLock.tryLock()) {
146 try {
147 if ((status == Status.INITIALIZED || status == Status.STOPPED)) {
148 status = Status.STARTING;
149 reconfigure();
150 if (config.isShutdownHookEnabled()) {
151 shutdownThread = new ShutdownThread(this);
152 try {
153 Runtime.getRuntime().addShutdownHook(shutdownThread);
154 } catch (final IllegalStateException ise) {
155 LOGGER.warn("Unable to register shutdown hook due to JVM state");
156 shutdownThread = null;
157 } catch (final SecurityException se) {
158 LOGGER.warn("Unable to register shutdown hook due to security restrictions");
159 shutdownThread = null;
160 }
161 }
162 status = Status.STARTED;
163 }
164 } finally {
165 configLock.unlock();
166 }
167 }
168 }
169
170
171
172
173
174 public void start(final Configuration config) {
175 if (configLock.tryLock()) {
176 try {
177 if ((status == Status.INITIALIZED || status == Status.STOPPED) && config.isShutdownHookEnabled() ) {
178 shutdownThread = new ShutdownThread(this);
179 try {
180 Runtime.getRuntime().addShutdownHook(shutdownThread);
181 } catch (final IllegalStateException ise) {
182 LOGGER.warn("Unable to register shutdown hook due to JVM state");
183 shutdownThread = null;
184 } catch (final SecurityException se) {
185 LOGGER.warn("Unable to register shutdown hook due to security restrictions");
186 shutdownThread = null;
187 }
188 status = Status.STARTED;
189 }
190 } finally {
191 configLock.unlock();
192 }
193 }
194 setConfiguration(config);
195 }
196
197 @Override
198 public void stop() {
199 configLock.lock();
200 try {
201 if (status == Status.STOPPED) {
202 return;
203 }
204 status = Status.STOPPING;
205 if (shutdownThread != null) {
206 Runtime.getRuntime().removeShutdownHook(shutdownThread);
207 shutdownThread = null;
208 }
209 final Configuration prev = config;
210 config = new NullConfiguration();
211 updateLoggers();
212 prev.stop();
213 externalContext = null;
214 LogManager.getFactory().removeContext(this);
215 status = Status.STOPPED;
216 } finally {
217 configLock.unlock();
218 }
219 }
220
221
222
223
224
225
226 public String getName() {
227 return name;
228 }
229
230 public Status getStatus() {
231 return status;
232 }
233
234 @Override
235 public boolean isStarted() {
236 return status == Status.STARTED;
237 }
238
239
240
241
242
243 public void setExternalContext(final Object context) {
244 this.externalContext = context;
245 }
246
247
248
249
250
251 @Override
252 public Object getExternalContext() {
253 return this.externalContext;
254 }
255
256
257
258
259
260
261 @Override
262 public Logger getLogger(final String name) {
263 return getLogger(name, null);
264 }
265
266
267
268
269
270
271
272
273
274 @Override
275 public Logger getLogger(final String name, final MessageFactory messageFactory) {
276 Logger logger = loggers.get(name);
277 if (logger != null) {
278 AbstractLogger.checkMessageFactory(logger, messageFactory);
279 return logger;
280 }
281
282 logger = newInstance(this, name, messageFactory);
283 final Logger prev = loggers.putIfAbsent(name, logger);
284 return prev == null ? logger : prev;
285 }
286
287
288
289
290
291
292 @Override
293 public boolean hasLogger(final String name) {
294 return loggers.containsKey(name);
295 }
296
297
298
299
300
301
302
303 public Configuration getConfiguration() {
304 return config;
305 }
306
307
308
309
310
311
312 public void addFilter(final Filter filter) {
313 config.addFilter(filter);
314 }
315
316
317
318
319
320 public void removeFilter(final Filter filter) {
321 config.removeFilter(filter);
322 }
323
324
325
326
327
328
329 private synchronized Configuration setConfiguration(final Configuration config) {
330 if (config == null) {
331 throw new NullPointerException("No Configuration was provided");
332 }
333 final Configuration prev = this.config;
334 config.addListener(this);
335 final Map<String, String> map = new HashMap<String, String>();
336 map.put("hostName", NetUtils.getLocalHostname());
337 map.put("contextName", name);
338 config.addComponent(Configuration.CONTEXT_PROPERTIES, map);
339 config.start();
340 this.config = config;
341 updateLoggers();
342 if (prev != null) {
343 prev.removeListener(this);
344 prev.stop();
345 }
346
347
348 final PropertyChangeEvent evt = new PropertyChangeEvent(this, PROPERTY_CONFIG, prev, config);
349 for (final PropertyChangeListener listener : propertyChangeListeners) {
350 listener.propertyChange(evt);
351 }
352 return prev;
353 }
354
355 public void addPropertyChangeListener(final PropertyChangeListener listener) {
356 propertyChangeListeners.add(Assert.isNotNull(listener, "listener"));
357 }
358
359 public void removePropertyChangeListener(final PropertyChangeListener listener) {
360 propertyChangeListeners.remove(listener);
361 }
362
363 public synchronized URI getConfigLocation() {
364 return configLocation;
365 }
366
367 public synchronized void setConfigLocation(final URI configLocation) {
368 this.configLocation = configLocation;
369 reconfigure();
370 }
371
372
373
374
375 public synchronized void reconfigure() {
376 LOGGER.debug("Reconfiguration started for context " + name);
377 final Configuration instance = ConfigurationFactory.getInstance().getConfiguration(name, configLocation);
378 setConfiguration(instance);
379
380
381
382
383 LOGGER.debug("Reconfiguration completed");
384 }
385
386
387
388
389 public void updateLoggers() {
390 updateLoggers(this.config);
391 }
392
393
394
395
396
397 public void updateLoggers(final Configuration config) {
398 for (final Logger logger : loggers.values()) {
399 logger.updateConfiguration(config);
400 }
401 }
402
403
404
405
406
407
408
409 @Override
410 public synchronized void onChange(final Reconfigurable reconfigurable) {
411 LOGGER.debug("Reconfiguration started for context " + name);
412 final Configuration config = reconfigurable.reconfigure();
413 if (config != null) {
414 setConfiguration(config);
415 LOGGER.debug("Reconfiguration completed");
416 } else {
417 LOGGER.debug("Reconfiguration failed");
418 }
419 }
420
421
422 protected Logger newInstance(final LoggerContext ctx, final String name, final MessageFactory messageFactory) {
423 return new Logger(ctx, name, messageFactory);
424 }
425
426 private class ShutdownThread extends Thread {
427
428 private final LoggerContext context;
429
430 public ShutdownThread(final LoggerContext context) {
431 this.context = context;
432 }
433
434 @Override
435 public void run() {
436 context.shutdownThread = null;
437 context.stop();
438 }
439 }
440
441 }