4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
26 * ident "%Z%%M% %I% %E% SMI"
28 import org.opensolaris.os.dtrace.*;
31 import java.util.logging.*;
34 * Emulates {@code dtrace(1M)} using the Java DTrace API.
36 public class JDTrace {
37 static Logger logger = Logger.getLogger(JDTrace.class.getName());
39 static Consumer dtrace;
42 Handler handler = new ConsoleHandler();
43 handler.setLevel(Level.ALL);
44 logger.addHandler(handler);
47 static final String CLASSNAME = "JDTrace";
48 static final String OPTSTR =
49 "3:6:b:c:CD:ef:Fi:I:lL:m:n:o:p:P:qs:U:vVwx:X:Z";
50 static boolean heading = false;
51 static boolean quiet = false;
52 static boolean flow = false;
53 static int stackindent = 14;
54 static int exitStatus = 0;
55 static boolean started;
56 static boolean stopped;
57 static PrintStream out = System.out;
58 static final String ATS = "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@";
59 static final String SPACES = " ";
60 static final int QUANTIZE_ZERO_BUCKET = 63;
74 static class CompileRequest {
77 ProbeDescription.Spec probespec;
80 // Modify program string by expanding an incomplete probe
81 // description according to the requested probespec.
83 applyProbespec(CompileRequest req)
85 ProbeDescription.Spec spec = ((req.probespec == null)
86 ? ProbeDescription.Spec.NAME
90 switch (req.probespec) {
102 StringBuffer buf = new StringBuffer();
105 int len = req.s.length();
108 // Find first whitespace character not including leading
109 // whitespace (end of first token). Ignore whitespace
110 // inside a block if the block is concatenated with the
111 // probe description.
112 for (; (i < len) && Character.isWhitespace(req.s.charAt(i)); ++i);
114 boolean inBlock = false;
115 for (; (npos < len) &&
116 (!Character.isWhitespace(ch = req.s.charAt(npos)) ||
120 } else if (ch == '}') {
125 // libdtrace lets you concatenate multiple probe
126 // descriptions separated by code blocks in curly braces,
127 // for example genunix::'{printf("FOUND");}'::entry, as long
128 // as the concatenated probe descriptions begin with ':' and
129 // not a specific field such as 'syscall'. So to expand the
130 // possibly multiple probe descriptions, we need to insert
131 // colons before each open curly brace, and again at the end
132 // only if there is at least one non-whitespace (probe
133 // specifying) character after the last closing curly brace.
137 for (; (i < npos) && (req.s.charAt(i) != '{'); ++i);
138 buf.append(req.s.substring(prev_i, i));
139 if ((i < npos) || ((i > 0) && (req.s.charAt(i - 1) != '}'))) {
140 for (int c = 0; c < colons; ++c) {
145 buf.append(req.s.charAt(i++));
150 // append remainder of program text
151 buf.append(req.s.substring(i));
153 req.s = buf.toString();
158 printValue(Object value, int bytes, String stringFormat)
160 if (value instanceof Integer) {
162 out.printf(" %3d", (Integer)value);
163 } else if (bytes == 2) {
164 out.printf(" %5d", (Integer)value);
166 out.printf(" %8d", (Integer)value);
168 } else if (value instanceof Long) {
169 out.printf(" %16d", (Long)value);
171 out.printf(stringFormat, value.toString());
176 consumeProbeData(ProbeData data)
178 if (logger.isLoggable(Level.FINER)) {
179 logger.finer(data.toString());
184 out.printf("%3s %-41s\n", "CPU", "FUNCTION");
187 out.printf("%3s %6s %32s\n",
188 "CPU", "ID", "FUNCTION:NAME");
193 ProbeDescription probe = data.getEnabledProbeDescription();
195 Flow flow = data.getFlow();
196 int indent = (flow.getDepth() * 2);
197 StringBuffer buf = new StringBuffer();
200 for (int i = 0; i < indent; ++i) {
204 switch (flow.getKind()) {
221 switch (flow.getKind()) {
223 buf.append(probe.getFunction());
225 buf.append(probe.getName());
228 buf.append(probe.getFunction());
231 out.printf("%3s %-41s ", data.getCPU(),
235 StringBuffer buf = new StringBuffer();
236 buf.append(probe.getFunction());
238 buf.append(probe.getName());
239 out.printf("%3s %6s %32s ",
240 data.getCPU(), probe.getID(),
244 Record record = null;
246 List <Record> records = data.getRecords();
247 Iterator <Record> itr = records.iterator();
248 while (itr.hasNext()) {
251 if (record instanceof ExitRecord) {
252 exitStatus = ((ExitRecord)record).getStatus();
253 } else if (record instanceof ScalarRecord) {
254 ScalarRecord scalar = (ScalarRecord)record;
255 value = scalar.getValue();
256 if (value instanceof byte[]) {
257 out.print(record.toString());
262 printValue(value, scalar.getNumberOfBytes(),
266 } else if (record instanceof PrintfRecord) {
268 } else if (record instanceof PrintaRecord) {
269 PrintaRecord printa = (PrintaRecord)record;
270 List <Tuple> tuples = printa.getTuples();
271 if (tuples.isEmpty()) {
272 out.print(printa.getOutput());
274 for (Tuple t : tuples) {
275 out.print(printa.getFormattedString(t));
279 if (logger.isLoggable(Level.FINE)) {
280 logger.fine(printa.toString());
282 } else if (record instanceof StackValueRecord) {
283 printStack((StackValueRecord)record);
292 printDistribution(Distribution d)
294 out.printf("\n%16s %41s %-9s\n", "value",
295 "------------- Distribution -------------",
297 long v; // bucket frequency (value)
298 long b; // lower bound of bucket range
300 boolean positives = false;
301 boolean negatives = false;
303 Distribution.Bucket bucket;
304 int b1 = 0; // first displayed bucket
305 int b2 = d.size() - 1; // last displayed bucket
306 for (; (b1 <= b2) && (d.get(b1).getFrequency() == 0); ++b1);
307 // If possible, get one bucket before the first non-zero
308 // bucket and one bucket after the last.
310 // There isn't any data. This is possible if (and only if)
311 // negative increment values have been used. In this case,
312 // print the buckets around the base.
313 if (d instanceof LinearDistribution) {
317 b1 = QUANTIZE_ZERO_BUCKET - 1;
318 b2 = QUANTIZE_ZERO_BUCKET + 1;
322 for (; (b2 > 0) && (d.get(b2).getFrequency() == 0); --b2);
323 if (b2 < (d.size() - 1)) ++b2;
325 for (int i = b1; i <= b2; ++i) {
326 v = d.get(i).getFrequency();
333 total += Math.abs((double)v);
335 for (int i = b1; i <= b2; ++i) {
337 v = bucket.getFrequency();
340 if (d instanceof LinearDistribution) {
341 if (b == Long.MIN_VALUE) {
342 String lt = "< " + ((LinearDistribution)d).getBase();
343 out.printf("%16s ", lt);
344 } else if (bucket.getMax() == Long.MAX_VALUE) {
345 String ge = ">= " + b;
346 out.printf("%16s ", ge);
348 out.printf("%16d ", b);
351 out.printf("%16d ", b);
354 printDistributionLine(v, total, positives, negatives);
359 printDistributionLine(long val, double total, boolean positives,
365 assert (ATS.length() == len && SPACES.length() == len);
366 assert (!(total == 0 && (positives || negatives)));
367 assert (!(val < 0 && !negatives));
368 assert (!(val > 0 && !positives));
369 assert (!(val != 0 && total == 0));
373 f = (Math.abs((double)val) * (double)len) / total;
374 depth = (int)(f + 0.5);
379 out.printf("|%s%s %-9d\n", ATS.substring(len - depth),
380 SPACES.substring(depth), val);
385 f = (Math.abs((double)val) * (double)len) / total;
386 depth = (int)(f + 0.5);
388 out.printf("%s%s| %-9d\n", SPACES.substring(depth),
389 ATS.substring(len - depth), val);
394 * If we're here, we have both positive and negative bucket values.
395 * To express this graphically, we're going to generate both positive
396 * and negative bars separated by a centerline. These bars are half
397 * the size of normal quantize()/lquantize() bars, so we divide the
398 * length in half before calculating the bar length.
401 String ats = ATS.substring(len);
402 String spaces = SPACES.substring(len);
404 f = (Math.abs((double)val) * (double)len) / total;
405 depth = (int)(f + 0.5);
408 out.printf("%s%s|%s %-9d\n", spaces.substring(depth),
409 ats.substring(len - depth), repeat(" ", len), val);
412 out.printf("%20s|%s%s %-9d\n", "", ats.substring(len - depth),
413 spaces.substring(depth), val);
418 repeat(String s, int n)
420 StringBuffer buf = new StringBuffer();
421 for (int i = 0; i < n; ++i) {
424 return buf.toString();
428 printStack(StackValueRecord rec)
430 StackFrame[] frames = rec.getStackFrames();
434 for (StackFrame f : frames) {
435 for (i = 0; i < stackindent; ++i) {
439 if (s.indexOf('[') == 0) {
447 printAggregate(Aggregate aggregate)
449 printAggregationRecords(aggregate.getOrderedRecords());
453 printAggregationRecords(List <AggregationRecord> list)
456 AggregationValue value;
457 ValueRecord tupleRecord;
460 for (AggregationRecord r : list) {
461 tuple = r.getTuple();
462 value = r.getValue();
464 for (i = 0; i < len; ++i) {
465 tupleRecord = tuple.get(i);
466 if (tupleRecord instanceof StackValueRecord) {
467 printStack((StackValueRecord)tupleRecord);
468 } else if (tupleRecord instanceof SymbolValueRecord) {
469 printValue(tupleRecord.toString(), -1, " %-50s");
471 printValue(tupleRecord.getValue(),
472 ((ScalarRecord)tupleRecord).getNumberOfBytes(),
476 if (value instanceof Distribution) {
477 Distribution d = (Distribution)value;
478 printDistribution(d);
480 Number v = value.getValue();
481 printValue(v, -1, " %-50s");
501 String predact = "[[ predicate ] action ]";
502 System.err.printf("Usage: java %s [-32|-64] [-CeFlqvVwZ] " +
503 "[-b bufsz] [-c cmd] [-D name[=def]]\n\t[-I path] [-L path] " +
504 "[-o output] [-p pid] [-s script] [-U name]\n\t" +
505 "[-x opt[=val]] [-X a|c|s|t]\n\n" +
506 "\t[-P provider %s]\n" +
507 "\t[-m [ provider: ] module %s]\n" +
508 "\t[-f [[ provider: ] module: ] func %s]\n" +
509 "\t[-n [[[ provider: ] module: ] func: ] name %s]\n" +
510 "\t[-i probe-id %s] [ args ... ]\n\n", CLASSNAME,
511 predact, predact, predact, predact, predact);
512 System.err.printf("\tpredicate -> '/' D-expression '/'\n");
513 System.err.printf("\t action -> '{' D-statements '}'\n");
514 System.err.printf("\n" +
515 "\t-32 generate 32-bit D programs\n" +
516 "\t-64 generate 64-bit D programs\n\n" +
517 "\t-b set trace buffer size\n" +
518 "\t-c run specified command and exit upon its completion\n" +
519 "\t-C run cpp(1) preprocessor on script files\n" +
520 "\t-D define symbol when invoking preprocessor\n" +
521 "\t-e exit after compiling request but prior to enabling " +
523 "\t-f enable or list probes matching the specified " +
525 "\t-F coalesce trace output by function\n" +
526 "\t-i enable or list probes matching the specified probe id\n" +
527 "\t-I add include directory to preprocessor search path\n" +
528 "\t-l list probes matching specified criteria\n" +
529 "\t-L add library directory to library search path\n" +
530 "\t-m enable or list probes matching the specified " +
532 "\t-n enable or list probes matching the specified probe name\n" +
533 "\t-o set output file\n" +
534 "\t-p grab specified process-ID and cache its symbol tables\n" +
535 "\t-P enable or list probes matching the specified " +
537 "\t-q set quiet mode (only output explicitly traced data)\n" +
538 "\t-s enable or list probes according to the specified " +
540 "\t-U undefine symbol when invoking preprocessor\n" +
541 "\t-v set verbose mode (report stability attributes, " +
543 "\t-V report DTrace API version\n" +
544 "\t-w permit destructive actions\n" +
545 "\t-x enable or modify compiler and tracing options\n" +
546 "\t-X specify ISO C conformance settings for preprocessor\n" +
547 "\t-Z permit probe descriptions that match zero probes\n" +
549 "\tTo log PrintaRecord, set this environment variable:\n" +
550 "\t\tJDTRACE_LOGGING_LEVEL=FINE\n" +
551 "\tTo log ProbeData, set JDTRACE_LOGGING_LEVEL=FINER\n");
556 printProgramStability(String programType, String programDescription,
560 out.printf("Stability data for %s %s:\n\n",
561 programType, programDescription);
562 InterfaceAttributes a;
563 out.println("\tMinimum probe description " +
565 a = info.getMinimumProbeAttributes();
566 out.printf("\t\tIdentifier Names: %s\n",
567 a.getNameStability());
568 out.printf("\t\tData Semantics: %s\n",
569 a.getDataStability());
570 out.printf("\t\tDependency Class: %s\n",
571 a.getDependencyClass());
572 out.println("\tMinimum probe statement attributes");
573 a = info.getMinimumStatementAttributes();
574 out.printf("\t\tIdentifier Names: %s\n",
575 a.getNameStability());
576 out.printf("\t\tData Semantics: %s\n",
577 a.getDataStability());
578 out.printf("\t\tDependency Class: %s\n",
579 a.getDependencyClass());
583 printProbeDescription(ProbeDescription p)
585 out.printf("%5d %10s %17s %33s %s\n", p.getID(),
586 p.getProvider(), p.getModule(),
587 p.getFunction(), p.getName());
591 printProbeInfo(ProbeInfo p)
593 InterfaceAttributes a;
594 out.println("\n\tProbe Description Attributes");
596 a = p.getProbeAttributes();
597 out.printf("\t\tIdentifier Names: %s\n",
598 a.getNameStability());
599 out.printf("\t\tData Semantics: %s\n",
600 a.getDataStability());
601 out.printf("\t\tDependency Class: %s\n",
602 a.getDependencyClass());
604 out.println("\n\tArgument Attributes");
606 a = p.getArgumentAttributes();
607 out.printf("\t\tIdentifier Names: %s\n",
608 a.getNameStability());
609 out.printf("\t\tData Semantics: %s\n",
610 a.getDataStability());
611 out.printf("\t\tDependency Class: %s\n",
612 a.getDependencyClass());
614 // Argument types unsupported for now.
622 String loggingLevel = System.getenv().get("JDTRACE_LOGGING_LEVEL");
624 logger.setLevel(Level.parse(loggingLevel));
625 } catch (Exception e) {
626 logger.setLevel(Level.OFF);
629 if (args.length == 0) {
633 List <CompileRequest> compileRequests = new LinkedList
635 List <Program> programList = new LinkedList <Program> ();
636 boolean verbose = false;
637 Mode mode = Mode.EXEC;
639 final ExceptionHandler exceptionHandler = new ExceptionHandler() {
640 public void handleException(Throwable e) {
641 if (e instanceof DTraceException) {
642 DTraceException de = (DTraceException)e;
643 System.err.printf("dtrace: %s\n", de.getMessage());
644 } else if (e instanceof ConsumerException) {
645 ConsumerException ce = (ConsumerException)e;
646 Object msg = ce.getNotificationObject();
647 if ((msg instanceof org.opensolaris.os.dtrace.Error) ||
648 (msg instanceof Drop)) {
649 System.err.printf("dtrace: %s\n", ce.getMessage());
651 ce.printStackTrace();
660 Getopt g = new Getopt(CLASSNAME, args, OPTSTR);
663 List <Consumer.OpenFlag> openFlags =
664 new ArrayList <Consumer.OpenFlag> ();
666 while ((c = g.getopt()) != -1) {
669 String s = g.getOptarg();
670 if (!s.equals("2")) {
671 System.err.println("dtrace: illegal option -- 3" + s);
674 openFlags.add(Consumer.OpenFlag.ILP32);
678 String s = g.getOptarg();
679 if (!s.equals("4")) {
680 System.err.println("dtrace: illegal option -- 6" + s);
683 openFlags.add(Consumer.OpenFlag.LP64);
689 Consumer.OpenFlag[] oflags = new Consumer.OpenFlag[openFlags.size()];
690 oflags = openFlags.toArray(oflags);
692 dtrace = new LocalConsumer() {
693 protected Thread createThread() {
694 Thread t = super.createThread();
696 t.setPriority(Thread.MIN_PRIORITY);
701 g = new Getopt(CLASSNAME, args, OPTSTR);
707 // Set default options that may be overriden by options or #pragma
708 dtrace.setOption(Option.bufsize, Option.mb(4));
709 dtrace.setOption(Option.aggsize, Option.mb(4));
712 while ((c = g.getopt()) != -1) {
715 dtrace.setOption(Option.bufsize, g.getOptarg());
718 dtrace.createProcess(g.getOptarg());
721 dtrace.setOption(Option.cpp);
724 dtrace.setOption(Option.define, g.getOptarg());
730 r = new CompileRequest();
732 r.type = ProgramType.STRING;
733 r.probespec = ProbeDescription.Spec.FUNCTION;
734 compileRequests.add(r);
737 dtrace.setOption(Option.flowindent);
740 r = new CompileRequest();
742 r.type = ProgramType.STRING;
743 r.probespec = ProbeDescription.Spec.NAME;
744 compileRequests.add(r);
747 dtrace.setOption(Option.incdir, g.getOptarg());
751 dtrace.setOption(Option.zdefs); // -l implies -Z
754 dtrace.setOption(Option.libdir, g.getOptarg());
757 r = new CompileRequest();
759 r.type = ProgramType.STRING;
760 r.probespec = ProbeDescription.Spec.MODULE;
761 compileRequests.add(r);
764 r = new CompileRequest();
766 r.type = ProgramType.STRING;
767 r.probespec = ProbeDescription.Spec.NAME;
768 compileRequests.add(r);
771 String outFileName = g.getOptarg();
772 File outFile = new File(outFileName);
774 FileOutputStream fos = new FileOutputStream(
776 out = new PrintStream(fos);
777 } catch (FileNotFoundException e) {
778 System.err.println("failed to open " +
779 outFileName + " in write mode");
781 } catch (SecurityException e) {
782 System.err.println("failed to open " +
788 String pidstr = g.getOptarg();
791 pid = Integer.parseInt(pidstr);
792 } catch (NumberFormatException e) {
793 System.err.println("invalid pid: " + pidstr);
796 dtrace.grabProcess(pid);
799 r = new CompileRequest();
801 r.type = ProgramType.STRING;
802 r.probespec = ProbeDescription.Spec.PROVIDER;
803 compileRequests.add(r);
806 dtrace.setOption(Option.quiet);
809 r = new CompileRequest();
811 r.type = ProgramType.FILE;
812 compileRequests.add(r);
815 dtrace.setOption(Option.undef, g.getOptarg());
824 dtrace.setOption(Option.destructive);
827 String[] xarg = g.getOptarg().split("=", 2);
828 if (xarg.length > 1) {
829 dtrace.setOption(xarg[0], xarg[1]);
830 } else if (xarg.length == 1) {
831 dtrace.setOption(xarg[0]);
835 dtrace.setOption(Option.stdc, g.getOptarg());
838 dtrace.setOption(Option.zdefs);
841 usage(); // getopt() already printed an error
844 System.err.print("getopt() returned " + c + "\n");
849 List <String> argList = new LinkedList <String> ();
850 for (int i = g.getOptind(); i < args.length; ++i) {
851 argList.add(args[i]);
854 if (mode == Mode.VERSION) {
855 out.printf("dtrace: %s\n", dtrace.getVersion());
860 String[] compileArgs = new String[argList.size()];
861 compileArgs = argList.toArray(compileArgs);
864 for (CompileRequest req : compileRequests) {
868 program = dtrace.compile(req.s, compileArgs);
871 File file = new File(req.s);
872 program = dtrace.compile(file, compileArgs);
875 throw new IllegalArgumentException(
876 "Unexpected program type: " + req.type);
879 programList.add(program);
882 // Get options set by #pragmas in compiled program
884 quiet = (dtrace.getOption(Option.quiet) != Option.UNSET);
885 flow = (dtrace.getOption(Option.flowindent) != Option.UNSET);
886 optval = dtrace.getOption("stackindent");
887 if (optval != Option.UNSET) {
888 stackindent = (int)optval;
891 if (mode == Mode.LIST) {
892 out.printf("%5s %10s %17s %33s %s\n",
893 "ID", "PROVIDER", "MODULE", "FUNCTION", "NAME");
896 List <List <Probe>> lists =
897 new LinkedList <List <Probe>> ();
898 for (Program p : programList) {
899 lists.add(dtrace.listProgramProbeDetail(p));
903 for (List <Probe> list : lists) {
904 for (Probe probe : list) {
905 p = probe.getDescription();
906 pinfo = probe.getInfo();
907 printProbeDescription(p);
908 printProbeInfo(pinfo);
912 List <List <ProbeDescription>> lists =
913 new LinkedList <List <ProbeDescription>> ();
914 for (Program p : programList) {
915 lists.add(dtrace.listProgramProbes(p));
917 for (List <ProbeDescription> list : lists) {
918 for (ProbeDescription p : list) {
919 printProbeDescription(p);
927 String programDescription;
929 for (Program p : programList) {
930 if (p instanceof Program.File) {
931 Program.File pf = (Program.File)p;
932 programType = "script";
933 programDescription = pf.getFile().getPath();
935 programType = "description";
937 p.getContents().split("[/{;]", 2)[0];
940 if (mode == Mode.EXEC) {
943 dtrace.getProgramInfo(p);
946 if ((mode == Mode.EXEC) && !quiet) {
947 System.err.printf("dtrace: %s '%s' matched %d probe%s\n",
948 programType, programDescription,
949 info.getMatchingProbeCount(),
950 info.getMatchingProbeCount() == 1 ? "" : "s");
953 printProgramStability(programType,
954 programDescription, info);
957 if (mode != Mode.EXEC) {
960 dtrace.addConsumerListener(new ConsumerAdapter() {
961 public void consumerStarted(ConsumerEvent e) {
964 public void consumerStopped(ConsumerEvent e) {
968 Aggregate aggregate = dtrace.getAggregate();
969 if (aggregate != null) {
970 printAggregate(aggregate);
973 } catch (Throwable x) {
974 exceptionHandler.handleException(x);
978 public void dataDropped(DropEvent e) {
979 System.err.printf("dtrace: %s",
980 e.getDrop().getDefaultMessage());
982 public void errorEncountered(ErrorEvent e)
983 throws ConsumerException {
984 org.opensolaris.os.dtrace.Error error = e.getError();
985 if (logger.isLoggable(Level.FINE)) {
986 logger.fine(error.toString());
988 System.err.printf("dtrace: %s",
989 error.getDefaultMessage());
991 public void dataReceived(DataEvent e)
992 throws ConsumerException {
993 consumeProbeData(e.getProbeData());
995 public void processStateChanged(ProcessEvent e)
996 throws ConsumerException {
997 if (logger.isLoggable(Level.FINE)) {
998 logger.fine(e.getProcessState().toString());
1002 // Print unprinted aggregations after Ctrl-C
1003 Runtime.getRuntime().addShutdownHook(new Thread() {
1005 if (stopped || !started) {
1010 Aggregate aggregate = dtrace.getAggregate();
1011 if (aggregate != null) {
1014 printAggregate(aggregate);
1016 } catch (Throwable x) {
1017 exceptionHandler.handleException(x);
1021 dtrace.go(exceptionHandler);
1022 } catch (DTraceException e) {
1025 if (g.getOptarg() == null) {
1026 System.err.printf("dtrace: failed to set -%c: %s\n",
1029 System.err.printf("dtrace: failed to set -%c %s: %s\n",
1030 c, g.getOptarg(), e.getMessage());
1034 System.err.printf("dtrace: %s\n", e.getMessage());
1037 } catch (Exception e) {
1038 e.printStackTrace();