Line data Source code
1 : // Copyright (C) 2014 The Android Open Source Project 2 : // 3 : // Licensed under the Apache License, Version 2.0 (the "License"); 4 : // you may not use this file except in compliance with the License. 5 : // You may obtain a copy of the License at 6 : // 7 : // http://www.apache.org/licenses/LICENSE-2.0 8 : // 9 : // Unless required by applicable law or agreed to in writing, software 10 : // distributed under the License is distributed on an "AS IS" BASIS, 11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 : // See the License for the specific language governing permissions and 13 : // limitations under the License. 14 : 15 : package com.google.gerrit.server.restapi.config; 16 : 17 : import com.google.gerrit.common.Nullable; 18 : import com.google.gerrit.common.data.GlobalCapability; 19 : import com.google.gerrit.extensions.annotations.RequiresCapability; 20 : import com.google.gerrit.extensions.restapi.Response; 21 : import com.google.gerrit.extensions.restapi.RestReadView; 22 : import com.google.gerrit.server.config.ConfigResource; 23 : import com.google.gerrit.server.config.SitePath; 24 : import com.google.gerrit.server.git.WorkQueue; 25 : import com.google.gerrit.server.git.WorkQueue.Task; 26 : import com.google.inject.Inject; 27 : import java.io.IOException; 28 : import java.lang.management.ManagementFactory; 29 : import java.lang.management.OperatingSystemMXBean; 30 : import java.lang.management.RuntimeMXBean; 31 : import java.lang.management.ThreadInfo; 32 : import java.lang.management.ThreadMXBean; 33 : import java.net.InetAddress; 34 : import java.net.UnknownHostException; 35 : import java.nio.file.Path; 36 : import java.nio.file.Paths; 37 : import java.util.Arrays; 38 : import java.util.Collection; 39 : import java.util.HashMap; 40 : import java.util.List; 41 : import java.util.Map; 42 : import org.eclipse.jgit.storage.file.WindowCacheStats; 43 : import org.kohsuke.args4j.Option; 44 : 45 : @RequiresCapability(GlobalCapability.MAINTAIN_SERVER) 46 : public class GetSummary implements RestReadView<ConfigResource> { 47 : 48 : private final WorkQueue workQueue; 49 : private final Path sitePath; 50 : 51 : @Option(name = "--gc", usage = "perform Java GC before retrieving memory stats") 52 : private boolean gc; 53 : 54 : public GetSummary setGc(boolean gc) { 55 0 : this.gc = gc; 56 0 : return this; 57 : } 58 : 59 : @Option(name = "--jvm", usage = "include details about the JVM") 60 : private boolean jvm; 61 : 62 : public GetSummary setJvm(boolean jvm) { 63 0 : this.jvm = jvm; 64 0 : return this; 65 : } 66 : 67 : @Inject 68 2 : public GetSummary(WorkQueue workQueue, @SitePath Path sitePath) { 69 2 : this.workQueue = workQueue; 70 2 : this.sitePath = sitePath; 71 2 : } 72 : 73 : @Override 74 : public Response<SummaryInfo> apply(ConfigResource rsrc) { 75 1 : if (gc) { 76 0 : System.gc(); 77 0 : System.runFinalization(); 78 0 : System.gc(); 79 : } 80 : 81 1 : SummaryInfo summary = new SummaryInfo(); 82 1 : summary.taskSummary = getTaskSummary(); 83 1 : summary.memSummary = getMemSummary(); 84 1 : summary.threadSummary = getThreadSummary(); 85 1 : if (jvm) { 86 0 : summary.jvmSummary = getJvmSummary(); 87 : } 88 1 : return Response.ok(summary); 89 : } 90 : 91 : private TaskSummaryInfo getTaskSummary() { 92 1 : Collection<Task<?>> pending = workQueue.getTasks(); 93 1 : int tasksTotal = pending.size(); 94 1 : int tasksStopping = 0; 95 1 : int tasksRunning = 0; 96 1 : int tasksStarting = 0; 97 1 : int tasksReady = 0; 98 1 : int tasksSleeping = 0; 99 1 : for (Task<?> task : pending) { 100 1 : switch (task.getState()) { 101 : case STOPPING: 102 0 : tasksStopping++; 103 0 : break; 104 : case RUNNING: 105 0 : tasksRunning++; 106 0 : break; 107 : case STARTING: 108 0 : tasksStarting++; 109 0 : break; 110 : case READY: 111 0 : tasksReady++; 112 0 : break; 113 : case SLEEPING: 114 1 : tasksSleeping++; 115 1 : break; 116 : case CANCELLED: 117 : case DONE: 118 : case OTHER: 119 : break; 120 : } 121 1 : } 122 : 123 1 : TaskSummaryInfo taskSummary = new TaskSummaryInfo(); 124 1 : taskSummary.total = toInteger(tasksTotal); 125 1 : taskSummary.stopping = toInteger(tasksStopping); 126 1 : taskSummary.running = toInteger(tasksRunning); 127 1 : taskSummary.starting = toInteger(tasksStarting); 128 1 : taskSummary.ready = toInteger(tasksReady); 129 1 : taskSummary.sleeping = toInteger(tasksSleeping); 130 1 : return taskSummary; 131 : } 132 : 133 : private MemSummaryInfo getMemSummary() { 134 1 : Runtime r = Runtime.getRuntime(); 135 1 : long mMax = r.maxMemory(); 136 1 : long mFree = r.freeMemory(); 137 1 : long mTotal = r.totalMemory(); 138 1 : long mInuse = mTotal - mFree; 139 : 140 1 : long jgitOpen = WindowCacheStats.getStats().getOpenFileCount(); 141 1 : long jgitBytes = WindowCacheStats.getStats().getOpenByteCount(); 142 : 143 1 : MemSummaryInfo memSummaryInfo = new MemSummaryInfo(); 144 1 : memSummaryInfo.total = bytes(mTotal); 145 1 : memSummaryInfo.used = bytes(mInuse - jgitBytes); 146 1 : memSummaryInfo.free = bytes(mFree); 147 1 : memSummaryInfo.buffers = bytes(jgitBytes); 148 1 : memSummaryInfo.max = bytes(mMax); 149 1 : memSummaryInfo.openFiles = Long.valueOf(jgitOpen); 150 1 : return memSummaryInfo; 151 : } 152 : 153 : private ThreadSummaryInfo getThreadSummary() { 154 1 : Runtime r = Runtime.getRuntime(); 155 1 : ThreadSummaryInfo threadInfo = new ThreadSummaryInfo(); 156 1 : threadInfo.cpus = r.availableProcessors(); 157 1 : threadInfo.threads = toInteger(ManagementFactory.getThreadMXBean().getThreadCount()); 158 : 159 1 : List<String> prefixes = 160 1 : Arrays.asList( 161 : "H2", 162 : "HTTP", 163 : "IntraLineDiff", 164 : "ReceiveCommits", 165 : "SSH git-receive-pack", 166 : "SSH git-upload-pack", 167 : "SSH-Interactive-Worker", 168 : "SSH-Stream-Worker", 169 : "SshCommandStart", 170 : "sshd-SshServer"); 171 1 : String other = "Other"; 172 1 : ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); 173 : 174 1 : threadInfo.counts = new HashMap<>(); 175 1 : for (long id : threadMXBean.getAllThreadIds()) { 176 1 : ThreadInfo info = threadMXBean.getThreadInfo(id); 177 1 : if (info == null) { 178 0 : continue; 179 : } 180 1 : String name = info.getThreadName(); 181 1 : Thread.State state = info.getThreadState(); 182 1 : String group = other; 183 1 : for (String p : prefixes) { 184 1 : if (name.startsWith(p)) { 185 1 : group = p; 186 1 : break; 187 : } 188 1 : } 189 1 : Map<Thread.State, Integer> counts = threadInfo.counts.get(group); 190 1 : if (counts == null) { 191 1 : counts = new HashMap<>(); 192 1 : threadInfo.counts.put(group, counts); 193 : } 194 1 : Integer c = counts.get(state); 195 1 : counts.put(state, c != null ? c + 1 : 1); 196 : } 197 : 198 1 : return threadInfo; 199 : } 200 : 201 : private JvmSummaryInfo getJvmSummary() { 202 0 : OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean(); 203 0 : RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean(); 204 : 205 0 : JvmSummaryInfo jvmSummary = new JvmSummaryInfo(); 206 0 : jvmSummary.vmVendor = runtimeBean.getVmVendor(); 207 0 : jvmSummary.vmName = runtimeBean.getVmName(); 208 0 : jvmSummary.vmVersion = runtimeBean.getVmVersion(); 209 0 : jvmSummary.osName = osBean.getName(); 210 0 : jvmSummary.osVersion = osBean.getVersion(); 211 0 : jvmSummary.osArch = osBean.getArch(); 212 0 : jvmSummary.user = System.getProperty("user.name"); 213 : 214 : try { 215 0 : jvmSummary.host = InetAddress.getLocalHost().getHostName(); 216 0 : } catch (UnknownHostException e) { 217 : // Ignored 218 0 : } 219 : 220 0 : jvmSummary.currentWorkingDirectory = path(Paths.get(".").toAbsolutePath().getParent()); 221 0 : jvmSummary.site = path(sitePath); 222 0 : return jvmSummary; 223 : } 224 : 225 : @Nullable 226 : private static Integer toInteger(int i) { 227 1 : return i != 0 ? i : null; 228 : } 229 : 230 : private static String bytes(double value) { 231 1 : value /= 1024; 232 1 : String suffix = "k"; 233 : 234 1 : if (value > 1024) { 235 1 : value /= 1024; 236 1 : suffix = "m"; 237 : } 238 1 : if (value > 1024) { 239 0 : value /= 1024; 240 0 : suffix = "g"; 241 : } 242 1 : return String.format("%1$6.2f%2$s", value, suffix).trim(); 243 : } 244 : 245 : private static String path(Path path) { 246 : try { 247 0 : return path.toRealPath().normalize().toString(); 248 0 : } catch (IOException err) { 249 0 : return path.toAbsolutePath().normalize().toString(); 250 : } 251 : } 252 : 253 1 : public static class SummaryInfo { 254 : public TaskSummaryInfo taskSummary; 255 : public MemSummaryInfo memSummary; 256 : public ThreadSummaryInfo threadSummary; 257 : public JvmSummaryInfo jvmSummary; 258 : } 259 : 260 1 : public static class TaskSummaryInfo { 261 : public Integer total; 262 : public Integer stopping; 263 : public Integer running; 264 : public Integer starting; 265 : public Integer ready; 266 : public Integer sleeping; 267 : } 268 : 269 1 : public static class MemSummaryInfo { 270 : public String total; 271 : public String used; 272 : public String free; 273 : public String buffers; 274 : public String max; 275 : public Long openFiles; 276 : } 277 : 278 1 : public static class ThreadSummaryInfo { 279 : public Integer cpus; 280 : public Integer threads; 281 : public Map<String, Map<Thread.State, Integer>> counts; 282 : } 283 : 284 0 : public static class JvmSummaryInfo { 285 : public String vmVendor; 286 : public String vmName; 287 : public String vmVersion; 288 : public String osName; 289 : public String osVersion; 290 : public String osArch; 291 : public String user; 292 : public String host; 293 : public String currentWorkingDirectory; 294 : public String site; 295 : } 296 : }