LCOV - code coverage report
Current view: top level - sshd/commands - ShowCaches.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 10 112 8.9 %
Date: 2022-11-19 15:00:39 Functions: 5 15 33.3 %

          Line data    Source code
       1             : // Copyright (C) 2009 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.sshd.commands;
      16             : 
      17             : import static com.google.gerrit.common.data.GlobalCapability.MAINTAIN_SERVER;
      18             : import static com.google.gerrit.common.data.GlobalCapability.VIEW_CACHES;
      19             : import static com.google.gerrit.sshd.CommandMetaData.Mode.MASTER_OR_SLAVE;
      20             : 
      21             : import com.google.common.base.Strings;
      22             : import com.google.gerrit.common.Version;
      23             : import com.google.gerrit.extensions.annotations.RequiresAnyCapability;
      24             : import com.google.gerrit.extensions.events.LifecycleListener;
      25             : import com.google.gerrit.extensions.restapi.AuthException;
      26             : import com.google.gerrit.server.CurrentUser;
      27             : import com.google.gerrit.server.cache.CacheDisplay;
      28             : import com.google.gerrit.server.cache.CacheInfo;
      29             : import com.google.gerrit.server.config.ConfigResource;
      30             : import com.google.gerrit.server.permissions.GlobalPermission;
      31             : import com.google.gerrit.server.permissions.PermissionBackend;
      32             : import com.google.gerrit.server.permissions.PermissionBackendException;
      33             : import com.google.gerrit.server.restapi.config.GetSummary;
      34             : import com.google.gerrit.server.restapi.config.GetSummary.JvmSummaryInfo;
      35             : import com.google.gerrit.server.restapi.config.GetSummary.MemSummaryInfo;
      36             : import com.google.gerrit.server.restapi.config.GetSummary.SummaryInfo;
      37             : import com.google.gerrit.server.restapi.config.GetSummary.TaskSummaryInfo;
      38             : import com.google.gerrit.server.restapi.config.GetSummary.ThreadSummaryInfo;
      39             : import com.google.gerrit.server.restapi.config.ListCaches;
      40             : import com.google.gerrit.server.util.time.TimeUtil;
      41             : import com.google.gerrit.sshd.CommandMetaData;
      42             : import com.google.gerrit.sshd.SshCommand;
      43             : import com.google.gerrit.sshd.SshDaemon;
      44             : import com.google.inject.Inject;
      45             : import java.io.IOException;
      46             : import java.time.Instant;
      47             : import java.time.ZoneId;
      48             : import java.time.format.DateTimeFormatter;
      49             : import java.util.Collection;
      50             : import java.util.Map;
      51             : import org.apache.sshd.common.io.IoAcceptor;
      52             : import org.apache.sshd.common.io.IoSession;
      53             : import org.apache.sshd.mina.MinaSession;
      54             : import org.apache.sshd.server.Environment;
      55             : import org.apache.sshd.server.channel.ChannelSession;
      56             : import org.kohsuke.args4j.Option;
      57             : 
      58             : /** Show the current cache states. */
      59             : @RequiresAnyCapability({VIEW_CACHES, MAINTAIN_SERVER})
      60             : @CommandMetaData(
      61             :     name = "show-caches",
      62             :     description = "Display current cache statistics",
      63             :     runsAt = MASTER_OR_SLAVE)
      64           1 : final class ShowCaches extends SshCommand {
      65             :   private static volatile long serverStarted;
      66             : 
      67          17 :   static class StartupListener implements LifecycleListener {
      68             :     @Override
      69             :     public void start() {
      70          17 :       serverStarted = TimeUtil.nowMs();
      71          17 :     }
      72             : 
      73             :     @Override
      74          17 :     public void stop() {}
      75             :   }
      76             : 
      77             :   @Option(name = "--gc", usage = "perform Java GC before printing memory stats")
      78             :   private boolean gc;
      79             : 
      80             :   @Option(name = "--show-jvm", usage = "show details about the JVM")
      81             :   private boolean showJVM;
      82             : 
      83             :   @Option(name = "--show-threads", usage = "show detailed thread counts")
      84             :   private boolean showThreads;
      85             : 
      86             :   @Inject private SshDaemon daemon;
      87             :   @Inject private ListCaches listCaches;
      88             :   @Inject private GetSummary getSummary;
      89             :   @Inject private CurrentUser self;
      90             :   @Inject private PermissionBackend permissionBackend;
      91             : 
      92           1 :   @Option(
      93             :       name = "--width",
      94             :       aliases = {"-w"},
      95             :       metaVar = "COLS",
      96             :       usage = "width of output table")
      97             :   private int columns = 80;
      98             : 
      99             :   private int nw;
     100             : 
     101             :   @Override
     102             :   public void start(ChannelSession channel, Environment env) throws IOException {
     103           1 :     String s = env.getEnv().get(Environment.ENV_COLUMNS);
     104           1 :     if (s != null && !s.isEmpty()) {
     105             :       try {
     106           0 :         columns = Integer.parseInt(s);
     107           0 :       } catch (NumberFormatException err) {
     108           0 :         columns = 80;
     109           0 :       }
     110             :     }
     111           1 :     super.start(channel, env);
     112           1 :   }
     113             : 
     114             :   @Override
     115             :   protected void run() throws Failure {
     116           0 :     enableGracefulStop();
     117           0 :     nw = columns - 50;
     118           0 :     Instant now = Instant.now();
     119           0 :     DateTimeFormatter fmt =
     120           0 :         DateTimeFormatter.ofPattern("HH:mm:ss   zzz").withZone(ZoneId.of("UTC"));
     121           0 :     stdout.format(
     122             :         "%-25s %-20s      now  %16s\n",
     123             :         "Gerrit Code Review",
     124           0 :         Version.getVersion() != null ? Version.getVersion() : "",
     125           0 :         fmt.format(now));
     126           0 :     stdout.format(
     127           0 :         "%-25s %-20s   uptime %16s\n", "", "", uptime(now.toEpochMilli() - serverStarted));
     128           0 :     stdout.print('\n');
     129             : 
     130             :     try {
     131           0 :       new CacheDisplay(stdout, nw, getCaches()).displayCaches();
     132             : 
     133             :       boolean showJvm;
     134             :       try {
     135           0 :         permissionBackend.user(self).check(GlobalPermission.MAINTAIN_SERVER);
     136           0 :         showJvm = true;
     137           0 :       } catch (AuthException | PermissionBackendException e) {
     138             :         // Silently ignore and do not display detailed JVM information.
     139           0 :         showJvm = false;
     140           0 :       }
     141           0 :       if (showJvm) {
     142           0 :         sshSummary();
     143             : 
     144           0 :         SummaryInfo summary =
     145           0 :             getSummary.setGc(gc).setJvm(showJVM).apply(new ConfigResource()).value();
     146           0 :         taskSummary(summary.taskSummary);
     147           0 :         memSummary(summary.memSummary);
     148           0 :         threadSummary(summary.threadSummary);
     149             : 
     150           0 :         if (showJVM && summary.jvmSummary != null) {
     151           0 :           jvmSummary(summary.jvmSummary);
     152             :         }
     153             :       }
     154           0 :     } catch (Exception e) {
     155           0 :       throw new Failure(1, "unavailable", e);
     156           0 :     }
     157             : 
     158           0 :     stdout.flush();
     159           0 :   }
     160             : 
     161             :   private Collection<CacheInfo> getCaches() {
     162             :     @SuppressWarnings("unchecked")
     163           0 :     Map<String, CacheInfo> caches =
     164           0 :         (Map<String, CacheInfo>) listCaches.apply(new ConfigResource()).value();
     165           0 :     for (Map.Entry<String, CacheInfo> entry : caches.entrySet()) {
     166           0 :       CacheInfo cache = entry.getValue();
     167           0 :       cache.name = entry.getKey();
     168           0 :     }
     169           0 :     return caches.values();
     170             :   }
     171             : 
     172             :   private void memSummary(MemSummaryInfo memSummary) {
     173           0 :     stdout.format(
     174             :         "Mem: %s total = %s used + %s free + %s buffers\n",
     175             :         memSummary.total, memSummary.used, memSummary.free, memSummary.buffers);
     176           0 :     stdout.format("     %s max\n", memSummary.max);
     177           0 :     stdout.format("    %8d open files\n", nullToZero(memSummary.openFiles));
     178           0 :     stdout.print('\n');
     179           0 :   }
     180             : 
     181             :   private void threadSummary(ThreadSummaryInfo threadSummary) {
     182           0 :     stdout.format(
     183             :         "Threads: %d CPUs available, %d threads\n", threadSummary.cpus, threadSummary.threads);
     184             : 
     185           0 :     if (showThreads) {
     186           0 :       stdout.print(String.format("  %22s", ""));
     187           0 :       for (Thread.State s : Thread.State.values()) {
     188           0 :         stdout.print(String.format(" %14s", s.name()));
     189             :       }
     190           0 :       stdout.print('\n');
     191           0 :       for (Map.Entry<String, Map<Thread.State, Integer>> e : threadSummary.counts.entrySet()) {
     192           0 :         stdout.print(String.format("  %-22s", e.getKey()));
     193           0 :         for (Thread.State s : Thread.State.values()) {
     194           0 :           stdout.print(String.format(" %14d", nullToZero(e.getValue().get(s))));
     195             :         }
     196           0 :         stdout.print('\n');
     197           0 :       }
     198             :     }
     199           0 :     stdout.print('\n');
     200           0 :   }
     201             : 
     202             :   private void taskSummary(TaskSummaryInfo taskSummary) {
     203           0 :     stdout.format(
     204             :         "Tasks: %4d  total = %4d running +   %4d ready + %4d sleeping\n",
     205           0 :         nullToZero(taskSummary.total),
     206           0 :         nullToZero(taskSummary.running),
     207           0 :         nullToZero(taskSummary.ready),
     208           0 :         nullToZero(taskSummary.sleeping));
     209           0 :   }
     210             : 
     211             :   private static int nullToZero(Integer i) {
     212           0 :     return i != null ? i : 0;
     213             :   }
     214             : 
     215             :   private static long nullToZero(Long i) {
     216           0 :     return i != null ? i : 0;
     217             :   }
     218             : 
     219             :   private void sshSummary() {
     220           0 :     IoAcceptor acceptor = daemon.getIoAcceptor();
     221           0 :     if (acceptor == null) {
     222           0 :       return;
     223             :     }
     224             : 
     225           0 :     long now = TimeUtil.nowMs();
     226           0 :     Collection<IoSession> list = acceptor.getManagedSessions().values();
     227           0 :     long oldest = now;
     228             : 
     229           0 :     for (IoSession s : list) {
     230           0 :       if (s instanceof MinaSession) {
     231           0 :         MinaSession minaSession = (MinaSession) s;
     232           0 :         oldest = Math.min(oldest, minaSession.getSession().getCreationTime());
     233             :       }
     234           0 :     }
     235             : 
     236           0 :     stdout.format(
     237           0 :         "SSH:   %4d  users, oldest session started %s ago\n", list.size(), uptime(now - oldest));
     238           0 :   }
     239             : 
     240             :   private void jvmSummary(JvmSummaryInfo jvmSummary) {
     241           0 :     stdout.format("JVM: %s %s %s\n", jvmSummary.vmVendor, jvmSummary.vmName, jvmSummary.vmVersion);
     242           0 :     stdout.format("  on %s %s %s\n", jvmSummary.osName, jvmSummary.osVersion, jvmSummary.osArch);
     243           0 :     stdout.format("  running as %s on %s\n", jvmSummary.user, Strings.nullToEmpty(jvmSummary.host));
     244           0 :     stdout.format("  cwd  %s\n", jvmSummary.currentWorkingDirectory);
     245           0 :     stdout.format("  site %s\n", jvmSummary.site);
     246           0 :   }
     247             : 
     248             :   private String uptime(long uptimeMillis) {
     249           0 :     if (uptimeMillis < 1000) {
     250           0 :       return String.format("%3d ms", uptimeMillis);
     251             :     }
     252             : 
     253           0 :     long uptime = uptimeMillis / 1000L;
     254             : 
     255           0 :     long min = uptime / 60;
     256           0 :     if (min < 60) {
     257           0 :       return String.format("%2d min %2d sec", min, uptime - min * 60);
     258             :     }
     259             : 
     260           0 :     long hr = uptime / 3600;
     261           0 :     if (hr < 24) {
     262           0 :       min = (uptime - hr * 3600) / 60;
     263           0 :       return String.format("%2d hrs %2d min", hr, min);
     264             :     }
     265             : 
     266           0 :     long days = uptime / (24 * 3600);
     267           0 :     hr = (uptime - (days * 24 * 3600)) / 3600;
     268           0 :     return String.format("%4d days %2d hrs", days, hr);
     269             :   }
     270             : }

Generated by: LCOV version 1.16+git.20220603.dfeb750