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