content: /*
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF licenses this file
   * to you under the Apache License, Version 2.0 (the
   * "License"); you may not use this file except in compliance
   * with the License.  You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package org.apache.cassandra.tools.nodetool.stats;
  
  import java.io.PrintStream;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  import java.util.stream.Stream;
  
  import com.google.common.collect.Multimap;
  
  import org.apache.cassandra.tools.nodetool.formatter.TableBuilder;
  
  import static java.util.stream.Collectors.toList;
  
  public class TpStatsPrinter
  {
      public static StatsPrinter from(String format)
      {
          switch (format)
          {
              case "json":
                  return new StatsPrinter.JsonPrinter();
              case "yaml":
                  return new StatsPrinter.YamlPrinter();
              default:
                  return new DefaultPrinter();
          }
      }
  
      public static class DefaultPrinter implements StatsPrinter<TpStatsHolder>
      {
          @Override
          public void print(TpStatsHolder data, PrintStream out, boolean verbose)
          {
              final TableBuilder poolBuilder = new TableBuilder();
  
              if (verbose)
                  poolBuilder.add("Pool Name", "Active", "Pending", "Completed", "Blocked", "All time blocked", "Core Pool Size", "Max Pool Size", "Max Tasks Queued");
              else
                  poolBuilder.add("Pool Name", "Active", "Pending", "Completed", "Blocked", "All time blocked");
  
              final Multimap<String, String> threadPools = data.probe.getThreadPools();
  
              for (final Map.Entry<String, String> tpool : threadPools.entries())
              {
                  List<String> values = new ArrayList<>();
                  values.add(tpool.getValue());
                  values.add(data.probe.getThreadPoolMetric(tpool.getKey(), tpool.getValue(), "ActiveTasks").toString());
                  values.add(data.probe.getThreadPoolMetric(tpool.getKey(), tpool.getValue(), "PendingTasks").toString());
                  values.add(data.probe.getThreadPoolMetric(tpool.getKey(), tpool.getValue(), "CompletedTasks").toString());
                  values.add(data.probe.getThreadPoolMetric(tpool.getKey(), tpool.getValue(), "CurrentlyBlockedTasks").toString());
                  values.add(data.probe.getThreadPoolMetric(tpool.getKey(), tpool.getValue(), "TotalBlockedTasks").toString());
  
                  if (verbose)
                  {
                      values.add(data.probe.getThreadPoolMetric(tpool.getKey(), tpool.getValue(), "CorePoolSize").toString());
                      values.add(data.probe.getThreadPoolMetric(tpool.getKey(), tpool.getValue(), "MaxPoolSize").toString());
                      values.add(data.probe.getThreadPoolMetric(tpool.getKey(), tpool.getValue(), "MaxTasksQueued").toString());
                  }
  
                  poolBuilder.add(values);
              }
  
              poolBuilder.printTo(out);
  
              out.println("\nLatencies waiting in queue (micros) per dropped message types");
  
              final TableBuilder droppedBuilder = new TableBuilder();
              droppedBuilder.add("Message type", "Dropped    ", "50%     ", "95%     ", "99%     ", "Max");
  
              final HashMap<String, Object> droppedMessage = new HashMap<>();
              final HashMap<String, Double[]> waitLatencies = new HashMap<>();
  
              for (final Map.Entry<String, Integer> entry : data.probe.getDroppedMessages().entrySet())
              {
                  droppedMessage.put(entry.getKey(), entry.getValue());
                  try
                  {
                      waitLatencies.put(entry.getKey(), data.probe.metricPercentilesAsArray(data.probe.getMessagingQueueWaitMetrics(entry.getKey())));
                  }
                  catch (RuntimeException e)
                  {
                      // ignore the exceptions when fetching metrics
                  }
              }
  
              for (final Map.Entry<String, Object> entry : droppedMessage.entrySet())
              {
                  final List<String> columns = Stream.of(entry.getKey(), entry.getValue().toString()).collect(toList());
  
                  if (waitLatencies.containsKey(entry.getKey()))
                  {
                      final Double[] latencies = waitLatencies.get(entry.getKey());
                      columns.addAll(Arrays.asList(latencies[0].toString(),
                                                   latencies[2].toString(),
                                                   latencies[4].toString(),
                                                   latencies[6].toString()));
                  }
                  else
                  {
                      columns.addAll(Arrays.asList("N/A", "N/A", "N/A", "N/A"));
                  }
  
                  droppedBuilder.add(columns.toArray(new String[0]));
              }
  
              droppedBuilder.printTo(out);
          }
  
          @Override
          public void print(TpStatsHolder data, PrintStream out)
          {
              print(data, out, false);
          }
      }
  }
  