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.ShutdownCallbackRegistry;
33 import org.apache.logging.log4j.spi.LoggerContextFactory;
34 import org.apache.logging.log4j.status.StatusLogger;
35 import org.apache.logging.log4j.util.LoaderUtil;
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 try {
93 final ContextSelector selector = LoaderUtil.newCheckedInstanceOfProperty(Constants.LOG4J_CONTEXT_SELECTOR,
94 ContextSelector.class);
95 if (selector != null) {
96 return selector;
97 }
98 } catch (final Exception e) {
99 LOGGER.error("Unable to create custom ContextSelector. Falling back to default.", e);
100 }
101 return new ClassLoaderContextSelector();
102 }
103
104 private static ShutdownCallbackRegistry createShutdownCallbackRegistry() {
105 try {
106 final ShutdownCallbackRegistry registry = LoaderUtil.newCheckedInstanceOfProperty(
107 ShutdownCallbackRegistry.SHUTDOWN_CALLBACK_REGISTRY, ShutdownCallbackRegistry.class
108 );
109 if (registry != null) {
110 return registry;
111 }
112 } catch (final Exception e) {
113 LOGGER.error("Unable to create custom ShutdownCallbackRegistry. Falling back to default.", e);
114 }
115 return new DefaultShutdownCallbackRegistry();
116 }
117
118 private void initializeShutdownCallbackRegistry() {
119 if (SHUTDOWN_HOOK_ENABLED && this.shutdownCallbackRegistry instanceof LifeCycle) {
120 try {
121 ((LifeCycle) this.shutdownCallbackRegistry).start();
122 } catch (final Exception e) {
123 LOGGER.error("There was an error starting the ShutdownCallbackRegistry.", e);
124 }
125 }
126 }
127
128
129
130
131
132
133
134
135
136
137 @Override
138 public LoggerContext getContext(final String fqcn, final ClassLoader loader, final Object externalContext,
139 final boolean currentContext) {
140 final LoggerContext ctx = selector.getContext(fqcn, loader, currentContext);
141 if (externalContext != null && ctx.getExternalContext() == null) {
142 ctx.setExternalContext(externalContext);
143 }
144 if (ctx.getState() == LifeCycle.State.INITIALIZED) {
145 ctx.start();
146 }
147 return ctx;
148 }
149
150
151
152
153
154
155
156
157
158
159
160 public LoggerContext getContext(final String fqcn, final ClassLoader loader, final Object externalContext,
161 final boolean currentContext, final ConfigurationSource source) {
162 final LoggerContext ctx = selector.getContext(fqcn, loader, currentContext, null);
163 if (externalContext != null && ctx.getExternalContext() == null) {
164 ctx.setExternalContext(externalContext);
165 }
166 if (ctx.getState() == LifeCycle.State.INITIALIZED) {
167 if (source != null) {
168 ContextAnchor.THREAD_CONTEXT.set(ctx);
169 final Configuration config = ConfigurationFactory.getInstance().getConfiguration(source);
170 LOGGER.debug("Starting LoggerContext[name={}] from configuration {}", ctx.getName(), source);
171 ctx.start(config);
172 ContextAnchor.THREAD_CONTEXT.remove();
173 } else {
174 ctx.start();
175 }
176 }
177 return ctx;
178 }
179
180
181
182
183
184
185
186
187
188
189
190 public LoggerContext getContext(final String fqcn, final ClassLoader loader, final Object externalContext,
191 final boolean currentContext, final Configuration configuration) {
192 final LoggerContext ctx = selector.getContext(fqcn, loader, currentContext, null);
193 if (externalContext != null && ctx.getExternalContext() == null) {
194 ctx.setExternalContext(externalContext);
195 }
196 if (ctx.getState() == LifeCycle.State.INITIALIZED) {
197 ContextAnchor.THREAD_CONTEXT.set(ctx);
198 try {
199 ctx.start(configuration);
200 } finally {
201 ContextAnchor.THREAD_CONTEXT.remove();
202 }
203 }
204 return ctx;
205 }
206
207
208
209
210
211
212
213
214
215
216
217 @Override
218 public LoggerContext getContext(final String fqcn, final ClassLoader loader, final Object externalContext,
219 final boolean currentContext, final URI configLocation, final String name) {
220 final LoggerContext ctx = selector.getContext(fqcn, loader, currentContext, configLocation);
221 if (externalContext != null && ctx.getExternalContext() == null) {
222 ctx.setExternalContext(externalContext);
223 }
224 if (name != null) {
225 ctx.setName(name);
226 }
227 if (ctx.getState() == LifeCycle.State.INITIALIZED) {
228 if (configLocation != null || name != null) {
229 ContextAnchor.THREAD_CONTEXT.set(ctx);
230 final Configuration config = ConfigurationFactory.getInstance().getConfiguration(name, configLocation);
231 LOGGER.debug("Starting LoggerContext[name={}] from configuration at {}", ctx.getName(), configLocation);
232 ctx.start(config);
233 ContextAnchor.THREAD_CONTEXT.remove();
234 } else {
235 ctx.start();
236 }
237 }
238 return ctx;
239 }
240
241
242
243
244
245 public ContextSelector getSelector() {
246 return selector;
247 }
248
249
250
251
252
253
254
255 public ShutdownCallbackRegistry getShutdownCallbackRegistry() {
256 return shutdownCallbackRegistry;
257 }
258
259
260
261
262
263
264 @Override
265 public void removeContext(final org.apache.logging.log4j.spi.LoggerContext context) {
266 if (context instanceof LoggerContext) {
267 selector.removeContext((LoggerContext) context);
268 }
269 }
270
271 @Override
272 public Cancellable addShutdownCallback(final Runnable callback) {
273 return SHUTDOWN_HOOK_ENABLED ? shutdownCallbackRegistry.addShutdownCallback(callback) : null;
274 }
275
276 }