|
| 1 | +/*[INCLUDE-IF Sidecar18-SE]*/ |
| 2 | +/******************************************************************************* |
| 3 | + * Copyright (c) 2019, 2019 IBM Corp. and others |
| 4 | + * |
| 5 | + * This program and the accompanying materials are made available under |
| 6 | + * the terms of the Eclipse Public License 2.0 which accompanies this |
| 7 | + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ |
| 8 | + * or the Apache License, Version 2.0 which accompanies this distribution and |
| 9 | + * is available at https://www.apache.org/licenses/LICENSE-2.0. |
| 10 | + * |
| 11 | + * This Source Code may also be made available under the following |
| 12 | + * Secondary Licenses when the conditions for such availability set |
| 13 | + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU |
| 14 | + * General Public License, version 2 with the GNU Classpath |
| 15 | + * Exception [1] and GNU General Public License, version 2 with the |
| 16 | + * OpenJDK Assembly Exception [2]. |
| 17 | + * |
| 18 | + * [1] https://www.gnu.org/software/classpath/license.html |
| 19 | + * [2] http://openjdk.java.net/legal/assembly-exception.html |
| 20 | + * |
| 21 | + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception |
| 22 | + *******************************************************************************/ |
| 23 | + |
| 24 | +package openj9.tools.attach.diagnostics.tools; |
| 25 | + |
| 26 | +import java.io.IOException; |
| 27 | + |
| 28 | +import openj9.internal.tools.attach.target.AttachHandler; |
| 29 | +import openj9.internal.tools.attach.target.DiagnosticProperties; |
| 30 | +import openj9.internal.tools.attach.target.IPC; |
| 31 | +import openj9.tools.attach.diagnostics.attacher.AttacherDiagnosticsProvider; |
| 32 | + |
| 33 | +/** |
| 34 | + * JStat A tool for statistics monitoring of another Java process |
| 35 | + * |
| 36 | + */ |
| 37 | +@SuppressWarnings("nls") |
| 38 | +public class Jstat { |
| 39 | + |
| 40 | + private static String vmid; |
| 41 | + private static String statOption; |
| 42 | + |
| 43 | + private static final String OPTION_CLASS = "-class"; |
| 44 | + private static final String[] OPTIONS = { OPTION_CLASS }; |
| 45 | + |
| 46 | + private static final String ERROR_AN_ARG_REQUIRED = "An argument is required"; |
| 47 | + private static final String ERROR_INVALID_ARG = "An invalid argument"; |
| 48 | + private static final String ERROR_INVALID_OPTION = "An invalid option"; |
| 49 | + private static final String ERROR_INVALID_VMID = "Can't monitor this utility JVM itself: "; |
| 50 | + private static final String ERROR_NOT_EXIST_VMID = "No such process for vmid: "; |
| 51 | + private static final String ERROR_OPTION_REQUIRED = "An <option> is required"; |
| 52 | + private static final String ERROR_VMID_REQUIRED = "A <vmid> is required"; |
| 53 | + |
| 54 | + private static String HELPTEXT = "jstat: obtain statistics information about a Java process%n" |
| 55 | + + " Usage:%n" |
| 56 | + + " jstat [<option>] [<vmid>]%n" |
| 57 | + + "%n" |
| 58 | + + " option:%n" |
| 59 | + + " -J : supply arguments to the Java VM running jstat%n" |
| 60 | + + " -h : print this help message%n" |
| 61 | + + " -options : list the available command options%n" |
| 62 | + + " -class : Classloading statistics%n" |
| 63 | + + " <vmid>: Attach API VM ID as shown in jps or other Attach API-based tools%n" |
| 64 | + + "NOTE: this utility may significantly affect the performance of the target VM.%n" |
| 65 | + + "At least one option must be selected.%n"; |
| 66 | + |
| 67 | + /** |
| 68 | + * Print a list of Java processes and information about them. |
| 69 | + * |
| 70 | + * @param args |
| 71 | + * Arguments to the application |
| 72 | + */ |
| 73 | + public static void main(String[] args) { |
| 74 | + if (parseArguments(args)) { |
| 75 | + if (vmid == null || vmid.isEmpty()) { |
| 76 | + // no valid vmid supplied, print error message and help text, and exit |
| 77 | + Util.exitJVMWithReasonAndHelp(ERROR_VMID_REQUIRED, HELPTEXT); |
| 78 | + } |
| 79 | + |
| 80 | + AttacherDiagnosticsProvider diagProvider = new AttacherDiagnosticsProvider(); |
| 81 | + String myId = AttachHandler.getVmId(); |
| 82 | + |
| 83 | + if (vmid.equals(myId)) { |
| 84 | + // this utility doesn't monitor itself, print error message and help text, and exit |
| 85 | + Util.exitJVMWithReasonAndHelp(ERROR_INVALID_VMID + vmid, HELPTEXT); |
| 86 | + } |
| 87 | + |
| 88 | + // if the ID looks like a process ID, check if it is running |
| 89 | + if (vmid.matches("\\d+")) { |
| 90 | + if (!IPC.processExists(Long.parseLong(vmid))) { |
| 91 | + Util.exitJVMWithReasonAndHelp(ERROR_NOT_EXIST_VMID + vmid, HELPTEXT); |
| 92 | + } |
| 93 | + } |
| 94 | + |
| 95 | + try { |
| 96 | + diagProvider.attach(vmid); |
| 97 | + Util.runCommandAndPrintResult(diagProvider, statOption, "jstat"); |
| 98 | + } catch (Exception e) { |
| 99 | + System.err.printf("Error getting data from %s", vmid); |
| 100 | + final String msg = e.getMessage(); |
| 101 | + if (msg == null) { |
| 102 | + System.err.println(); |
| 103 | + } else { |
| 104 | + if (msg.matches(IPC.INCOMPATIBLE_JAVA_VERSION)) { |
| 105 | + System.err.println(": incompatible target JVM"); |
| 106 | + } else { |
| 107 | + System.err.printf(": %s%n", msg); |
| 108 | + } |
| 109 | + } |
| 110 | + if (DiagnosticProperties.isDebug) { |
| 111 | + e.printStackTrace(); |
| 112 | + } |
| 113 | + } finally { |
| 114 | + try { |
| 115 | + diagProvider.detach(); |
| 116 | + } catch (IOException e) { |
| 117 | + // ignore |
| 118 | + } |
| 119 | + } |
| 120 | + } |
| 121 | + } |
| 122 | + |
| 123 | + private static boolean parseArguments(String[] args) { |
| 124 | + boolean foundStatOption = false; |
| 125 | + |
| 126 | + if ((args == null) || (args.length == 0)) { |
| 127 | + // no argument supplied, print error message and help text, and exit |
| 128 | + Util.exitJVMWithReasonAndHelp(ERROR_AN_ARG_REQUIRED, HELPTEXT); |
| 129 | + } else if (Util.checkHelpOption(args[0])) { |
| 130 | + // Help argument is supplied, print help text |
| 131 | + System.out.printf(HELPTEXT); |
| 132 | + } else if ("-options".equals(args[0])) { |
| 133 | + if (args.length > 1) { |
| 134 | + // there are more arguments after -options, print error message and help text, and exit |
| 135 | + Util.exitJVMWithReasonAndHelp(ERROR_INVALID_ARG, HELPTEXT); |
| 136 | + } |
| 137 | + // print options available |
| 138 | + for (String option : OPTIONS) { |
| 139 | + System.out.println(option); |
| 140 | + } |
| 141 | + } else { |
| 142 | + for (String arg : args) { |
| 143 | + if (arg.startsWith("-")) { |
| 144 | + if (statOption != null) { |
| 145 | + // one option has already been set, print error message and help text, and exit |
| 146 | + Util.exitJVMWithReasonAndHelp(ERROR_INVALID_ARG, HELPTEXT); |
| 147 | + } else { |
| 148 | + foundStatOption = true; |
| 149 | + switch (arg) { |
| 150 | + case OPTION_CLASS: |
| 151 | + statOption = "jstat.class"; |
| 152 | + break; |
| 153 | + default: |
| 154 | + // invalid option was specified, print error message and help text, and exit |
| 155 | + Util.exitJVMWithReasonAndHelp(ERROR_INVALID_OPTION, HELPTEXT); |
| 156 | + } |
| 157 | + } |
| 158 | + } else { |
| 159 | + if (statOption == null) { |
| 160 | + // no option was specified, print error message and help text, and exit |
| 161 | + Util.exitJVMWithReasonAndHelp(ERROR_OPTION_REQUIRED, HELPTEXT); |
| 162 | + } else if (vmid != null) { |
| 163 | + // one vmid has already been set, print error message and help text, and exit |
| 164 | + Util.exitJVMWithReasonAndHelp(ERROR_INVALID_ARG, HELPTEXT); |
| 165 | + } else { |
| 166 | + vmid = arg; |
| 167 | + } |
| 168 | + } |
| 169 | + } |
| 170 | + } |
| 171 | + |
| 172 | + return foundStatOption; |
| 173 | + } |
| 174 | +} |
0 commit comments