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