1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.log4j.db;
19
20 import org.apache.log4j.Level;
21 import org.apache.log4j.Logger;
22 import org.apache.log4j.plugins.Pauseable;
23 import org.apache.log4j.plugins.Receiver;
24 import org.apache.log4j.scheduler.Job;
25 import org.apache.log4j.scheduler.Scheduler;
26 import org.apache.log4j.spi.LocationInfo;
27 import org.apache.log4j.spi.LoggerRepositoryEx;
28 import org.apache.log4j.spi.LoggingEvent;
29 import org.apache.log4j.spi.ThrowableInformation;
30 import org.apache.log4j.xml.DOMConfigurator;
31 import org.apache.log4j.xml.UnrecognizedElementHandler;
32 import org.w3c.dom.Element;
33
34 import java.sql.Connection;
35 import java.sql.ResultSet;
36 import java.sql.SQLException;
37 import java.sql.Statement;
38 import java.util.Hashtable;
39 import java.util.Properties;
40 import java.util.StringTokenizer;
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135 public class CustomSQLDBReceiver extends Receiver implements Pauseable, UnrecognizedElementHandler {
136
137 protected volatile Connection connection = null;
138
139 protected String sqlStatement = "";
140
141
142
143
144
145
146 static int DEFAULT_REFRESH_MILLIS = 1000;
147
148 int refreshMillis = DEFAULT_REFRESH_MILLIS;
149
150 protected String idField = null;
151
152 int lastID = -1;
153
154 private static final String WHERE_CLAUSE = " WHERE ";
155
156 private static final String AND_CLAUSE = " AND ";
157
158 private boolean whereExists = false;
159
160 private boolean paused = false;
161
162 private ConnectionSource connectionSource;
163
164 public static final String LOG4J_ID_KEY = "log4jid";
165
166 private Job customReceiverJob;
167
168 public void activateOptions() {
169
170 if (connectionSource == null) {
171 throw new IllegalStateException(
172 "CustomSQLDBReceiver cannot function without a connection source");
173 }
174 whereExists = (sqlStatement.toUpperCase().contains(WHERE_CLAUSE));
175
176 customReceiverJob = new CustomReceiverJob();
177
178 if (this.repository == null) {
179 throw new IllegalStateException(
180 "CustomSQLDBReceiver cannot function without a reference to its owning repository");
181 }
182
183
184 if (repository instanceof LoggerRepositoryEx) {
185 Scheduler scheduler = ((LoggerRepositoryEx) repository).getScheduler();
186
187 scheduler.schedule(
188 customReceiverJob, System.currentTimeMillis() + 500, refreshMillis);
189 }
190
191 }
192
193 void closeConnection() {
194 if (connection != null) {
195 try {
196
197 connection.close();
198 } catch (SQLException sqle) {
199
200 }
201 }
202 }
203
204 public void setRefreshMillis(int refreshMillis) {
205 this.refreshMillis = refreshMillis;
206 }
207
208 public int getRefreshMillis() {
209 return refreshMillis;
210 }
211
212
213
214
215 public ConnectionSource getConnectionSource() {
216 return connectionSource;
217 }
218
219
220
221
222 public void setConnectionSource(ConnectionSource connectionSource) {
223 this.connectionSource = connectionSource;
224 }
225
226 public void close() {
227 try {
228 if ((connection != null) && !connection.isClosed()) {
229 connection.close();
230 }
231 } catch (SQLException e) {
232 e.printStackTrace();
233 } finally {
234 connection = null;
235 }
236 }
237
238 public void finalize() throws Throwable {
239 super.finalize();
240 close();
241 }
242
243
244
245
246
247
248 public void shutdown() {
249 getLogger().info("removing receiverJob from the Scheduler.");
250
251 if (this.repository instanceof LoggerRepositoryEx) {
252 Scheduler scheduler = ((LoggerRepositoryEx) repository).getScheduler();
253 scheduler.delete(customReceiverJob);
254 }
255
256 lastID = -1;
257 }
258
259 public void setSql(String s) {
260 sqlStatement = s;
261 }
262
263 public String getSql() {
264 return sqlStatement;
265 }
266
267 public void setIDField(String id) {
268 idField = id;
269 }
270
271 public String getIDField() {
272 return idField;
273 }
274
275 public synchronized void setPaused(boolean p) {
276 paused = p;
277 }
278
279 public synchronized boolean isPaused() {
280 return paused;
281 }
282
283 class CustomReceiverJob implements Job {
284 public void execute() {
285 int oldLastID = lastID;
286 try {
287 connection = connectionSource.getConnection();
288 Statement statement = connection.createStatement();
289
290 Logger eventLogger;
291 long timeStamp;
292 String level;
293 String threadName;
294 Object message;
295 String ndc;
296 Hashtable<String, String> mdc;
297 String[] throwable;
298 String className;
299 String methodName;
300 String fileName;
301 String lineNumber;
302 Hashtable<String, String> properties;
303
304 String currentSQLStatement;
305 if (whereExists) {
306 currentSQLStatement = sqlStatement + AND_CLAUSE + idField
307 + " > " + lastID;
308 } else {
309 currentSQLStatement = sqlStatement + WHERE_CLAUSE + idField
310 + " > " + lastID;
311 }
312
313 ResultSet rs = statement.executeQuery(currentSQLStatement);
314
315 int i = 0;
316 while (rs.next()) {
317
318 if (++i == 1000) {
319 synchronized (this) {
320 try {
321
322 wait(300);
323 } catch (InterruptedException ie) {
324 }
325 i = 0;
326 }
327 }
328 eventLogger = Logger.getLogger(rs.getString("LOGGER"));
329 timeStamp = rs.getTimestamp("TIMESTAMP").getTime();
330
331 level = rs.getString("LEVEL");
332 threadName = rs.getString("THREAD");
333 message = rs.getString("MESSAGE");
334 ndc = rs.getString("NDC");
335
336 String mdcString = rs.getString("MDC");
337 mdc = new Hashtable<>();
338
339 if (mdcString != null) {
340
341
342
343 if ((mdcString.contains("{{"))
344 && (mdcString.contains("}}"))) {
345 mdcString = mdcString
346 .substring(mdcString.indexOf("{{") + 2,
347 mdcString.indexOf("}}"));
348 }
349
350 StringTokenizer tok = new StringTokenizer(mdcString,
351 ",");
352
353 while (tok.countTokens() > 1) {
354 mdc.put(tok.nextToken(), tok.nextToken());
355 }
356 }
357
358 throwable = new String[]{rs.getString("THROWABLE")};
359 className = rs.getString("CLASS");
360 methodName = rs.getString("METHOD");
361 fileName = rs.getString("FILE");
362 lineNumber = rs.getString("LINE");
363
364
365
366
367
368
369
370 String propertiesString = rs.getString("PROPERTIES");
371 properties = new Hashtable<>();
372
373 if (propertiesString != null) {
374
375
376 if ((propertiesString.contains("{{"))
377 && (propertiesString.contains("}}"))) {
378 propertiesString = propertiesString.substring(
379 propertiesString.indexOf("{{") + 2,
380 propertiesString.indexOf("}}"));
381 }
382
383 StringTokenizer tok2 = new StringTokenizer(
384 propertiesString, ",");
385 while (tok2.countTokens() > 1) {
386 String tokenName = tok2.nextToken();
387 String value = tok2.nextToken();
388 if (tokenName.equals(LOG4J_ID_KEY)) {
389 try {
390 int thisInt = Integer.parseInt(value);
391 value = String.valueOf(thisInt);
392 if (thisInt > lastID) {
393 lastID = thisInt;
394 }
395 } catch (Exception e) {
396 }
397 }
398 properties.put(tokenName, value);
399 }
400 }
401
402 Level levelImpl = Level.toLevel(level);
403
404
405 LocationInfo locationInfo = new LocationInfo(fileName,
406 className, methodName, lineNumber);
407
408 ThrowableInformation throwableInfo = new ThrowableInformation(
409 throwable);
410
411 properties.putAll(mdc);
412
413 LoggingEvent event = new LoggingEvent(eventLogger.getName(),
414 eventLogger, timeStamp, levelImpl, message,
415 threadName,
416 throwableInfo,
417 ndc,
418 locationInfo,
419 properties);
420
421 doPost(event);
422 }
423
424 if (lastID != oldLastID) {
425 getLogger().debug("lastID: " + lastID);
426 }
427
428 statement.close();
429 } catch (SQLException sqle) {
430 getLogger()
431 .error("*************Problem receiving events", sqle);
432 } finally {
433 closeConnection();
434 }
435
436
437 synchronized (this) {
438 while (isPaused()) {
439 try {
440 wait(1000);
441 } catch (InterruptedException ie) {
442 }
443 }
444 }
445 }
446 }
447
448
449
450
451 public boolean parseUnrecognizedElement(Element element, Properties props) throws Exception {
452 if ("connectionSource".equals(element.getNodeName())) {
453 Object instance =
454 DOMConfigurator.parseElement(element, props, ConnectionSource.class);
455 if (instance instanceof ConnectionSource) {
456 ConnectionSource source = (ConnectionSource) instance;
457 source.activateOptions();
458 setConnectionSource(source);
459 }
460 return true;
461 }
462 return false;
463 }
464
465 }