1 /* 2 * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package jdk.jfr.internal.dcmd; 26 27 import java.time.Duration; 28 import java.time.ZoneId; 29 import java.util.ArrayList; 30 import java.util.Collection; 31 import java.util.Collections; 32 import java.util.Comparator; 33 import java.util.List; 34 import java.util.Map; 35 import java.util.StringJoiner; 36 37 import jdk.jfr.EventType; 38 import jdk.jfr.Recording; 39 import jdk.jfr.SettingDescriptor; 40 import jdk.jfr.internal.LogLevel; 41 import jdk.jfr.internal.LogTag; 42 import jdk.jfr.internal.Logger; 43 import jdk.jfr.internal.OldObjectSample; 44 import jdk.jfr.internal.PrivateAccess; 45 46 /** 47 * JFR.check - invoked from native 48 * 49 */ 50 final class DCmdCheck extends AbstractDCmd { 51 /** 52 * Execute JFR.check 53 * 54 * @param recordingText name or id of the recording to check, or 55 * <code>null</code> to show a list of all recordings. 56 * 57 * @param verbose if event settings should be included. 58 * 59 * @return result output 60 * 61 * @throws DCmdException if the check could not be completed. 62 */ 63 public String execute(String recordingText, Boolean verbose) throws DCmdException { 64 executeInternal(recordingText, verbose); 65 return getResult(); 66 } 67 68 private void executeInternal(String name, Boolean verbose) throws DCmdException { 69 if (LogTag.JFR_DCMD.shouldLog(LogLevel.DEBUG)) { 70 Logger.log(LogTag.JFR_DCMD, LogLevel.DEBUG, "Executing DCmdCheck: name=" + name + ", verbose=" + verbose); 71 } 72 73 if (verbose == null) { 74 verbose = Boolean.FALSE; 75 } 76 77 if (name != null) { 78 printRecording(findRecording(name), verbose); 79 return; 80 } 81 82 List<Recording> recordings = getRecordings(); 83 if (!verbose && recordings.isEmpty()) { 84 println("No available recordings."); 85 println(); 86 println("Use jcmd " + getPid() + " JFR.start to start a recording."); 87 return; 88 } 89 boolean first = true; 90 for (Recording recording : recordings) { 91 // Print separation between recordings, 92 if (!first) { 93 println(); 94 if (Boolean.TRUE.equals(verbose)) { 95 println(); 96 } 97 } 98 first = false; 99 printRecording(recording, verbose); 100 } 101 } 102 103 private void printRecording(Recording recording, boolean verbose) { 104 printGeneral(recording); 105 if (verbose) { 106 println(); 107 printSetttings(recording); 108 } 109 } 110 111 private void printGeneral(Recording recording) { 112 var platformRecording = PrivateAccess.getInstance().getPlatformRecording(recording); 113 print("Recording " + recording.getId() + ": name=" + recording.getName()); 114 115 print(" settings=" + platformRecording.getConfigNames()); 116 117 var delay = platformRecording.getDelay(); 118 print(" delay="); 119 if (delay == null) { 120 print("<N/A>"); 121 } else { 122 printTimespan(delay, ""); 123 print(" (" + recording.getStartTime().atZone(ZoneId.systemDefault()) + ")"); 124 } 125 126 Duration duration = recording.getDuration(); 127 print(" duration="); 128 if (duration == null) { 129 print("<N/A>"); 130 } else { 131 printTimespan(duration, ""); 132 } 133 134 print(" disk=" + recording.isToDisk()); 135 136 print(" filename="); 137 var path = recording.getDestination(); 138 if (path == null) { 139 var dir = platformRecording.getDumpOnExitDirectory(); 140 if (dir != null) { 141 path = dir.toPath(); 142 } 143 } 144 print(path == null ? "<N/A>" : path.toString()); 145 146 Duration maxAge = recording.getMaxAge(); 147 print(" maxage="); 148 if (maxAge == null) { 149 print("<N/A>"); 150 } else { 151 printTimespan(maxAge, ""); 152 } 153 154 print(" maxsize="); 155 printBytes(recording.getMaxSize(), ""); 156 157 print(" dumponexit=" + recording.getDumpOnExit()); 158 159 print(" path-to-gc-roots=" + OldObjectSample.isPathToGcRootsEnabled(recording)); 160 161 print(" (" + recording.getState().toString().toLowerCase() + ")"); 162 println(); 163 } 164 165 private void printSetttings(Recording recording) { 166 Map<String, String> settings = recording.getSettings(); 167 for (EventType eventType : sortByEventPath(getFlightRecorder().getEventTypes())) { 168 StringJoiner sj = new StringJoiner(",", "[", "]"); 169 sj.setEmptyValue(""); 170 for (SettingDescriptor s : eventType.getSettingDescriptors()) { 171 String settingsPath = eventType.getName() + "#" + s.getName(); 172 if (settings.containsKey(settingsPath)) { 173 sj.add(s.getName() + "=" + settings.get(settingsPath)); 174 } 175 } 176 String settingsText = sj.toString(); 177 if (!settingsText.isEmpty()) { 178 print(" %s (%s)", eventType.getLabel(), eventType.getName()); 179 println(); 180 println(" " + settingsText); 181 } 182 } 183 } 184 185 private static List<EventType> sortByEventPath(Collection<EventType> events) { 186 List<EventType> sorted = new ArrayList<>(); 187 sorted.addAll(events); 188 Collections.sort(sorted, new Comparator<EventType>() { 189 @Override 190 public int compare(EventType e1, EventType e2) { 191 return e1.getName().compareTo(e2.getName()); 192 } 193 }); 194 return sorted; 195 } 196 }