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.io.ByteArrayInputStream;
22 import java.io.File;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.io.InputStreamReader;
26 import java.io.PrintWriter;
27 import java.io.Reader;
28 import java.io.StringWriter;
29 import java.net.URI;
30 import java.net.URISyntaxException;
31 import java.util.Map;
32 import java.util.concurrent.Executor;
33 import java.util.concurrent.atomic.AtomicLong;
34
35 import javax.management.MBeanNotificationInfo;
36 import javax.management.Notification;
37 import javax.management.NotificationBroadcasterSupport;
38 import javax.management.ObjectName;
39
40 import org.apache.logging.log4j.core.LoggerContext;
41 import org.apache.logging.log4j.core.config.Configuration;
42 import org.apache.logging.log4j.core.config.ConfigurationFactory;
43 import org.apache.logging.log4j.core.config.ConfigurationFactory.ConfigurationSource;
44 import org.apache.logging.log4j.status.StatusLogger;
45
46
47
48
49 public class LoggerContextAdmin extends NotificationBroadcasterSupport
50 implements LoggerContextAdminMBean, PropertyChangeListener {
51 private static final int PAGE = 4 * 1024;
52 private static final int TEXT_BUFFER = 64 * 1024;
53 private static final int BUFFER_SIZE = 2048;
54 private static final StatusLogger LOGGER = StatusLogger.getLogger();
55
56 private final AtomicLong sequenceNo = new AtomicLong();
57 private final ObjectName objectName;
58 private final LoggerContext loggerContext;
59 private String customConfigText;
60
61
62
63
64
65
66
67 public LoggerContextAdmin(LoggerContext loggerContext, Executor executor) {
68 super(executor, createNotificationInfo());
69 this.loggerContext = Assert.isNotNull(loggerContext, "loggerContext");
70 try {
71 String ctxName = Server.escape(loggerContext.getName());
72 String name = String.format(PATTERN, ctxName);
73 objectName = new ObjectName(name);
74 } catch (Exception e) {
75 throw new IllegalStateException(e);
76 }
77 loggerContext.addPropertyChangeListener(this);
78 }
79
80 private static MBeanNotificationInfo createNotificationInfo() {
81 String[] notifTypes = new String[] { NOTIF_TYPE_RECONFIGURED };
82 String name = Notification.class.getName();
83 String description = "Configuration reconfigured";
84 return new MBeanNotificationInfo(notifTypes, name, description);
85 }
86
87 @Override
88 public String getStatus() {
89 return loggerContext.getStatus().toString();
90 }
91
92 @Override
93 public String getName() {
94 return loggerContext.getName();
95 }
96
97 private Configuration getConfig() {
98 return loggerContext.getConfiguration();
99 }
100
101 @Override
102 public String getConfigLocationURI() {
103 if (loggerContext.getConfigLocation() != null) {
104 return String.valueOf(loggerContext.getConfigLocation());
105 }
106 if (getConfigName() != null) {
107 return String.valueOf(new File(getConfigName()).toURI());
108 }
109 return "";
110 }
111
112 @Override
113 public void setConfigLocationURI(String configLocation)
114 throws URISyntaxException, IOException {
115 LOGGER.debug("---------");
116 LOGGER.debug("Remote request to reconfigure using location "
117 + configLocation);
118 URI uri = new URI(configLocation);
119
120
121
122 uri.toURL().openStream().close();
123
124 loggerContext.setConfigLocation(uri);
125 LOGGER.debug("Completed remote request to reconfigure.");
126 }
127
128 @Override
129 public void propertyChange(PropertyChangeEvent evt) {
130 if (!LoggerContext.PROPERTY_CONFIG.equals(evt.getPropertyName())) {
131 return;
132 }
133
134 if (loggerContext.getConfiguration().getName() != null) {
135 customConfigText = null;
136 }
137 Notification notif = new Notification(NOTIF_TYPE_RECONFIGURED,
138 getObjectName(), nextSeqNo(), now(), null);
139 sendNotification(notif);
140 }
141
142 @Override
143 public String getConfigText() throws IOException {
144 if (customConfigText != null) {
145 return customConfigText;
146 }
147 try {
148 return readContents(new URI(getConfigLocationURI()));
149 } catch (Exception ex) {
150 StringWriter sw = new StringWriter(BUFFER_SIZE);
151 ex.printStackTrace(new PrintWriter(sw));
152 return sw.toString();
153 }
154 }
155
156 @Override
157 public void setConfigText(String configText, String charsetName) {
158 String old = customConfigText;
159 customConfigText = Assert.isNotNull(configText, "configText");
160 LOGGER.debug("---------");
161 LOGGER.debug("Remote request to reconfigure from config text.");
162
163 try {
164 InputStream in = new ByteArrayInputStream(
165 configText.getBytes(charsetName));
166 ConfigurationSource source = new ConfigurationSource(in);
167 Configuration updated = ConfigurationFactory.getInstance()
168 .getConfiguration(source);
169 loggerContext.setConfiguration(updated);
170 LOGGER.debug("Completed remote request to reconfigure from config text.");
171 } catch (Exception ex) {
172 customConfigText = old;
173 String msg = "Could not reconfigure from config text";
174 LOGGER.error(msg, ex);
175 throw new IllegalArgumentException(msg, ex);
176 }
177 }
178
179 private String readContents(URI uri) throws IOException {
180 InputStream in = null;
181 try {
182 in = uri.toURL().openStream();
183 Reader reader = new InputStreamReader(in);
184 StringBuilder result = new StringBuilder(TEXT_BUFFER);
185 char[] buff = new char[PAGE];
186 int count = -1;
187 while ((count = reader.read(buff)) >= 0) {
188 result.append(buff, 0, count);
189 }
190 return result.toString();
191 } finally {
192 try {
193 in.close();
194 } catch (Exception ignored) {
195 }
196 }
197 }
198
199 @Override
200 public String getConfigName() {
201 return getConfig().getName();
202 }
203
204 @Override
205 public String getConfigClassName() {
206 return getConfig().getClass().getName();
207 }
208
209 @Override
210 public String getConfigFilter() {
211 return String.valueOf(getConfig().getFilter());
212 }
213
214 @Override
215 public String getConfigMonitorClassName() {
216 return getConfig().getConfigurationMonitor().getClass().getName();
217 }
218
219 @Override
220 public Map<String, String> getConfigProperties() {
221 return getConfig().getProperties();
222 }
223
224
225 public ObjectName getObjectName() {
226 return objectName;
227 }
228
229 private long nextSeqNo() {
230 return sequenceNo.getAndIncrement();
231 }
232
233 private long now() {
234 return System.currentTimeMillis();
235 }
236 }