1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.jmx;
18
19 import java.lang.management.ManagementFactory;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.Set;
23 import java.util.concurrent.Executor;
24 import java.util.concurrent.Executors;
25
26 import javax.management.InstanceAlreadyExistsException;
27 import javax.management.MBeanRegistrationException;
28 import javax.management.MBeanServer;
29 import javax.management.NotCompliantMBeanException;
30 import javax.management.ObjectName;
31
32 import org.apache.logging.log4j.LogManager;
33 import org.apache.logging.log4j.core.Appender;
34 import org.apache.logging.log4j.core.LoggerContext;
35 import org.apache.logging.log4j.core.appender.AsyncAppender;
36 import org.apache.logging.log4j.core.async.AsyncLogger;
37 import org.apache.logging.log4j.core.async.AsyncLoggerConfig;
38 import org.apache.logging.log4j.core.async.AsyncLoggerContext;
39 import org.apache.logging.log4j.core.config.LoggerConfig;
40 import org.apache.logging.log4j.core.impl.Log4jContextFactory;
41 import org.apache.logging.log4j.core.selector.ContextSelector;
42 import org.apache.logging.log4j.spi.LoggerContextFactory;
43 import org.apache.logging.log4j.status.StatusLogger;
44
45
46
47
48
49
50
51 public final class Server {
52
53
54
55
56
57 public static final String DOMAIN = "org.apache.logging.log4j2";
58 private static final String PROPERTY_DISABLE_JMX = "log4j2.disable.jmx";
59 private static final StatusLogger LOGGER = StatusLogger.getLogger();
60 static final Executor executor = Executors.newFixedThreadPool(1);
61
62 private Server() {
63 }
64
65
66
67
68
69
70
71
72
73
74 public static String escape(final String name) {
75 final StringBuilder sb = new StringBuilder(name.length() * 2);
76 boolean needsQuotes = false;
77 for (int i = 0; i < name.length(); i++) {
78 final char c = name.charAt(i);
79 switch (c) {
80 case '\\':
81 case '*':
82 case '?':
83 case '\"':
84
85 sb.append('\\');
86 needsQuotes = true;
87 break;
88 case ',':
89 case '=':
90 case ':':
91
92 needsQuotes = true;
93 break;
94 case '\r':
95
96 continue;
97 case '\n':
98
99 sb.append("\\n");
100 needsQuotes = true;
101 continue;
102 }
103 sb.append(c);
104 }
105 if (needsQuotes) {
106 sb.insert(0, '\"');
107 sb.append('\"');
108 }
109 return sb.toString();
110 }
111
112 public static void reregisterMBeansAfterReconfigure() {
113
114 if (Boolean.getBoolean(PROPERTY_DISABLE_JMX)) {
115 LOGGER.debug("JMX disabled for log4j2. Not registering MBeans.");
116 return;
117 }
118 final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
119 reregisterMBeansAfterReconfigure(mbs);
120 }
121
122 public static void reregisterMBeansAfterReconfigure(MBeanServer mbs) {
123 if (Boolean.getBoolean(PROPERTY_DISABLE_JMX)) {
124 LOGGER.debug("JMX disabled for log4j2. Not registering MBeans.");
125 return;
126 }
127
128
129
130 try {
131 final ContextSelector selector = getContextSelector();
132 if (selector == null) {
133 LOGGER.debug("Could not register MBeans: no ContextSelector found.");
134 return;
135 }
136 final List<LoggerContext> contexts = selector.getLoggerContexts();
137 for (LoggerContext ctx : contexts) {
138
139
140 unregisterLoggerContext(ctx.getName(), mbs);
141
142 final LoggerContextAdmin mbean = new LoggerContextAdmin(ctx, executor);
143 register(mbs, mbean, mbean.getObjectName());
144
145 if (ctx instanceof AsyncLoggerContext) {
146 RingBufferAdmin rbmbean = AsyncLogger.createRingBufferAdmin(ctx.getName());
147 register(mbs, rbmbean, rbmbean.getObjectName());
148 }
149
150
151
152
153
154
155 registerStatusLogger(ctx.getName(), mbs, executor);
156 registerContextSelector(ctx.getName(), selector, mbs, executor);
157
158 registerLoggerConfigs(ctx, mbs, executor);
159 registerAppenders(ctx, mbs, executor);
160 }
161 } catch (final Exception ex) {
162 LOGGER.error("Could not register mbeans", ex);
163 }
164 }
165
166
167
168
169 public static void unregisterMBeans() {
170 final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
171 unregisterMBeans(mbs);
172 }
173
174
175
176
177
178
179 public static void unregisterMBeans(MBeanServer mbs) {
180 unregisterStatusLogger("*", mbs);
181 unregisterContextSelector("*", mbs);
182 unregisterContexts(mbs);
183 unregisterLoggerConfigs("*", mbs);
184 unregisterAsyncLoggerRingBufferAdmins("*", mbs);
185 unregisterAsyncLoggerConfigRingBufferAdmins("*", mbs);
186 unregisterAppenders("*", mbs);
187 unregisterAsyncAppenders("*", mbs);
188 }
189
190
191
192
193
194
195
196
197 private static ContextSelector getContextSelector() {
198 final LoggerContextFactory factory = LogManager.getFactory();
199 if (factory instanceof Log4jContextFactory) {
200 ContextSelector selector = ((Log4jContextFactory) factory).getSelector();
201 return selector;
202 }
203 return null;
204 }
205
206
207
208
209
210
211
212
213 public static void unregisterLoggerContext(String loggerContextName) {
214 final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
215 unregisterLoggerContext(loggerContextName, mbs);
216 }
217
218
219
220
221
222
223
224
225
226 public static void unregisterLoggerContext(String contextName, MBeanServer mbs) {
227 final String pattern = LoggerContextAdminMBean.PATTERN;
228 final String search = String.format(pattern, escape(contextName), "*");
229 unregisterAllMatching(search, mbs);
230
231
232 unregisterStatusLogger(contextName, mbs);
233 unregisterContextSelector(contextName, mbs);
234 unregisterLoggerConfigs(contextName, mbs);
235 unregisterAppenders(contextName, mbs);
236 unregisterAsyncAppenders(contextName, mbs);
237 unregisterAsyncLoggerRingBufferAdmins(contextName, mbs);
238 unregisterAsyncLoggerConfigRingBufferAdmins(contextName, mbs);
239 }
240
241 private static void registerStatusLogger(final String contextName, final MBeanServer mbs, final Executor executor)
242 throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException {
243
244 final StatusLoggerAdmin mbean = new StatusLoggerAdmin(contextName, executor);
245 register(mbs, mbean, mbean.getObjectName());
246 }
247
248 private static void registerContextSelector(final String contextName, final ContextSelector selector,
249 final MBeanServer mbs, final Executor executor) throws InstanceAlreadyExistsException,
250 MBeanRegistrationException, NotCompliantMBeanException {
251
252 final ContextSelectorAdmin mbean = new ContextSelectorAdmin(contextName, selector);
253 register(mbs, mbean, mbean.getObjectName());
254 }
255
256 private static void unregisterStatusLogger(final String contextName, final MBeanServer mbs) {
257 final String pattern = StatusLoggerAdminMBean.PATTERN;
258 final String search = String.format(pattern, escape(contextName), "*");
259 unregisterAllMatching(search, mbs);
260 }
261
262 private static void unregisterContextSelector(final String contextName, final MBeanServer mbs) {
263 final String pattern = ContextSelectorAdminMBean.PATTERN;
264 final String search = String.format(pattern, escape(contextName), "*");
265 unregisterAllMatching(search, mbs);
266 }
267
268 private static void unregisterLoggerConfigs(final String contextName, final MBeanServer mbs) {
269 final String pattern = LoggerConfigAdminMBean.PATTERN;
270 final String search = String.format(pattern, escape(contextName), "*");
271 unregisterAllMatching(search, mbs);
272 }
273
274 private static void unregisterContexts(final MBeanServer mbs) {
275 final String pattern = LoggerContextAdminMBean.PATTERN;
276 final String search = String.format(pattern, "*");
277 unregisterAllMatching(search, mbs);
278 }
279
280 private static void unregisterAppenders(final String contextName, final MBeanServer mbs) {
281 final String pattern = AppenderAdminMBean.PATTERN;
282 final String search = String.format(pattern, escape(contextName), "*");
283 unregisterAllMatching(search, mbs);
284 }
285
286 private static void unregisterAsyncAppenders(final String contextName, final MBeanServer mbs) {
287 final String pattern = AsyncAppenderAdminMBean.PATTERN;
288 final String search = String.format(pattern, escape(contextName), "*");
289 unregisterAllMatching(search, mbs);
290 }
291
292 private static void unregisterAsyncLoggerRingBufferAdmins(final String contextName, final MBeanServer mbs) {
293 final String pattern1 = RingBufferAdminMBean.PATTERN_ASYNC_LOGGER;
294 final String search1 = String.format(pattern1, escape(contextName));
295 unregisterAllMatching(search1, mbs);
296 }
297
298 private static void unregisterAsyncLoggerConfigRingBufferAdmins(final String contextName, final MBeanServer mbs) {
299 final String pattern2 = RingBufferAdminMBean.PATTERN_ASYNC_LOGGER_CONFIG;
300 final String search2 = String.format(pattern2, escape(contextName), "*");
301 unregisterAllMatching(search2, mbs);
302 }
303
304 private static void unregisterAllMatching(final String search, final MBeanServer mbs) {
305 try {
306 final ObjectName pattern = new ObjectName(search);
307 final Set<ObjectName> found = mbs.queryNames(pattern, null);
308 for (final ObjectName objectName : found) {
309 LOGGER.debug("Unregistering MBean {}", objectName);
310 mbs.unregisterMBean(objectName);
311 }
312 } catch (final Exception ex) {
313 LOGGER.error("Could not unregister MBeans for " + search, ex);
314 }
315 }
316
317 private static void registerLoggerConfigs(final LoggerContext ctx, final MBeanServer mbs, final Executor executor)
318 throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException {
319
320 final Map<String, LoggerConfig> map = ctx.getConfiguration().getLoggers();
321 for (final String name : map.keySet()) {
322 final LoggerConfig cfg = map.get(name);
323 final LoggerConfigAdmin mbean = new LoggerConfigAdmin(ctx, cfg);
324 register(mbs, mbean, mbean.getObjectName());
325
326 if (cfg instanceof AsyncLoggerConfig) {
327 AsyncLoggerConfig async = (AsyncLoggerConfig) cfg;
328 RingBufferAdmin rbmbean = async.createRingBufferAdmin(ctx.getName());
329 register(mbs, rbmbean, rbmbean.getObjectName());
330 }
331 }
332 }
333
334 private static void registerAppenders(final LoggerContext ctx, final MBeanServer mbs, final Executor executor)
335 throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException {
336
337 final Map<String, Appender> map = ctx.getConfiguration().getAppenders();
338 for (final String name : map.keySet()) {
339 final Appender appender = map.get(name);
340
341 if (appender instanceof AsyncAppender) {
342 AsyncAppender async = ((AsyncAppender) appender);
343 final AsyncAppenderAdmin mbean = new AsyncAppenderAdmin(ctx.getName(), async);
344 register(mbs, mbean, mbean.getObjectName());
345 } else {
346 final AppenderAdmin mbean = new AppenderAdmin(ctx.getName(), appender);
347 register(mbs, mbean, mbean.getObjectName());
348 }
349 }
350 }
351
352 private static void register(MBeanServer mbs, Object mbean, ObjectName objectName)
353 throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException {
354 LOGGER.debug("Registering MBean {}", objectName);
355 mbs.registerMBean(mbean, objectName);
356 }
357 }