1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.impl;
18
19 import java.net.URI;
20 import java.util.Objects;
21
22 import org.apache.logging.log4j.core.LifeCycle;
23 import org.apache.logging.log4j.core.LoggerContext;
24 import org.apache.logging.log4j.core.config.Configuration;
25 import org.apache.logging.log4j.core.config.ConfigurationFactory;
26 import org.apache.logging.log4j.core.config.ConfigurationSource;
27 import org.apache.logging.log4j.core.selector.ClassLoaderContextSelector;
28 import org.apache.logging.log4j.core.selector.ContextSelector;
29 import org.apache.logging.log4j.core.util.Cancellable;
30 import org.apache.logging.log4j.core.util.Constants;
31 import org.apache.logging.log4j.core.util.DefaultShutdownCallbackRegistry;
32 import org.apache.logging.log4j.core.util.Loader;
33 import org.apache.logging.log4j.core.util.ShutdownCallbackRegistry;
34 import org.apache.logging.log4j.spi.LoggerContextFactory;
35 import org.apache.logging.log4j.status.StatusLogger;
36 import org.apache.logging.log4j.util.PropertiesUtil;
37
38
39
40
41 public class Log4jContextFactory implements LoggerContextFactory, ShutdownCallbackRegistry {
42
43 private static final StatusLogger LOGGER = StatusLogger.getLogger();
44 private static final boolean SHUTDOWN_HOOK_ENABLED =
45 PropertiesUtil.getProperties().getBooleanProperty(ShutdownCallbackRegistry.SHUTDOWN_HOOK_ENABLED, true);
46
47 private final ContextSelector selector;
48 private final ShutdownCallbackRegistry shutdownCallbackRegistry;
49
50
51
52
53 public Log4jContextFactory() {
54 this(createContextSelector(), createShutdownCallbackRegistry());
55 }
56
57
58
59
60
61 public Log4jContextFactory(final ContextSelector selector) {
62 this(selector, createShutdownCallbackRegistry());
63 }
64
65
66
67
68
69
70
71
72 public Log4jContextFactory(final ShutdownCallbackRegistry shutdownCallbackRegistry) {
73 this(createContextSelector(), shutdownCallbackRegistry);
74 }
75
76
77
78
79
80
81
82
83 public Log4jContextFactory(final ContextSelector selector,
84 final ShutdownCallbackRegistry shutdownCallbackRegistry) {
85 this.selector = Objects.requireNonNull(selector, "No ContextSelector provided");
86 this.shutdownCallbackRegistry = Objects.requireNonNull(shutdownCallbackRegistry, "No ShutdownCallbackRegistry provided");
87 LOGGER.debug("Using ShutdownCallbackRegistry {}", shutdownCallbackRegistry.getClass());
88 initializeShutdownCallbackRegistry();
89 }
90
91 private static ContextSelector createContextSelector() {
92 final String sel = PropertiesUtil.getProperties().getStringProperty(Constants.LOG4J_CONTEXT_SELECTOR);
93 if (sel != null) {
94 try {
95 return Loader.newCheckedInstanceOf(sel, ContextSelector.class);
96 } catch (final Exception ex) {
97 LOGGER.error("Unable to create context {}", sel, ex);
98 }
99 }
100 return new ClassLoaderContextSelector();
101 }
102
103 private static ShutdownCallbackRegistry createShutdownCallbackRegistry() {
104
105 final String registry = PropertiesUtil.getProperties().getStringProperty(
106 ShutdownCallbackRegistry.SHUTDOWN_CALLBACK_REGISTRY);
107 if (registry != null) {
108 try {
109 return Loader.newCheckedInstanceOf(registry, ShutdownCallbackRegistry.class);
110 } catch (final Exception e) {
111 LOGGER.error(SHUTDOWN_HOOK_MARKER,
112 "There was an error loading the ShutdownCallbackRegistry [{}]. "
113 + "Falling back to DefaultShutdownCallbackRegistry.", registry, e);
114 }
115 }
116 return new DefaultShutdownCallbackRegistry();
117 }
118
119 private void initializeShutdownCallbackRegistry() {
120 if (SHUTDOWN_HOOK_ENABLED && this.shutdownCallbackRegistry instanceof LifeCycle) {
121 try {
122 ((LifeCycle) this.shutdownCallbackRegistry).start();
123 } catch (final Exception e) {
124 LOGGER.error("There was an error starting the ShutdownCallbackRegistry.", e);
125 }
126 }
127 }
128
129
130
131
132
133
134
135
136
137
138 @Override
139 public LoggerContext getContext(final String fqcn, final ClassLoader loader, final Object externalContext,
140 final boolean currentContext) {
141 final LoggerContext ctx = selector.getContext(fqcn, loader, currentContext);
142 if (externalContext != null && ctx.getExternalContext() == null) {
143 ctx.setExternalContext(externalContext);
144 }
145 if (ctx.getState() == LifeCycle.State.INITIALIZED) {
146 ctx.start();
147 }
148 return ctx;
149 }
150
151
152
153
154
155
156
157
158
159
160
161 public LoggerContext getContext(final String fqcn, final ClassLoader loader, final Object externalContext,
162 final boolean currentContext, final ConfigurationSource source) {
163 final LoggerContext ctx = selector.getContext(fqcn, loader, currentContext, null);
164 if (externalContext != null && ctx.getExternalContext() == null) {
165 ctx.setExternalContext(externalContext);
166 }
167 if (ctx.getState() == LifeCycle.State.INITIALIZED) {
168 if (source != null) {
169 ContextAnchor.THREAD_CONTEXT.set(ctx);
170 final Configuration config = ConfigurationFactory.getInstance().getConfiguration(source);
171 LOGGER.debug("Starting LoggerContext[name={}] from configuration {}", ctx.getName(), source);
172 ctx.start(config);
173 ContextAnchor.THREAD_CONTEXT.remove();
174 } else {
175 ctx.start();
176 }
177 }
178 return ctx;
179 }
180
181
182
183
184
185
186
187
188
189
190
191 public LoggerContext getContext(final String fqcn, final ClassLoader loader, final Object externalContext,
192 final boolean currentContext, final Configuration configuration) {
193 final LoggerContext ctx = selector.getContext(fqcn, loader, currentContext, null);
194 if (externalContext != null && ctx.getExternalContext() == null) {
195 ctx.setExternalContext(externalContext);
196 }
197 if (ctx.getState() == LifeCycle.State.INITIALIZED) {
198 ContextAnchor.THREAD_CONTEXT.set(ctx);
199 try {
200 ctx.start(configuration);
201 } finally {
202 ContextAnchor.THREAD_CONTEXT.remove();
203 }
204 }
205 return ctx;
206 }
207
208
209
210
211
212
213
214
215
216
217
218 @Override
219 public LoggerContext getContext(final String fqcn, final ClassLoader loader, final Object externalContext,
220 final boolean currentContext, final URI configLocation, final String name) {
221 final LoggerContext ctx = selector.getContext(fqcn, loader, currentContext, configLocation);
222 if (externalContext != null && ctx.getExternalContext() == null) {
223 ctx.setExternalContext(externalContext);
224 }
225 if (ctx.getState() == LifeCycle.State.INITIALIZED) {
226 if (configLocation != null || name != null) {
227 ContextAnchor.THREAD_CONTEXT.set(ctx);
228 final Configuration config = ConfigurationFactory.getInstance().getConfiguration(name, configLocation);
229 LOGGER.debug("Starting LoggerContext[name={}] from configuration at {}", ctx.getName(), configLocation);
230 ctx.start(config);
231 ContextAnchor.THREAD_CONTEXT.remove();
232 } else {
233 ctx.start();
234 }
235 }
236 return ctx;
237 }
238
239
240
241
242
243 public ContextSelector getSelector() {
244 return selector;
245 }
246
247
248
249
250
251
252
253 public ShutdownCallbackRegistry getShutdownCallbackRegistry() {
254 return shutdownCallbackRegistry;
255 }
256
257
258
259
260
261
262 @Override
263 public void removeContext(final org.apache.logging.log4j.spi.LoggerContext context) {
264 if (context instanceof LoggerContext) {
265 selector.removeContext((LoggerContext) context);
266 }
267 }
268
269 @Override
270 public Cancellable addShutdownCallback(final Runnable callback) {
271 return SHUTDOWN_HOOK_ENABLED ? shutdownCallbackRegistry.addShutdownCallback(callback) : null;
272 }
273
274 }