1
2
3
4
5
6
7 package org.mule.module.launcher.log4j;
8
9 import org.mule.module.launcher.MuleApplicationClassLoader;
10 import org.mule.module.reboot.MuleContainerBootstrapUtils;
11 import org.mule.module.reboot.MuleContainerSystemClassLoader;
12
13 import java.io.File;
14 import java.io.IOException;
15 import java.net.URL;
16 import java.util.concurrent.ConcurrentHashMap;
17 import java.util.concurrent.ConcurrentMap;
18
19 import org.apache.log4j.DailyRollingFileAppender;
20 import org.apache.log4j.Hierarchy;
21 import org.apache.log4j.Level;
22 import org.apache.log4j.Logger;
23 import org.apache.log4j.PatternLayout;
24 import org.apache.log4j.PropertyConfigurator;
25 import org.apache.log4j.helpers.LogLog;
26 import org.apache.log4j.spi.LoggerRepository;
27 import org.apache.log4j.spi.RepositorySelector;
28 import org.apache.log4j.spi.RootLogger;
29 import org.apache.log4j.xml.DOMConfigurator;
30
31 public class ApplicationAwareRepositorySelector implements RepositorySelector
32 {
33 protected static final String PATTERN_LAYOUT = "%-5p %d [%t] %c: %m%n";
34
35 protected static final Integer NO_CCL_CLASSLOADER = 0;
36 protected ConcurrentMap<Integer, LoggerRepository> repository = new ConcurrentHashMap<Integer, LoggerRepository>();
37
38
39 protected Logger logger = Logger.getLogger(getClass());
40
41 public LoggerRepository getLoggerRepository()
42 {
43 final ClassLoader ccl = Thread.currentThread().getContextClassLoader();
44
45 LoggerRepository repository = this.repository.get(ccl == null ? NO_CCL_CLASSLOADER : ccl.hashCode());
46 if (repository == null)
47 {
48 final RootLogger root = new RootLogger(Level.INFO);
49 repository = new Hierarchy(root);
50
51 try
52 {
53 ConfigWatchDog configWatchDog = null;
54 if (ccl instanceof MuleApplicationClassLoader)
55 {
56 MuleApplicationClassLoader muleCL = (MuleApplicationClassLoader) ccl;
57
58
59
60 URL appLogConfig = muleCL.findResource("log4j.xml");
61 if (appLogConfig == null)
62 {
63 appLogConfig = muleCL.findResource("log4j.properties");
64 }
65 final String appName = muleCL.getAppName();
66 if (appLogConfig == null)
67 {
68
69 String logName = String.format("mule-app-%s.log", appName);
70 File logDir = new File(MuleContainerBootstrapUtils.getMuleHome(), "logs");
71 File logFile = new File(logDir, logName);
72 DailyRollingFileAppender fileAppender = new DailyRollingFileAppender(new PatternLayout(PATTERN_LAYOUT), logFile.getAbsolutePath(), "'.'yyyy-MM-dd");
73 fileAppender.setAppend(true);
74 fileAppender.activateOptions();
75 root.addAppender(fileAppender);
76 }
77 else
78 {
79 configureFrom(appLogConfig, repository);
80 if (appLogConfig.toExternalForm().startsWith("file:"))
81 {
82
83 configWatchDog = new ConfigWatchDog(muleCL, appLogConfig.getFile(), repository);
84 configWatchDog.setName(String.format("[%s].log4j.config.monitor", appName));
85 }
86 else
87 {
88 if (logger.isInfoEnabled())
89 {
90 logger.info(String.format("Logging config %s is not an external file, will not be monitored for changes", appLogConfig));
91 }
92 }
93 }
94 }
95 else
96 {
97
98 File defaultSystemLog = new File(MuleContainerBootstrapUtils.getMuleHome(), "conf/log4j.xml");
99 if (!defaultSystemLog.exists() && !defaultSystemLog.canRead())
100 {
101 defaultSystemLog = new File(MuleContainerBootstrapUtils.getMuleHome(), "conf/log4j.properties");
102 }
103 configureFrom(defaultSystemLog.toURL(), repository);
104
105
106
107 if (ccl instanceof MuleContainerSystemClassLoader)
108 {
109 configWatchDog = new ConfigWatchDog(ccl, defaultSystemLog.getAbsolutePath(), repository);
110 configWatchDog.setName("Mule.system.log4j.config.monitor");
111 }
112 }
113
114 final LoggerRepository previous = this.repository.putIfAbsent(ccl == null ? NO_CCL_CLASSLOADER : ccl.hashCode(), repository);
115 if (previous != null)
116 {
117 repository = previous;
118 }
119
120 if (configWatchDog != null)
121 {
122 configWatchDog.start();
123 }
124 }
125 catch (IOException e)
126 {
127 throw new RuntimeException(e);
128 }
129 }
130
131 return repository;
132 }
133
134 protected void configureFrom(URL url, LoggerRepository repository)
135 {
136 if (url.toExternalForm().endsWith(".xml"))
137 {
138 new DOMConfigurator().doConfigure(url, repository);
139 }
140 else
141 {
142 new PropertyConfigurator().doConfigure(url, repository);
143 }
144 }
145
146
147
148 protected class ConfigWatchDog extends Thread
149 {
150
151 protected LoggerRepository repository;
152 protected File file;
153 protected long lastModif = 0;
154 protected boolean warnedAlready = false;
155 protected volatile boolean interrupted = false;
156
157
158
159
160
161 static final public long DEFAULT_DELAY = 60000;
162
163
164
165 protected String filename;
166
167
168
169
170
171 protected long delay = DEFAULT_DELAY;
172
173 public ConfigWatchDog(final ClassLoader classLoader, String filename, LoggerRepository repository)
174 {
175 if (classLoader instanceof MuleApplicationClassLoader)
176 {
177 ((MuleApplicationClassLoader) classLoader).addShutdownListener(new MuleApplicationClassLoader.ShutdownListener()
178 {
179 public void execute()
180 {
181 final ClassLoader ccl = Thread.currentThread().getContextClassLoader();
182 ApplicationAwareRepositorySelector.this.repository.remove(ccl == null ? NO_CCL_CLASSLOADER : ccl.hashCode());
183 interrupted = true;
184 }
185 });
186 }
187 this.filename = filename;
188 this.file = new File(filename);
189 this.lastModif = file.lastModified();
190 setDaemon(true);
191 this.repository = repository;
192 this.delay = 10000;
193 }
194
195 public void doOnChange()
196 {
197 if (logger.isInfoEnabled())
198 {
199 logger.info("Reconfiguring logging from: " + filename);
200 }
201 if (filename.endsWith(".xml"))
202 {
203 new DOMConfigurator().doConfigure(filename, repository);
204 }
205 else
206 {
207 new PropertyConfigurator().doConfigure(filename, repository);
208 }
209 }
210
211
212
213
214 public void setDelay(long delay)
215 {
216 this.delay = delay;
217 }
218
219 protected void checkAndConfigure()
220 {
221 boolean fileExists;
222 try
223 {
224 fileExists = file.exists();
225 }
226 catch (SecurityException e)
227 {
228 LogLog.warn("Was not allowed to read check file existence, file:[" + filename + "].");
229 interrupted = true;
230 return;
231 }
232
233 if (fileExists)
234 {
235 long l = file.lastModified();
236 if (l > lastModif)
237 {
238 lastModif = l;
239 doOnChange();
240 warnedAlready = false;
241 }
242 }
243 else
244 {
245 if (!warnedAlready)
246 {
247 LogLog.debug("[" + filename + "] does not exist.");
248 warnedAlready = true;
249 }
250 }
251 }
252
253 public void run()
254 {
255 while (!interrupted)
256 {
257 try
258 {
259 Thread.sleep(delay);
260 }
261 catch (InterruptedException e)
262 {
263 interrupted = true;
264 Thread.currentThread().interrupt();
265 break;
266 }
267 checkAndConfigure();
268 }
269 if (logger.isDebugEnabled())
270 {
271 logger.debug(getName() + " terminated successfully");
272 }
273 }
274
275 }
276 }
277