public SLSWebApp(SchedulerWrapper wrapper, int metricsAddressPort) {
   this.wrapper = wrapper;
   metrics = wrapper.getMetrics();
   handleOperTimecostHistogramMap = new HashMap<SchedulerEventType, Histogram>();
   queueAllocatedMemoryCounterMap = new HashMap<String, Counter>();
   queueAllocatedVCoresCounterMap = new HashMap<String, Counter>();
   schedulerMetrics = wrapper.getSchedulerMetrics();
   port = metricsAddressPort;
 }
  /**
   * html page for tracking one queue or job use d3.js
   *
   * @param request http request
   * @param response http response
   * @throws java.io.IOException
   */
  private void printPageTrack(
      HttpServletRequest request, HttpServletResponse response, int timeunit, String timeunitLabel)
      throws IOException {
    response.setContentType("text/html");
    response.setStatus(HttpServletResponse.SC_OK);

    // tracked queues {0}
    StringBuilder trackedQueueInfo = new StringBuilder();
    Set<String> trackedQueues = wrapper.getQueueSet();
    for (String queue : trackedQueues) {
      trackedQueueInfo
          .append("<option value='Queue ")
          .append(queue)
          .append("'>")
          .append(queue)
          .append("</option>");
    }

    // tracked apps {1}
    StringBuilder trackedAppInfo = new StringBuilder();
    Set<String> trackedApps = wrapper.getTrackedAppSet();
    for (String job : trackedApps) {
      trackedAppInfo
          .append("<option value='Job ")
          .append(job)
          .append("'>")
          .append(job)
          .append("</option>");
    }

    // timeunit label {2}
    // time unit {3}
    // ajax update time {4}
    // final html
    String trackInfo =
        MessageFormat.format(
            trackTemplate,
            trackedQueueInfo.toString(),
            trackedAppInfo.toString(),
            timeunitLabel,
            "" + timeunit,
            "" + ajaxUpdateTimeMS);
    response.getWriter().println(trackInfo);

    ((Request) request).setHandled(true);
  }
  /**
   * simulate html page, show several real-runtime chart path "/simulate" use d3.js
   *
   * @param request http request
   * @param response http response
   * @throws java.io.IOException
   */
  private void printPageSimulate(
      HttpServletRequest request, HttpServletResponse response, int timeunit, String timeunitLabel)
      throws IOException {
    response.setContentType("text/html");
    response.setStatus(HttpServletResponse.SC_OK);

    // queues {0}
    Set<String> queues = wrapper.getQueueSet();
    StringBuilder queueInfo = new StringBuilder();

    int i = 0;
    for (String queue : queues) {
      queueInfo
          .append("legends[4][")
          .append(i)
          .append("] = 'queue.")
          .append(queue)
          .append(".allocated.memory';");
      queueInfo
          .append("legends[5][")
          .append(i)
          .append("] = 'queue.")
          .append(queue)
          .append(".allocated.vcores';");
      i++;
    }

    // time unit label {1}
    // time unit {2}
    // ajax update time interval {3}
    String simulateInfo =
        MessageFormat.format(
            simulateTemplate,
            queueInfo.toString(),
            timeunitLabel,
            "" + timeunit,
            "" + ajaxUpdateTimeMS);
    response.getWriter().println(simulateInfo);

    ((Request) request).setHandled(true);
  }
  public String generateRealTimeTrackingMetrics() {
    // JVM
    double jvmFreeMemoryGB, jvmMaxMemoryGB, jvmTotalMemoryGB;
    if (jvmFreeMemoryGauge == null && metrics.getGauges().containsKey("variable.jvm.free.memory")) {
      jvmFreeMemoryGauge = metrics.getGauges().get("variable.jvm.free.memory");
    }
    if (jvmMaxMemoryGauge == null && metrics.getGauges().containsKey("variable.jvm.max.memory")) {
      jvmMaxMemoryGauge = metrics.getGauges().get("variable.jvm.max.memory");
    }
    if (jvmTotalMemoryGauge == null
        && metrics.getGauges().containsKey("variable.jvm.total.memory")) {
      jvmTotalMemoryGauge = metrics.getGauges().get("variable.jvm.total.memory");
    }
    jvmFreeMemoryGB =
        jvmFreeMemoryGauge == null
            ? 0
            : Double.parseDouble(jvmFreeMemoryGauge.getValue().toString()) / 1024 / 1024 / 1024;
    jvmMaxMemoryGB =
        jvmMaxMemoryGauge == null
            ? 0
            : Double.parseDouble(jvmMaxMemoryGauge.getValue().toString()) / 1024 / 1024 / 1024;
    jvmTotalMemoryGB =
        jvmTotalMemoryGauge == null
            ? 0
            : Double.parseDouble(jvmTotalMemoryGauge.getValue().toString()) / 1024 / 1024 / 1024;

    // number of running applications/containers
    String numRunningApps, numRunningContainers;
    if (numRunningAppsGauge == null
        && metrics.getGauges().containsKey("variable.running.application")) {
      numRunningAppsGauge = metrics.getGauges().get("variable.running.application");
    }
    if (numRunningContainersGauge == null
        && metrics.getGauges().containsKey("variable.running.container")) {
      numRunningContainersGauge = metrics.getGauges().get("variable.running.container");
    }
    numRunningApps = numRunningAppsGauge == null ? "0" : numRunningAppsGauge.getValue().toString();
    numRunningContainers =
        numRunningContainersGauge == null ? "0" : numRunningContainersGauge.getValue().toString();

    // cluster available/allocate resource
    double allocatedMemoryGB, allocatedVCoresGB, availableMemoryGB, availableVCoresGB;
    if (allocatedMemoryGauge == null
        && metrics.getGauges().containsKey("variable.cluster.allocated.memory")) {
      allocatedMemoryGauge = metrics.getGauges().get("variable.cluster.allocated.memory");
    }
    if (allocatedVCoresGauge == null
        && metrics.getGauges().containsKey("variable.cluster.allocated.vcores")) {
      allocatedVCoresGauge = metrics.getGauges().get("variable.cluster.allocated.vcores");
    }
    if (availableMemoryGauge == null
        && metrics.getGauges().containsKey("variable.cluster.available.memory")) {
      availableMemoryGauge = metrics.getGauges().get("variable.cluster.available.memory");
    }
    if (availableVCoresGauge == null
        && metrics.getGauges().containsKey("variable.cluster.available.vcores")) {
      availableVCoresGauge = metrics.getGauges().get("variable.cluster.available.vcores");
    }
    allocatedMemoryGB =
        allocatedMemoryGauge == null
            ? 0
            : Double.parseDouble(allocatedMemoryGauge.getValue().toString()) / 1024;
    allocatedVCoresGB =
        allocatedVCoresGauge == null
            ? 0
            : Double.parseDouble(allocatedVCoresGauge.getValue().toString());
    availableMemoryGB =
        availableMemoryGauge == null
            ? 0
            : Double.parseDouble(availableMemoryGauge.getValue().toString()) / 1024;
    availableVCoresGB =
        availableVCoresGauge == null
            ? 0
            : Double.parseDouble(availableVCoresGauge.getValue().toString());

    // scheduler operation
    double allocateTimecost, handleTimecost;
    if (allocateTimecostHistogram == null
        && metrics.getHistograms().containsKey("sampler.scheduler.operation.allocate.timecost")) {
      allocateTimecostHistogram =
          metrics.getHistograms().get("sampler.scheduler.operation.allocate.timecost");
    }
    if (handleTimecostHistogram == null
        && metrics.getHistograms().containsKey("sampler.scheduler.operation.handle.timecost")) {
      handleTimecostHistogram =
          metrics.getHistograms().get("sampler.scheduler.operation.handle.timecost");
    }
    allocateTimecost =
        allocateTimecostHistogram == null
            ? 0.0
            : allocateTimecostHistogram.getSnapshot().getMean() / 1000000;
    handleTimecost =
        handleTimecostHistogram == null
            ? 0.0
            : handleTimecostHistogram.getSnapshot().getMean() / 1000000;
    // various handle operation
    Map<SchedulerEventType, Double> handleOperTimecostMap =
        new HashMap<SchedulerEventType, Double>();
    for (SchedulerEventType e : SchedulerEventType.values()) {
      String key = "sampler.scheduler.operation.handle." + e + ".timecost";
      if (!handleOperTimecostHistogramMap.containsKey(e)
          && metrics.getHistograms().containsKey(key)) {
        handleOperTimecostHistogramMap.put(e, metrics.getHistograms().get(key));
      }
      double timecost =
          handleOperTimecostHistogramMap.containsKey(e)
              ? handleOperTimecostHistogramMap.get(e).getSnapshot().getMean() / 1000000
              : 0;
      handleOperTimecostMap.put(e, timecost);
    }

    // allocated resource for each queue
    Map<String, Double> queueAllocatedMemoryMap = new HashMap<String, Double>();
    Map<String, Long> queueAllocatedVCoresMap = new HashMap<String, Long>();
    for (String queue : wrapper.getQueueSet()) {
      // memory
      String key = "counter.queue." + queue + ".allocated.memory";
      if (!queueAllocatedMemoryCounterMap.containsKey(queue)
          && metrics.getCounters().containsKey(key)) {
        queueAllocatedMemoryCounterMap.put(queue, metrics.getCounters().get(key));
      }
      double queueAllocatedMemoryGB =
          queueAllocatedMemoryCounterMap.containsKey(queue)
              ? queueAllocatedMemoryCounterMap.get(queue).getCount() / 1024.0
              : 0;
      queueAllocatedMemoryMap.put(queue, queueAllocatedMemoryGB);
      // vCores
      key = "counter.queue." + queue + ".allocated.cores";
      if (!queueAllocatedVCoresCounterMap.containsKey(queue)
          && metrics.getCounters().containsKey(key)) {
        queueAllocatedVCoresCounterMap.put(queue, metrics.getCounters().get(key));
      }
      long queueAllocatedVCores =
          queueAllocatedVCoresCounterMap.containsKey(queue)
              ? queueAllocatedVCoresCounterMap.get(queue).getCount()
              : 0;
      queueAllocatedVCoresMap.put(queue, queueAllocatedVCores);
    }

    // package results
    StringBuilder sb = new StringBuilder();
    sb.append("{");
    sb.append("\"time\":")
        .append(System.currentTimeMillis())
        .append(",\"jvm.free.memory\":")
        .append(jvmFreeMemoryGB)
        .append(",\"jvm.max.memory\":")
        .append(jvmMaxMemoryGB)
        .append(",\"jvm.total.memory\":")
        .append(jvmTotalMemoryGB)
        .append(",\"running.applications\":")
        .append(numRunningApps)
        .append(",\"running.containers\":")
        .append(numRunningContainers)
        .append(",\"cluster.allocated.memory\":")
        .append(allocatedMemoryGB)
        .append(",\"cluster.allocated.vcores\":")
        .append(allocatedVCoresGB)
        .append(",\"cluster.available.memory\":")
        .append(availableMemoryGB)
        .append(",\"cluster.available.vcores\":")
        .append(availableVCoresGB);

    for (String queue : wrapper.getQueueSet()) {
      sb.append(",\"queue.")
          .append(queue)
          .append(".allocated.memory\":")
          .append(queueAllocatedMemoryMap.get(queue));
      sb.append(",\"queue.")
          .append(queue)
          .append(".allocated.vcores\":")
          .append(queueAllocatedVCoresMap.get(queue));
    }
    // scheduler allocate & handle
    sb.append(",\"scheduler.allocate.timecost\":").append(allocateTimecost);
    sb.append(",\"scheduler.handle.timecost\":").append(handleTimecost);
    for (SchedulerEventType e : SchedulerEventType.values()) {
      sb.append(",\"scheduler.handle-")
          .append(e)
          .append(".timecost\":")
          .append(handleOperTimecostMap.get(e));
    }
    sb.append("}");
    return sb.toString();
  }