1 | /* |
2 | Copyright (C) 2002-2004 MySQL AB |
3 | |
4 | This program is free software; you can redistribute it and/or modify |
5 | it under the terms of version 2 of the GNU General Public License as |
6 | published by the Free Software Foundation. |
7 | |
8 | There are special exceptions to the terms and conditions of the GPL |
9 | as it is applied to this software. View the full text of the |
10 | exception in file EXCEPTIONS-CONNECTOR-J in the directory of this |
11 | software distribution. |
12 | |
13 | This program is distributed in the hope that it will be useful, |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | GNU General Public License for more details. |
17 | |
18 | You should have received a copy of the GNU General Public License |
19 | along with this program; if not, write to the Free Software |
20 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | |
22 | |
23 | |
24 | */ |
25 | package com.mysql.jdbc.profiler; |
26 | |
27 | import java.util.Date; |
28 | |
29 | import com.mysql.jdbc.Util; |
30 | |
31 | /** |
32 | * @author mmatthew |
33 | */ |
34 | public class ProfilerEvent { |
35 | |
36 | /** |
37 | * A Profiler warning event |
38 | */ |
39 | public static final byte TYPE_WARN = 0; |
40 | |
41 | /** |
42 | * Profiler creating object type event |
43 | */ |
44 | public static final byte TYPE_OBJECT_CREATION = 1; |
45 | |
46 | /** |
47 | * Profiler event for prepared statements being prepared |
48 | */ |
49 | public static final byte TYPE_PREPARE = 2; |
50 | |
51 | /** |
52 | * Profiler event for a query being executed |
53 | */ |
54 | public static final byte TYPE_QUERY = 3; |
55 | |
56 | /** |
57 | * Profiler event for prepared statements being executed |
58 | */ |
59 | public static final byte TYPE_EXECUTE = 4; |
60 | |
61 | /** |
62 | * Profiler event for result sets being retrieved |
63 | */ |
64 | public static final byte TYPE_FETCH = 5; |
65 | |
66 | /** |
67 | * Type of event |
68 | */ |
69 | protected byte eventType; |
70 | |
71 | /** |
72 | * Associated connection (-1 for none) |
73 | */ |
74 | protected long connectionId; |
75 | |
76 | /** |
77 | * Associated statement (-1 for none) |
78 | */ |
79 | protected int statementId; |
80 | |
81 | /** |
82 | * Associated result set (-1 for none) |
83 | */ |
84 | protected int resultSetId; |
85 | |
86 | /** |
87 | * When was the event created? |
88 | */ |
89 | protected long eventCreationTime; |
90 | |
91 | /** |
92 | * How long did the event last? |
93 | */ |
94 | protected int eventDurationMillis; |
95 | |
96 | /** |
97 | * The hostname the event occurred on (as an index into a dictionary, used |
98 | * by 'remote' profilers for efficiency)? |
99 | */ |
100 | protected int hostNameIndex; |
101 | |
102 | /** |
103 | * The hostname the event occurred on |
104 | */ |
105 | protected String hostName; |
106 | |
107 | /** |
108 | * The catalog the event occurred on (as an index into a dictionary, used by |
109 | * 'remote' profilers for efficiency)? |
110 | */ |
111 | protected int catalogIndex; |
112 | |
113 | /** |
114 | * The catalog the event occurred on |
115 | */ |
116 | protected String catalog; |
117 | |
118 | /** |
119 | * Where was the event created (as an index into a dictionary, used by |
120 | * 'remote' profilers for efficiency)? |
121 | */ |
122 | protected int eventCreationPointIndex; |
123 | |
124 | /** |
125 | * Where was the event created (as a Throwable)? |
126 | */ |
127 | protected Throwable eventCreationPoint; |
128 | |
129 | /** |
130 | * Where was the event created (as a string description of the |
131 | * eventCreationPoint)? |
132 | */ |
133 | protected String eventCreationPointDesc; |
134 | |
135 | /** |
136 | * Optional event message |
137 | */ |
138 | protected String message; |
139 | |
140 | /** |
141 | * Creates a new profiler event |
142 | * |
143 | * @param eventType |
144 | * the event type (from the constants TYPE_????) |
145 | * @param hostName |
146 | * the hostname where the event occurs |
147 | * @param catalog |
148 | * the catalog in use |
149 | * @param connectionId |
150 | * the connection id (-1 if N/A) |
151 | * @param statementId |
152 | * the statement id (-1 if N/A) |
153 | * @param resultSetId |
154 | * the result set id (-1 if N/A) |
155 | * @param eventCreationTime |
156 | * when was the event created? |
157 | * @param eventDurationMillis |
158 | * how long did the event last? |
159 | * @param eventCreationPointDesc |
160 | * event creation point as a string |
161 | * @param eventCreationPoint |
162 | * event creation point as a Throwable |
163 | * @param message |
164 | * optional message |
165 | */ |
166 | public ProfilerEvent(byte eventType, String hostName, String catalog, |
167 | long connectionId, int statementId, int resultSetId, |
168 | long eventCreationTime, int eventDurationMillis, |
169 | String eventCreationPointDesc, Throwable eventCreationPoint, |
170 | String message) { |
171 | this.eventType = eventType; |
172 | this.connectionId = connectionId; |
173 | this.statementId = statementId; |
174 | this.resultSetId = resultSetId; |
175 | this.eventCreationTime = eventCreationTime; |
176 | this.eventDurationMillis = eventDurationMillis; |
177 | this.eventCreationPoint = eventCreationPoint; |
178 | this.eventCreationPointDesc = eventCreationPointDesc; |
179 | this.message = message; |
180 | } |
181 | |
182 | /** |
183 | * Returns the description of when this event was created. |
184 | * |
185 | * @return a description of when this event was created. |
186 | */ |
187 | public String getEventCreationPointAsString() { |
188 | if (this.eventCreationPointDesc == null) { |
189 | this.eventCreationPointDesc = Util |
190 | .stackTraceToString(this.eventCreationPoint); |
191 | } |
192 | |
193 | return this.eventCreationPointDesc; |
194 | } |
195 | |
196 | /** |
197 | * Returns a representation of this event as a String. |
198 | * |
199 | * @return a String representation of this event. |
200 | */ |
201 | public String toString() { |
202 | StringBuffer buf = new StringBuffer(32); |
203 | |
204 | switch (this.eventType) { |
205 | case TYPE_EXECUTE: |
206 | buf.append("EXECUTE"); |
207 | break; |
208 | |
209 | case TYPE_FETCH: |
210 | buf.append("FETCH"); |
211 | break; |
212 | |
213 | case TYPE_OBJECT_CREATION: |
214 | buf.append("CONSTRUCT"); |
215 | break; |
216 | |
217 | case TYPE_PREPARE: |
218 | buf.append("PREPARE"); |
219 | break; |
220 | |
221 | case TYPE_QUERY: |
222 | buf.append("QUERY"); |
223 | break; |
224 | |
225 | case TYPE_WARN: |
226 | buf.append("WARN"); |
227 | break; |
228 | default: |
229 | buf.append("UNKNOWN"); |
230 | } |
231 | |
232 | buf.append(" created: "); |
233 | buf.append(new Date(this.eventCreationTime)); |
234 | buf.append(" duration: "); |
235 | buf.append(this.eventDurationMillis); |
236 | buf.append(" connection: "); |
237 | buf.append(this.connectionId); |
238 | buf.append(" statement: "); |
239 | buf.append(this.statementId); |
240 | buf.append(" resultset: "); |
241 | buf.append(this.resultSetId); |
242 | |
243 | if (this.message != null) { |
244 | buf.append(" message: "); |
245 | buf.append(this.message); |
246 | |
247 | } |
248 | |
249 | if (this.eventCreationPointDesc != null) { |
250 | buf.append("\n\nEvent Created at:\n"); |
251 | buf.append(this.eventCreationPointDesc); |
252 | } |
253 | |
254 | return buf.toString(); |
255 | } |
256 | |
257 | /** |
258 | * Unpacks a binary representation of this event. |
259 | * |
260 | * @param buf |
261 | * the binary representation of this event |
262 | * @return the unpacked Event |
263 | * @throws Exception |
264 | * if an error occurs while unpacking the event |
265 | */ |
266 | public static ProfilerEvent unpack(byte[] buf) throws Exception { |
267 | int pos = 0; |
268 | |
269 | byte eventType = buf[pos++]; |
270 | long connectionId = readInt(buf, pos); |
271 | pos += 8; |
272 | int statementId = readInt(buf, pos); |
273 | pos += 4; |
274 | int resultSetId = readInt(buf, pos); |
275 | pos += 4; |
276 | long eventCreationTime = readLong(buf, pos); |
277 | pos += 8; |
278 | int eventDurationMillis = readInt(buf, pos); |
279 | pos += 4; |
280 | int eventCreationPointIndex = readInt(buf, pos); |
281 | pos += 4; |
282 | byte[] eventCreationAsBytes = readBytes(buf, pos); |
283 | pos += 4; |
284 | |
285 | if (eventCreationAsBytes != null) { |
286 | pos += eventCreationAsBytes.length; |
287 | } |
288 | |
289 | byte[] message = readBytes(buf, pos); |
290 | pos += 4; |
291 | |
292 | if (message != null) { |
293 | pos += message.length; |
294 | } |
295 | |
296 | return new ProfilerEvent(eventType, "", "", connectionId, statementId, |
297 | resultSetId, eventCreationTime, eventDurationMillis, |
298 | new String(eventCreationAsBytes, "ISO8859_1"), null, |
299 | new String(message, "ISO8859_1")); |
300 | } |
301 | |
302 | /** |
303 | * Creates a binary representation of this event. |
304 | * |
305 | * @return a binary representation of this event |
306 | * @throws Exception |
307 | * if an error occurs while packing this event. |
308 | */ |
309 | public byte[] pack() throws Exception { |
310 | |
311 | int len = 1 + 4 + 4 + 4 + 8 + 4 + 4; |
312 | |
313 | byte[] eventCreationAsBytes = null; |
314 | |
315 | getEventCreationPointAsString(); |
316 | |
317 | if (this.eventCreationPointDesc != null) { |
318 | eventCreationAsBytes = this.eventCreationPointDesc |
319 | .getBytes("ISO8859_1"); |
320 | len += (4 + eventCreationAsBytes.length); |
321 | } else { |
322 | len += 4; |
323 | } |
324 | |
325 | byte[] messageAsBytes = null; |
326 | |
327 | if (messageAsBytes != null) { |
328 | messageAsBytes = this.message.getBytes("ISO8859_1"); |
329 | len += (4 + messageAsBytes.length); |
330 | } else { |
331 | len += 4; |
332 | } |
333 | |
334 | byte[] buf = new byte[len]; |
335 | |
336 | int pos = 0; |
337 | |
338 | buf[pos++] = this.eventType; |
339 | pos = writeLong(this.connectionId, buf, pos); |
340 | pos = writeInt(this.statementId, buf, pos); |
341 | pos = writeInt(this.resultSetId, buf, pos); |
342 | pos = writeLong(this.eventCreationTime, buf, pos); |
343 | pos = writeInt(this.eventDurationMillis, buf, pos); |
344 | pos = writeInt(this.eventCreationPointIndex, buf, pos); |
345 | |
346 | if (eventCreationAsBytes != null) { |
347 | pos = writeBytes(eventCreationAsBytes, buf, pos); |
348 | } else { |
349 | pos = writeInt(0, buf, pos); |
350 | } |
351 | |
352 | if (messageAsBytes != null) { |
353 | pos = writeBytes(messageAsBytes, buf, pos); |
354 | } else { |
355 | pos = writeInt(0, buf, pos); |
356 | } |
357 | |
358 | return buf; |
359 | } |
360 | |
361 | private static int writeInt(int i, byte[] buf, int pos) { |
362 | |
363 | buf[pos++] = (byte) (i & 0xff); |
364 | buf[pos++] = (byte) (i >>> 8); |
365 | buf[pos++] = (byte) (i >>> 16); |
366 | buf[pos++] = (byte) (i >>> 24); |
367 | |
368 | return pos; |
369 | } |
370 | |
371 | private static int writeLong(long l, byte[] buf, int pos) { |
372 | buf[pos++] = (byte) (l & 0xff); |
373 | buf[pos++] = (byte) (l >>> 8); |
374 | buf[pos++] = (byte) (l >>> 16); |
375 | buf[pos++] = (byte) (l >>> 24); |
376 | buf[pos++] = (byte) (l >>> 32); |
377 | buf[pos++] = (byte) (l >>> 40); |
378 | buf[pos++] = (byte) (l >>> 48); |
379 | buf[pos++] = (byte) (l >>> 56); |
380 | |
381 | return pos; |
382 | } |
383 | |
384 | private static int writeBytes(byte[] msg, byte[] buf, int pos) { |
385 | pos = writeInt(msg.length, buf, pos); |
386 | |
387 | System.arraycopy(msg, 0, buf, pos, msg.length); |
388 | |
389 | return pos + msg.length; |
390 | } |
391 | |
392 | private static int readInt(byte[] buf, int pos) { |
393 | return (buf[pos++] & 0xff) | ((buf[pos++] & 0xff) << 8) |
394 | | ((buf[pos++] & 0xff) << 16) | ((buf[pos++] & 0xff) << 24); |
395 | |
396 | } |
397 | |
398 | private static long readLong(byte[] buf, int pos) { |
399 | return (long) (buf[pos++] & 0xff) | ((long) (buf[pos++] & 0xff) << 8) |
400 | | ((long) (buf[pos++] & 0xff) << 16) |
401 | | ((long) (buf[pos++] & 0xff) << 24) |
402 | | ((long) (buf[pos++] & 0xff) << 32) |
403 | | ((long) (buf[pos++] & 0xff) << 40) |
404 | | ((long) (buf[pos++] & 0xff) << 48) |
405 | | ((long) (buf[pos++] & 0xff) << 56); |
406 | } |
407 | |
408 | private static byte[] readBytes(byte[] buf, int pos) { |
409 | int length = readInt(buf, pos); |
410 | |
411 | pos += 4; |
412 | |
413 | byte[] msg = new byte[length]; |
414 | System.arraycopy(buf, pos, msg, 0, length); |
415 | |
416 | return msg; |
417 | } |
418 | |
419 | /** |
420 | * Returns the catalog in use |
421 | * |
422 | * @return the catalog in use |
423 | */ |
424 | public String getCatalog() { |
425 | return this.catalog; |
426 | } |
427 | |
428 | /** |
429 | * Returns the id of the connection in use when this event was created. |
430 | * |
431 | * @return the connection in use |
432 | */ |
433 | public long getConnectionId() { |
434 | return this.connectionId; |
435 | } |
436 | |
437 | /** |
438 | * Returns the point (as a Throwable stacktrace) where this event was |
439 | * created. |
440 | * |
441 | * @return the point where this event was created |
442 | */ |
443 | public Throwable getEventCreationPoint() { |
444 | return this.eventCreationPoint; |
445 | } |
446 | |
447 | /** |
448 | * Returns the time (in System.currentTimeMillis() form) when this event was |
449 | * created |
450 | * |
451 | * @return the time this event was created |
452 | */ |
453 | public long getEventCreationTime() { |
454 | return this.eventCreationTime; |
455 | } |
456 | |
457 | /** |
458 | * Returns the duration of the event in milliseconds |
459 | * |
460 | * @return the duration of the event in milliseconds |
461 | */ |
462 | public int getEventDurationMillis() { |
463 | return this.eventDurationMillis; |
464 | } |
465 | |
466 | /** |
467 | * Returns the event type flag |
468 | * |
469 | * @return the event type flag |
470 | */ |
471 | public byte getEventType() { |
472 | return this.eventType; |
473 | } |
474 | |
475 | /** |
476 | * Returns the id of the result set in use when this event was created. |
477 | * |
478 | * @return the result set in use |
479 | */ |
480 | public int getResultSetId() { |
481 | return this.resultSetId; |
482 | } |
483 | |
484 | /** |
485 | * Returns the id of the statement in use when this event was created. |
486 | * |
487 | * @return the statement in use |
488 | */ |
489 | public int getStatementId() { |
490 | return this.statementId; |
491 | } |
492 | |
493 | /** |
494 | * Returns the optional message for this event |
495 | * |
496 | * @return the message stored in this event |
497 | */ |
498 | public String getMessage() { |
499 | return this.message; |
500 | } |
501 | } |