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 shutdownThread = new ShutdownThread(this);
151 try {
152 Runtime.getRuntime().addShutdownHook(shutdownThread);
153 } catch (SecurityException se) {
154 LOGGER.warn("Unable to register shutdown hook due to security restrictions");
155 shutdownThread = null;
156 }
157 status = Status.STARTED;
158 }
159 } finally {
160 configLock.unlock();
161 }
162 }
163 }
164
165
166
167
168
169 public void start(final Configuration config) {
170 if (configLock.tryLock()) {
171 try {
172 if (status == Status.INITIALIZED || status == Status.STOPPED) {
173 shutdownThread = new ShutdownThread(this);
174 try {
175 Runtime.getRuntime().addShutdownHook(shutdownThread);
176 } catch (SecurityException se) {
177 LOGGER.warn("Unable to register shutdown hook due to security restrictions");
178 shutdownThread = null;
179 }
180 status = Status.STARTED;
181 }
182 } finally {
183 configLock.unlock();
184 }
185 }
186 setConfiguration(config);
187 }
188
189 @Override
190 public void stop() {
191 configLock.lock();
192 try {
193 if (status == Status.STOPPED) {
194 return;
195 }
196 status = Status.STOPPING;
197 if (shutdownThread != null) {
198 Runtime.getRuntime().removeShutdownHook(shutdownThread);
199 shutdownThread = null;
200 }
201 Configuration prev = config;
202 config = new NullConfiguration();
203 updateLoggers();
204 prev.stop();
205 externalContext = null;
206 LogManager.getFactory().removeContext(this);
207 status = Status.STOPPED;
208 } finally {
209 configLock.unlock();
210 }
211 }
212
213
214
215
216
217
218 public String getName() {
219 return name;
220 }
221
222 public Status getStatus() {
223 return status;
224 }
225
226 @Override
227 public boolean isStarted() {
228 return status == Status.STARTED;
229 }
230
231
232
233
234
235 public void setExternalContext(final Object context) {
236 this.externalContext = context;
237 }
238
239
240
241
242
243 @Override
244 public Object getExternalContext() {
245 return this.externalContext;
246 }
247
248
249
250
251
252
253 @Override
254 public Logger getLogger(final String name) {
255 return getLogger(name, null);
256 }
257
258
259
260
261
262
263
264
265
266 @Override
267 public Logger getLogger(final String name, final MessageFactory messageFactory) {
268 Logger logger = loggers.get(name);
269 if (logger != null) {
270 AbstractLogger.checkMessageFactory(logger, messageFactory);
271 return logger;
272 }
273
274 logger = newInstance(this, name, messageFactory);
275 final Logger prev = loggers.putIfAbsent(name, logger);
276 return prev == null ? logger : prev;
277 }
278
279
280
281
282
283
284 @Override
285 public boolean hasLogger(final String name) {
286 return loggers.containsKey(name);
287 }
288
289
290
291
292
293
294
295 public Configuration getConfiguration() {
296 return config;
297 }
298
299
300
301
302
303
304 public void addFilter(final Filter filter) {
305 config.addFilter(filter);
306 }
307
308
309
310
311
312 public void removeFilter(final Filter filter) {
313 config.removeFilter(filter);
314 }
315
316
317
318
319
320
321 private synchronized Configuration setConfiguration(final Configuration config) {
322 if (config == null) {
323 throw new NullPointerException("No Configuration was provided");
324 }
325 final Configuration prev = this.config;
326 config.addListener(this);
327 final Map<String, String> map = new HashMap<String, String>();
328 map.put("hostName", NetUtils.getLocalHostname());
329 map.put("contextName", name);
330 config.addComponent(Configuration.CONTEXT_PROPERTIES, map);
331 config.start();
332 this.config = config;
333 updateLoggers();
334 if (prev != null) {
335 prev.removeListener(this);
336 prev.stop();
337 }
338
339
340 PropertyChangeEvent evt = new PropertyChangeEvent(this, PROPERTY_CONFIG, prev, config);
341 for (PropertyChangeListener listener : propertyChangeListeners) {
342 listener.propertyChange(evt);
343 }
344 return prev;
345 }
346
347 public void addPropertyChangeListener(PropertyChangeListener listener) {
348 propertyChangeListeners.add(Assert.isNotNull(listener, "listener"));
349 }
350
351 public void removePropertyChangeListener(PropertyChangeListener listener) {
352 propertyChangeListeners.remove(listener);
353 }
354
355 public synchronized URI getConfigLocation() {
356 return configLocation;
357 }
358
359 public synchronized void setConfigLocation(URI configLocation) {
360 this.configLocation = configLocation;
361 reconfigure();
362 }
363
364
365
366
367 public synchronized void reconfigure() {
368 LOGGER.debug("Reconfiguration started for context " + name);
369 final Configuration instance = ConfigurationFactory.getInstance().getConfiguration(name, configLocation);
370 setConfiguration(instance);
371
372
373
374
375 LOGGER.debug("Reconfiguration completed");
376 }
377
378
379
380
381 public void updateLoggers() {
382 updateLoggers(this.config);
383 }
384
385
386
387
388
389 public void updateLoggers(final Configuration config) {
390 for (final Logger logger : loggers.values()) {
391 logger.updateConfiguration(config);
392 }
393 }
394
395
396
397
398
399
400
401 @Override
402 public synchronized void onChange(final Reconfigurable reconfigurable) {
403 LOGGER.debug("Reconfiguration started for context " + name);
404 final Configuration config = reconfigurable.reconfigure();
405 if (config != null) {
406 setConfiguration(config);
407 LOGGER.debug("Reconfiguration completed");
408 } else {
409 LOGGER.debug("Reconfiguration failed");
410 }
411 }
412
413
414 protected Logger newInstance(final LoggerContext ctx, final String name, final MessageFactory messageFactory) {
415 return new Logger(ctx, name, messageFactory);
416 }
417
418 private class ShutdownThread extends Thread {
419
420 private final LoggerContext context;
421
422 public ShutdownThread(LoggerContext context) {
423 this.context = context;
424 }
425
426 @Override
427 public void run() {
428 context.shutdownThread = null;
429 context.stop();
430 }
431 }
432
433 }