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