001: /*
002: Copyright (C) 2002-2007 MySQL AB
003:
004: This program is free software; you can redistribute it and/or modify
005: it under the terms of version 2 of the GNU General Public License as
006: published by the Free Software Foundation.
007:
008: There are special exceptions to the terms and conditions of the GPL
009: as it is applied to this software. View the full text of the
010: exception in file EXCEPTIONS-CONNECTOR-J in the directory of this
011: software distribution.
012:
013: This program is distributed in the hope that it will be useful,
014: but WITHOUT ANY WARRANTY; without even the implied warranty of
015: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016: GNU General Public License for more details.
017:
018: You should have received a copy of the GNU General Public License
019: along with this program; if not, write to the Free Software
020: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
021:
022: */
023:
024: package com.mysql.jdbc.profiler;
025:
026: import java.util.Date;
027:
028: import com.mysql.jdbc.Util;
029:
030: /**
031: * @author mmatthew
032: */
033: public class ProfilerEvent {
034:
035: /**
036: * A Profiler warning event
037: */
038: public static final byte TYPE_WARN = 0;
039:
040: /**
041: * Profiler creating object type event
042: */
043: public static final byte TYPE_OBJECT_CREATION = 1;
044:
045: /**
046: * Profiler event for prepared statements being prepared
047: */
048: public static final byte TYPE_PREPARE = 2;
049:
050: /**
051: * Profiler event for a query being executed
052: */
053: public static final byte TYPE_QUERY = 3;
054:
055: /**
056: * Profiler event for prepared statements being executed
057: */
058: public static final byte TYPE_EXECUTE = 4;
059:
060: /**
061: * Profiler event for result sets being retrieved
062: */
063: public static final byte TYPE_FETCH = 5;
064:
065: /**
066: * Profiler event for slow query
067: */
068: public static final byte TYPE_SLOW_QUERY = 6;
069:
070: /**
071: * Type of event
072: */
073: protected byte eventType;
074:
075: /**
076: * Associated connection (-1 for none)
077: */
078: protected long connectionId;
079:
080: /**
081: * Associated statement (-1 for none)
082: */
083: protected int statementId;
084:
085: /**
086: * Associated result set (-1 for none)
087: */
088: protected int resultSetId;
089:
090: /**
091: * When was the event created?
092: */
093: protected long eventCreationTime;
094:
095: /**
096: * How long did the event last?
097: */
098: protected long eventDuration;
099:
100: /**
101: * What units was the duration measured in?
102: */
103: protected String durationUnits;
104:
105: /**
106: * The hostname the event occurred on (as an index into a dictionary, used
107: * by 'remote' profilers for efficiency)?
108: */
109: protected int hostNameIndex;
110:
111: /**
112: * The hostname the event occurred on
113: */
114: protected String hostName;
115:
116: /**
117: * The catalog the event occurred on (as an index into a dictionary, used by
118: * 'remote' profilers for efficiency)?
119: */
120: protected int catalogIndex;
121:
122: /**
123: * The catalog the event occurred on
124: */
125: protected String catalog;
126:
127: /**
128: * Where was the event created (as an index into a dictionary, used by
129: * 'remote' profilers for efficiency)?
130: */
131: protected int eventCreationPointIndex;
132:
133: /**
134: * Where was the event created (as a Throwable)?
135: */
136: protected Throwable eventCreationPoint;
137:
138: /**
139: * Where was the event created (as a string description of the
140: * eventCreationPoint)?
141: */
142: protected String eventCreationPointDesc;
143:
144: /**
145: * Optional event message
146: */
147: protected String message;
148:
149: /**
150: * Creates a new profiler event
151: *
152: * @param eventType
153: * the event type (from the constants TYPE_????)
154: * @param hostName
155: * the hostname where the event occurs
156: * @param catalog
157: * the catalog in use
158: * @param connectionId
159: * the connection id (-1 if N/A)
160: * @param statementId
161: * the statement id (-1 if N/A)
162: * @param resultSetId
163: * the result set id (-1 if N/A)
164: * @param eventCreationTime
165: * when was the event created?
166: * @param eventDurationMillis
167: * how long did the event last?
168: * @param eventCreationPointDesc
169: * event creation point as a string
170: * @param eventCreationPoint
171: * event creation point as a Throwable
172: * @param message
173: * optional message
174: */
175: public ProfilerEvent(byte eventType, String hostName,
176: String catalog, long connectionId, int statementId,
177: int resultSetId, long eventCreationTime,
178: long eventDuration, String durationUnits,
179: String eventCreationPointDesc,
180: Throwable eventCreationPoint, String message) {
181: this .eventType = eventType;
182: this .connectionId = connectionId;
183: this .statementId = statementId;
184: this .resultSetId = resultSetId;
185: this .eventCreationTime = eventCreationTime;
186: this .eventDuration = eventDuration;
187: this .durationUnits = durationUnits;
188: this .eventCreationPoint = eventCreationPoint;
189: this .eventCreationPointDesc = eventCreationPointDesc;
190: this .message = message;
191: }
192:
193: /**
194: * Returns the description of when this event was created.
195: *
196: * @return a description of when this event was created.
197: */
198: public String getEventCreationPointAsString() {
199: if (this .eventCreationPointDesc == null) {
200: this .eventCreationPointDesc = Util
201: .stackTraceToString(this .eventCreationPoint);
202: }
203:
204: return this .eventCreationPointDesc;
205: }
206:
207: /**
208: * Returns a representation of this event as a String.
209: *
210: * @return a String representation of this event.
211: */
212: public String toString() {
213: StringBuffer buf = new StringBuffer(32);
214:
215: switch (this .eventType) {
216: case TYPE_EXECUTE:
217: buf.append("EXECUTE");
218: break;
219:
220: case TYPE_FETCH:
221: buf.append("FETCH");
222: break;
223:
224: case TYPE_OBJECT_CREATION:
225: buf.append("CONSTRUCT");
226: break;
227:
228: case TYPE_PREPARE:
229: buf.append("PREPARE");
230: break;
231:
232: case TYPE_QUERY:
233: buf.append("QUERY");
234: break;
235:
236: case TYPE_WARN:
237: buf.append("WARN");
238: break;
239: case TYPE_SLOW_QUERY:
240: buf.append("SLOW QUERY");
241: break;
242: default:
243: buf.append("UNKNOWN");
244: }
245:
246: buf.append(" created: ");
247: buf.append(new Date(this .eventCreationTime));
248: buf.append(" duration: ");
249: buf.append(this .eventDuration);
250: buf.append(" connection: ");
251: buf.append(this .connectionId);
252: buf.append(" statement: ");
253: buf.append(this .statementId);
254: buf.append(" resultset: ");
255: buf.append(this .resultSetId);
256:
257: if (this .message != null) {
258: buf.append(" message: ");
259: buf.append(this .message);
260:
261: }
262:
263: if (this .eventCreationPointDesc != null) {
264: buf.append("\n\nEvent Created at:\n");
265: buf.append(this .eventCreationPointDesc);
266: }
267:
268: return buf.toString();
269: }
270:
271: /**
272: * Unpacks a binary representation of this event.
273: *
274: * @param buf
275: * the binary representation of this event
276: * @return the unpacked Event
277: * @throws Exception
278: * if an error occurs while unpacking the event
279: */
280: public static ProfilerEvent unpack(byte[] buf) throws Exception {
281: int pos = 0;
282:
283: byte eventType = buf[pos++];
284: long connectionId = readInt(buf, pos);
285: pos += 8;
286: int statementId = readInt(buf, pos);
287: pos += 4;
288: int resultSetId = readInt(buf, pos);
289: pos += 4;
290: long eventCreationTime = readLong(buf, pos);
291: pos += 8;
292: long eventDuration = readLong(buf, pos);
293: pos += 4;
294:
295: byte[] eventDurationUnits = readBytes(buf, pos);
296: pos += 4;
297:
298: if (eventDurationUnits != null) {
299: pos += eventDurationUnits.length;
300: }
301:
302: int eventCreationPointIndex = readInt(buf, pos);
303: pos += 4;
304: byte[] eventCreationAsBytes = readBytes(buf, pos);
305: pos += 4;
306:
307: if (eventCreationAsBytes != null) {
308: pos += eventCreationAsBytes.length;
309: }
310:
311: byte[] message = readBytes(buf, pos);
312: pos += 4;
313:
314: if (message != null) {
315: pos += message.length;
316: }
317:
318: return new ProfilerEvent(eventType, "", "", connectionId,
319: statementId, resultSetId, eventCreationTime,
320: eventDuration, new String(eventDurationUnits,
321: "ISO8859_1"), new String(eventCreationAsBytes,
322: "ISO8859_1"), null, new String(message,
323: "ISO8859_1"));
324: }
325:
326: /**
327: * Creates a binary representation of this event.
328: *
329: * @return a binary representation of this event
330: * @throws Exception
331: * if an error occurs while packing this event.
332: */
333: public byte[] pack() throws Exception {
334:
335: int len = 1 + 4 + 4 + 4 + 8 + 4 + 4;
336:
337: byte[] eventCreationAsBytes = null;
338:
339: getEventCreationPointAsString();
340:
341: if (this .eventCreationPointDesc != null) {
342: eventCreationAsBytes = this .eventCreationPointDesc
343: .getBytes("ISO8859_1");
344: len += (4 + eventCreationAsBytes.length);
345: } else {
346: len += 4;
347: }
348:
349: byte[] messageAsBytes = null;
350:
351: if (messageAsBytes != null) {
352: messageAsBytes = this .message.getBytes("ISO8859_1");
353: len += (4 + messageAsBytes.length);
354: } else {
355: len += 4;
356: }
357:
358: byte[] durationUnitsAsBytes = null;
359:
360: if (durationUnits != null) {
361: durationUnitsAsBytes = this .durationUnits
362: .getBytes("ISO8859_1");
363: len += (4 + durationUnitsAsBytes.length);
364: } else {
365: len += 4;
366: }
367:
368: byte[] buf = new byte[len];
369:
370: int pos = 0;
371:
372: buf[pos++] = this .eventType;
373: pos = writeLong(this .connectionId, buf, pos);
374: pos = writeInt(this .statementId, buf, pos);
375: pos = writeInt(this .resultSetId, buf, pos);
376: pos = writeLong(this .eventCreationTime, buf, pos);
377: pos = writeLong(this .eventDuration, buf, pos);
378: pos = writeBytes(durationUnitsAsBytes, buf, pos);
379: pos = writeInt(this .eventCreationPointIndex, buf, pos);
380:
381: if (eventCreationAsBytes != null) {
382: pos = writeBytes(eventCreationAsBytes, buf, pos);
383: } else {
384: pos = writeInt(0, buf, pos);
385: }
386:
387: if (messageAsBytes != null) {
388: pos = writeBytes(messageAsBytes, buf, pos);
389: } else {
390: pos = writeInt(0, buf, pos);
391: }
392:
393: return buf;
394: }
395:
396: private static int writeInt(int i, byte[] buf, int pos) {
397:
398: buf[pos++] = (byte) (i & 0xff);
399: buf[pos++] = (byte) (i >>> 8);
400: buf[pos++] = (byte) (i >>> 16);
401: buf[pos++] = (byte) (i >>> 24);
402:
403: return pos;
404: }
405:
406: private static int writeLong(long l, byte[] buf, int pos) {
407: buf[pos++] = (byte) (l & 0xff);
408: buf[pos++] = (byte) (l >>> 8);
409: buf[pos++] = (byte) (l >>> 16);
410: buf[pos++] = (byte) (l >>> 24);
411: buf[pos++] = (byte) (l >>> 32);
412: buf[pos++] = (byte) (l >>> 40);
413: buf[pos++] = (byte) (l >>> 48);
414: buf[pos++] = (byte) (l >>> 56);
415:
416: return pos;
417: }
418:
419: private static int writeBytes(byte[] msg, byte[] buf, int pos) {
420: pos = writeInt(msg.length, buf, pos);
421:
422: System.arraycopy(msg, 0, buf, pos, msg.length);
423:
424: return pos + msg.length;
425: }
426:
427: private static int readInt(byte[] buf, int pos) {
428: return (buf[pos++] & 0xff) | ((buf[pos++] & 0xff) << 8)
429: | ((buf[pos++] & 0xff) << 16)
430: | ((buf[pos++] & 0xff) << 24);
431:
432: }
433:
434: private static long readLong(byte[] buf, int pos) {
435: return (long) (buf[pos++] & 0xff)
436: | ((long) (buf[pos++] & 0xff) << 8)
437: | ((long) (buf[pos++] & 0xff) << 16)
438: | ((long) (buf[pos++] & 0xff) << 24)
439: | ((long) (buf[pos++] & 0xff) << 32)
440: | ((long) (buf[pos++] & 0xff) << 40)
441: | ((long) (buf[pos++] & 0xff) << 48)
442: | ((long) (buf[pos++] & 0xff) << 56);
443: }
444:
445: private static byte[] readBytes(byte[] buf, int pos) {
446: int length = readInt(buf, pos);
447:
448: pos += 4;
449:
450: byte[] msg = new byte[length];
451: System.arraycopy(buf, pos, msg, 0, length);
452:
453: return msg;
454: }
455:
456: /**
457: * Returns the catalog in use
458: *
459: * @return the catalog in use
460: */
461: public String getCatalog() {
462: return this .catalog;
463: }
464:
465: /**
466: * Returns the id of the connection in use when this event was created.
467: *
468: * @return the connection in use
469: */
470: public long getConnectionId() {
471: return this .connectionId;
472: }
473:
474: /**
475: * Returns the point (as a Throwable stacktrace) where this event was
476: * created.
477: *
478: * @return the point where this event was created
479: */
480: public Throwable getEventCreationPoint() {
481: return this .eventCreationPoint;
482: }
483:
484: /**
485: * Returns the time (in System.currentTimeMillis() form) when this event was
486: * created
487: *
488: * @return the time this event was created
489: */
490: public long getEventCreationTime() {
491: return this .eventCreationTime;
492: }
493:
494: /**
495: * Returns the duration of the event in milliseconds
496: *
497: * @return the duration of the event in milliseconds
498: */
499: public long getEventDuration() {
500: return this .eventDuration;
501: }
502:
503: /**
504: * Returns the units for getEventDuration()
505: */
506: public String getDurationUnits() {
507: return this .durationUnits;
508: }
509:
510: /**
511: * Returns the event type flag
512: *
513: * @return the event type flag
514: */
515: public byte getEventType() {
516: return this .eventType;
517: }
518:
519: /**
520: * Returns the id of the result set in use when this event was created.
521: *
522: * @return the result set in use
523: */
524: public int getResultSetId() {
525: return this .resultSetId;
526: }
527:
528: /**
529: * Returns the id of the statement in use when this event was created.
530: *
531: * @return the statement in use
532: */
533: public int getStatementId() {
534: return this .statementId;
535: }
536:
537: /**
538: * Returns the optional message for this event
539: *
540: * @return the message stored in this event
541: */
542: public String getMessage() {
543: return this.message;
544: }
545: }
|