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.AppenderSkeleton;
21 import org.apache.log4j.db.dialect.SQLDialect;
22 import org.apache.log4j.db.dialect.Util;
23 import org.apache.log4j.helpers.LogLog;
24 import org.apache.log4j.spi.LocationInfo;
25 import org.apache.log4j.spi.LoggingEvent;
26 import org.apache.log4j.xml.DOMConfigurator;
27 import org.apache.log4j.xml.UnrecognizedElementHandler;
28 import org.w3c.dom.Element;
29
30 import java.sql.Connection;
31 import java.sql.PreparedStatement;
32 import java.sql.ResultSet;
33 import java.sql.Statement;
34 import java.util.Properties;
35 import java.util.Set;
36
37
38
39
40
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 public class DBAppender extends AppenderSkeleton implements UnrecognizedElementHandler {
117 static final String insertPropertiesSQL =
118 "INSERT INTO logging_event_property (event_id, mapped_key, mapped_value) VALUES (?, ?, ?)";
119 static final String insertExceptionSQL =
120 "INSERT INTO logging_event_exception (event_id, i, trace_line) VALUES (?, ?, ?)";
121 static final String insertSQL;
122
123
124 static {
125 String sql = "INSERT INTO logging_event (" +
126 "sequence_number, " +
127 "timestamp, " +
128 "rendered_message, " +
129 "logger_name, " +
130 "level_string, " +
131 "ndc, " +
132 "thread_name, " +
133 "reference_flag, " +
134 "caller_filename, " +
135 "caller_class, " +
136 "caller_method, " +
137 "caller_line) " +
138 " VALUES (?, ?, ? ,?, ?, ?, ?, ?, ?, ?, ?, ?)";
139 insertSQL = sql;
140 }
141
142 ConnectionSource connectionSource;
143 boolean cnxSupportsGetGeneratedKeys = false;
144 boolean cnxSupportsBatchUpdates = false;
145 SQLDialect sqlDialect;
146 boolean locationInfo = false;
147
148
149 public DBAppender() {
150 super(false);
151 }
152
153 public void activateOptions() {
154 LogLog.debug("DBAppender.activateOptions called");
155
156 if (connectionSource == null) {
157 throw new IllegalStateException(
158 "DBAppender cannot function without a connection source");
159 }
160
161 sqlDialect = Util.getDialectFromCode(connectionSource.getSQLDialectCode());
162 cnxSupportsGetGeneratedKeys = connectionSource.supportsGetGeneratedKeys();
163 cnxSupportsBatchUpdates = connectionSource.supportsBatchUpdates();
164 if (!cnxSupportsGetGeneratedKeys && (sqlDialect == null)) {
165 throw new IllegalStateException(
166 "DBAppender cannot function if the JDBC driver does not support getGeneratedKeys method *and* without a specific SQL dialect");
167 }
168
169
170 super.activateOptions();
171 }
172
173
174
175
176 public ConnectionSource getConnectionSource() {
177 return connectionSource;
178 }
179
180
181
182
183 public void setConnectionSource(ConnectionSource connectionSource) {
184 LogLog.debug("setConnectionSource called for DBAppender");
185 this.connectionSource = connectionSource;
186 }
187
188 protected void append(LoggingEvent event) {
189 Connection connection = null;
190 try {
191 connection = connectionSource.getConnection();
192 connection.setAutoCommit(false);
193
194 PreparedStatement insertStatement;
195 if (cnxSupportsGetGeneratedKeys) {
196 insertStatement = connection.prepareStatement(insertSQL, Statement.RETURN_GENERATED_KEYS);
197 } else {
198 insertStatement = connection.prepareStatement(insertSQL);
199 }
200
201
202 insertStatement.setLong(1, 0);
203
204 insertStatement.setLong(2, event.getTimeStamp());
205 insertStatement.setString(3, event.getRenderedMessage());
206 insertStatement.setString(4, event.getLoggerName());
207 insertStatement.setString(5, event.getLevel().toString());
208 insertStatement.setString(6, event.getNDC());
209 insertStatement.setString(7, event.getThreadName());
210 insertStatement.setShort(8, DBHelper.computeReferenceMask(event));
211
212 LocationInfo li;
213
214 if (event.locationInformationExists() || locationInfo) {
215 li = event.getLocationInformation();
216 } else {
217 li = LocationInfo.NA_LOCATION_INFO;
218 }
219
220 insertStatement.setString(9, li.getFileName());
221 insertStatement.setString(10, li.getClassName());
222 insertStatement.setString(11, li.getMethodName());
223 insertStatement.setString(12, li.getLineNumber());
224
225 int updateCount = insertStatement.executeUpdate();
226 if (updateCount != 1) {
227 LogLog.warn("Failed to insert loggingEvent");
228 }
229
230 ResultSet rs = null;
231 Statement idStatement = null;
232 boolean gotGeneratedKeys = false;
233 if (cnxSupportsGetGeneratedKeys) {
234 rs = insertStatement.getGeneratedKeys();
235 gotGeneratedKeys = true;
236 }
237
238 if (!gotGeneratedKeys) {
239 insertStatement.close();
240 insertStatement = null;
241
242 idStatement = connection.createStatement();
243 idStatement.setMaxRows(1);
244 rs = idStatement.executeQuery(sqlDialect.getSelectInsertId());
245 }
246
247
248
249 rs.next();
250 int eventId = rs.getInt(1);
251
252 rs.close();
253
254
255 if (insertStatement != null) {
256 insertStatement.close();
257 }
258
259 if (idStatement != null) {
260 idStatement.close();
261 }
262
263 Set propertiesKeys = event.getPropertyKeySet();
264
265 if (propertiesKeys.size() > 0) {
266 PreparedStatement insertPropertiesStatement =
267 connection.prepareStatement(insertPropertiesSQL);
268
269 for (Object propertiesKey : propertiesKeys) {
270 String key = (String) propertiesKey;
271 String value = event.getProperty(key);
272
273
274 insertPropertiesStatement.setInt(1, eventId);
275 insertPropertiesStatement.setString(2, key);
276 insertPropertiesStatement.setString(3, value);
277
278 if (cnxSupportsBatchUpdates) {
279 insertPropertiesStatement.addBatch();
280 } else {
281 insertPropertiesStatement.execute();
282 }
283 }
284
285 if (cnxSupportsBatchUpdates) {
286 insertPropertiesStatement.executeBatch();
287 }
288
289 insertPropertiesStatement.close();
290 }
291
292 String[] strRep = event.getThrowableStrRep();
293
294 if (strRep != null) {
295 LogLog.debug("Logging an exception");
296
297 PreparedStatement insertExceptionStatement =
298 connection.prepareStatement(insertExceptionSQL);
299
300 for (short i = 0; i < strRep.length; i++) {
301 insertExceptionStatement.setInt(1, eventId);
302 insertExceptionStatement.setShort(2, i);
303 insertExceptionStatement.setString(3, strRep[i]);
304 if (cnxSupportsBatchUpdates) {
305 insertExceptionStatement.addBatch();
306 } else {
307 insertExceptionStatement.execute();
308 }
309 }
310 if (cnxSupportsBatchUpdates) {
311 insertExceptionStatement.executeBatch();
312 }
313 insertExceptionStatement.close();
314 }
315
316 connection.commit();
317 } catch (Throwable sqle) {
318 LogLog.error("problem appending event", sqle);
319 } finally {
320 DBHelper.closeConnection(connection);
321 }
322 }
323
324 public void close() {
325 closed = true;
326 }
327
328
329
330
331
332 public boolean getLocationInfo() {
333 return locationInfo;
334 }
335
336
337
338
339
340
341 public void setLocationInfo(boolean locationInfo) {
342 this.locationInfo = locationInfo;
343 }
344
345
346
347
348
349
350 public boolean requiresLayout() {
351 return false;
352 }
353
354
355
356
357 public boolean parseUnrecognizedElement(Element element, Properties props) throws Exception {
358 if ("connectionSource".equals(element.getNodeName())) {
359 Object instance =
360 DOMConfigurator.parseElement(element, props, ConnectionSource.class);
361 if (instance instanceof ConnectionSource) {
362 ConnectionSource source = (ConnectionSource) instance;
363 source.activateOptions();
364 setConnectionSource(source);
365 }
366 return true;
367 }
368 return false;
369 }
370 }