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.beans.PropertyChangeEvent;
20 import java.beans.PropertyChangeListener;
21 import java.lang.management.ManagementFactory;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Set;
25 import java.util.concurrent.Executor;
26 import java.util.concurrent.Executors;
27
28 import javax.management.InstanceAlreadyExistsException;
29 import javax.management.JMException;
30 import javax.management.MBeanRegistrationException;
31 import javax.management.MBeanServer;
32 import javax.management.MalformedObjectNameException;
33 import javax.management.NotCompliantMBeanException;
34 import javax.management.ObjectName;
35
36 import org.apache.logging.log4j.core.Appender;
37 import org.apache.logging.log4j.core.LoggerContext;
38 import org.apache.logging.log4j.core.config.LoggerConfig;
39 import org.apache.logging.log4j.core.selector.ContextSelector;
40 import org.apache.logging.log4j.status.StatusLogger;
41
42
43
44
45
46
47
48 public final class Server {
49
50 private static final String PROPERTY_DISABLE_JMX = "log4j2.disable.jmx";
51
52 private Server() {
53 }
54
55
56
57
58
59
60
61
62
63
64
65 public static String escape(String name) {
66 StringBuilder sb = new StringBuilder(name.length() * 2);
67 boolean needsQuotes = false;
68 for (int i = 0; i < name.length(); i++) {
69 char c = name.charAt(i);
70 switch (c) {
71 case ',':
72 case '=':
73 case ':':
74 case '\\':
75 case '*':
76 case '?':
77 sb.append('\\');
78 needsQuotes = true;
79 }
80 sb.append(c);
81 }
82 if (needsQuotes) {
83 sb.insert(0, '\"');
84 sb.append('\"');
85 }
86 return sb.toString();
87 }
88
89
90
91
92
93
94
95
96
97
98
99 public static void registerMBeans(ContextSelector selector)
100 throws JMException {
101
102
103 if (Boolean.getBoolean(PROPERTY_DISABLE_JMX)) {
104 StatusLogger.getLogger().debug(
105 "JMX disabled for log4j2. Not registering MBeans.");
106 return;
107 }
108 MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
109 registerMBeans(selector, mbs);
110 }
111
112
113
114
115
116
117
118
119
120
121
122
123
124 public static void registerMBeans(ContextSelector selector,
125 final MBeanServer mbs) throws JMException {
126
127 if (Boolean.getBoolean(PROPERTY_DISABLE_JMX)) {
128 StatusLogger.getLogger().debug(
129 "JMX disabled for log4j2. Not registering MBeans.");
130 return;
131 }
132 final Executor executor = Executors.newFixedThreadPool(1);
133 registerStatusLogger(mbs, executor);
134 registerContextSelector(selector, mbs, executor);
135
136 List<LoggerContext> contexts = selector.getLoggerContexts();
137 registerContexts(contexts, mbs, executor);
138
139 for (final LoggerContext context : contexts) {
140 context.addPropertyChangeListener(new PropertyChangeListener() {
141
142 @Override
143 public void propertyChange(PropertyChangeEvent evt) {
144 if (!LoggerContext.PROPERTY_CONFIG.equals(evt
145 .getPropertyName())) {
146 return;
147 }
148
149
150 unregisterLoggerConfigs(context, mbs);
151 unregisterAppenders(context, mbs);
152
153
154
155 try {
156 registerLoggerConfigs(context, mbs, executor);
157 registerAppenders(context, mbs, executor);
158 } catch (Exception ex) {
159 StatusLogger.getLogger().error(
160 "Could not register mbeans", ex);
161 }
162 }
163 });
164 }
165 }
166
167 private static void registerStatusLogger(MBeanServer mbs, Executor executor)
168 throws MalformedObjectNameException,
169 InstanceAlreadyExistsException, MBeanRegistrationException,
170 NotCompliantMBeanException {
171
172 StatusLoggerAdmin mbean = new StatusLoggerAdmin(executor);
173 mbs.registerMBean(mbean, mbean.getObjectName());
174 }
175
176 private static void registerContextSelector(ContextSelector selector,
177 MBeanServer mbs, Executor executor)
178 throws MalformedObjectNameException,
179 InstanceAlreadyExistsException, MBeanRegistrationException,
180 NotCompliantMBeanException {
181
182 ContextSelectorAdmin mbean = new ContextSelectorAdmin(selector);
183 mbs.registerMBean(mbean, mbean.getObjectName());
184 }
185
186 private static void registerContexts(List<LoggerContext> contexts,
187 MBeanServer mbs, Executor executor)
188 throws MalformedObjectNameException,
189 InstanceAlreadyExistsException, MBeanRegistrationException,
190 NotCompliantMBeanException {
191
192 for (LoggerContext ctx : contexts) {
193 LoggerContextAdmin mbean = new LoggerContextAdmin(ctx, executor);
194 mbs.registerMBean(mbean, mbean.getObjectName());
195 }
196 }
197
198 private static void unregisterLoggerConfigs(LoggerContext context,
199 MBeanServer mbs) {
200 String pattern = LoggerConfigAdminMBean.PATTERN;
201 String search = String.format(pattern, context.getName(), "*");
202 unregisterAllMatching(search, mbs);
203 }
204
205 private static void unregisterAppenders(LoggerContext context,
206 MBeanServer mbs) {
207 String pattern = AppenderAdminMBean.PATTERN;
208 String search = String.format(pattern, context.getName(), "*");
209 unregisterAllMatching(search, mbs);
210 }
211
212 private static void unregisterAllMatching(String search, MBeanServer mbs) {
213 try {
214 ObjectName pattern = new ObjectName(search);
215 Set<ObjectName> found = mbs.queryNames(pattern, null);
216 for (ObjectName objectName : found) {
217 mbs.unregisterMBean(objectName);
218 }
219 } catch (Exception ex) {
220 StatusLogger.getLogger()
221 .error("Could not unregister " + search, ex);
222 }
223 }
224
225 private static void registerLoggerConfigs(LoggerContext ctx,
226 MBeanServer mbs, Executor executor)
227 throws MalformedObjectNameException,
228 InstanceAlreadyExistsException, MBeanRegistrationException,
229 NotCompliantMBeanException {
230
231 Map<String, LoggerConfig> map = ctx.getConfiguration().getLoggers();
232 for (String name : map.keySet()) {
233 LoggerConfig cfg = map.get(name);
234 LoggerConfigAdmin mbean = new LoggerConfigAdmin(ctx.getName(), cfg);
235 mbs.registerMBean(mbean, mbean.getObjectName());
236 }
237 }
238
239 private static void registerAppenders(LoggerContext ctx, MBeanServer mbs,
240 Executor executor) throws MalformedObjectNameException,
241 InstanceAlreadyExistsException, MBeanRegistrationException,
242 NotCompliantMBeanException {
243
244 Map<String, Appender<?>> map = ctx.getConfiguration().getAppenders();
245 for (String name : map.keySet()) {
246 Appender<?> appender = map.get(name);
247 AppenderAdmin mbean = new AppenderAdmin(ctx.getName(), appender);
248 mbs.registerMBean(mbean, mbean.getObjectName());
249 }
250 }
251 }