content: /**
   * Licensed 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.aurora.common.stats;
  
  import java.lang.management.ClassLoadingMXBean;
  import java.lang.management.GarbageCollectorMXBean;
  import java.lang.management.ManagementFactory;
  import java.lang.management.MemoryMXBean;
  import java.lang.management.OperatingSystemMXBean;
  import java.lang.management.RuntimeMXBean;
  import java.lang.management.ThreadMXBean;
  import java.util.Map;
  
  import com.google.common.collect.ImmutableList;
  import com.google.common.collect.Iterables;
  
  import org.apache.aurora.common.quantity.Amount;
  import org.apache.aurora.common.quantity.Data;
  import org.apache.aurora.common.quantity.Time;
  
  /**
   * Convenience class to export statistics about the JVM.
   */
  public class JvmStats {
  
    private static final long BYTES_PER_MB = Amount.of(1L, Data.MB).as(Data.BYTES);
    private static final double SECS_PER_NANO =
        ((double) 1) / Amount.of(1L, Time.SECONDS).as(Time.NANOSECONDS);
  
    private JvmStats() {
      // Utility class.
    }
  
    /**
     * Exports stats related to the JVM and runtime environment.
     */
    public static void export() {
      final OperatingSystemMXBean osMbean = ManagementFactory.getOperatingSystemMXBean();
      if (osMbean instanceof com.sun.management.OperatingSystemMXBean) {
        final com.sun.management.OperatingSystemMXBean sunOsMbean =
            (com.sun.management.OperatingSystemMXBean) osMbean;
  
        Stats.exportAll(
            ImmutableList.<Stat<? extends Number>>builder()
            .add(new StatImpl<Long>("system_free_physical_memory_mb") {
              @Override public Long read() {
                return sunOsMbean.getFreePhysicalMemorySize() / BYTES_PER_MB;
              }
            })
            .add(new StatImpl<Long>("system_free_swap_mb") {
              @Override public Long read() {
                return sunOsMbean.getFreeSwapSpaceSize() / BYTES_PER_MB;
              }
            })
            .add(
            Rate.of(
                new StatImpl<Long>("process_cpu_time_nanos") {
                  @Override public Long read() {
                    return sunOsMbean.getProcessCpuTime();
                  }
                }).withName("process_cpu_cores_utilized").withScaleFactor(SECS_PER_NANO).build())
            .build());
      }
      if (osMbean instanceof com.sun.management.UnixOperatingSystemMXBean) {
        final com.sun.management.UnixOperatingSystemMXBean unixOsMbean =
            (com.sun.management.UnixOperatingSystemMXBean) osMbean;
  
        Stats.exportAll(ImmutableList.<Stat<? extends Number>>builder()
            .add(new StatImpl<Long>("process_max_fd_count") {
              @Override public Long read() { return unixOsMbean.getMaxFileDescriptorCount(); }
            }).add(new StatImpl<Long>("process_open_fd_count") {
              @Override public Long read() { return unixOsMbean.getOpenFileDescriptorCount(); }
            }).build());
      }
  
      final Runtime runtime = Runtime.getRuntime();
      final ClassLoadingMXBean classLoadingBean = ManagementFactory.getClassLoadingMXBean();
      final MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
      final ThreadMXBean threads = ManagementFactory.getThreadMXBean();
      final RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
  
      Stats.exportAll(ImmutableList.<Stat<? extends Number>>builder()
        .add(new StatImpl<Long>("jvm_time_ms") {
          @Override public Long read() { return System.currentTimeMillis(); }
        })
        .add(new StatImpl<Integer>("jvm_available_processors") {
          @Override public Integer read() { return runtime.availableProcessors(); }
        })
        .add(new StatImpl<Long>("jvm_memory_free_mb") {
          @Override public Long read() { return runtime.freeMemory() / BYTES_PER_MB; }
        })
        .add(new StatImpl<Long>("jvm_memory_max_mb") {
          @Override public Long read() { return runtime.maxMemory() / BYTES_PER_MB; }
        })
        .add(new StatImpl<Long>("jvm_memory_mb_total") {
          @Override public Long read() { return runtime.totalMemory() / BYTES_PER_MB; }
        })
        .add(new StatImpl<Integer>("jvm_class_loaded_count") {
          @Override public Integer read() { return classLoadingBean.getLoadedClassCount(); }
        })
        .add(new StatImpl<Long>("jvm_class_total_loaded_count") {
          @Override public Long read() { return classLoadingBean.getTotalLoadedClassCount(); }
        })
        .add(new StatImpl<Long>("jvm_class_unloaded_count") {
          @Override public Long read() { return classLoadingBean.getUnloadedClassCount(); }
        })
        .add(new StatImpl<Long>("jvm_gc_collection_time_ms") {
          @Override public Long read() {
            long collectionTimeMs = 0;
            for (GarbageCollectorMXBean bean : ManagementFactory.getGarbageCollectorMXBeans()) {
              collectionTimeMs += bean.getCollectionTime();
            }
            return collectionTimeMs;
          }
        })
        .add(new StatImpl<Long>("jvm_gc_collection_count") {
          @Override public Long read() {
            long collections = 0;
            for (GarbageCollectorMXBean bean : ManagementFactory.getGarbageCollectorMXBeans()) {
              collections += bean.getCollectionCount();
            }
            return collections;
          }
        })
        .add(new StatImpl<Long>("jvm_memory_heap_mb_used") {
          @Override public Long read() {
            return memoryBean.getHeapMemoryUsage().getUsed() / BYTES_PER_MB;
          }
        })
        .add(new StatImpl<Long>("jvm_memory_heap_mb_committed") {
          @Override public Long read() {
            return memoryBean.getHeapMemoryUsage().getCommitted() / BYTES_PER_MB;
          }
        })
        .add(new StatImpl<Long>("jvm_memory_heap_mb_max") {
          @Override public Long read() {
            return memoryBean.getHeapMemoryUsage().getMax() / BYTES_PER_MB;
          }
        })
        .add(new StatImpl<Long>("jvm_memory_non_heap_mb_used") {
          @Override public Long read() {
            return memoryBean.getNonHeapMemoryUsage().getUsed() / BYTES_PER_MB;
          }
        })
        .add(new StatImpl<Long>("jvm_memory_non_heap_mb_committed") {
          @Override public Long read() {
            return memoryBean.getNonHeapMemoryUsage().getCommitted() / BYTES_PER_MB;
          }
        })
        .add(new StatImpl<Long>("jvm_memory_non_heap_mb_max") {
          @Override public Long read() {
            return memoryBean.getNonHeapMemoryUsage().getMax() / BYTES_PER_MB;
          }
        })
        .add(new StatImpl<Long>("jvm_uptime_secs") {
          @Override public Long read() { return runtimeMXBean.getUptime() / 1000; }
        })
        .add(new StatImpl<Double>("system_load_avg") {
          @Override public Double read() { return osMbean.getSystemLoadAverage(); }
        })
        .add(new StatImpl<Integer>("jvm_threads_peak") {
          @Override public Integer read() { return threads.getPeakThreadCount(); }
        })
        .add(new StatImpl<Long>("jvm_threads_started") {
          @Override public Long read() { return threads.getTotalStartedThreadCount(); }
        })
        .add(new StatImpl<Integer>("jvm_threads_daemon") {
          @Override public Integer read() { return threads.getDaemonThreadCount(); }
        })
        .add(new StatImpl<Integer>("jvm_threads_active") {
          @Override public Integer read() { return threads.getThreadCount(); }
        })
        .build());
  
      // Export per memory pool gc time and cycle count like Ostrich
      // This is based on code in Bridcage: https://cgit.twitter.biz/birdcage/tree/ \
      // ostrich/src/main/scala/com/twitter/ostrich/stats/StatsCollection.scala
      Stats.exportAll(Iterables.transform(ManagementFactory.getGarbageCollectorMXBeans(),
          gcMXBean -> new StatImpl<Long>(
              "jvm_gc_" + Stats.normalizeName(gcMXBean.getName()) + "_collection_count") {
            @Override public Long read() {
              return gcMXBean.getCollectionCount();
            }
          }
      ));
  
      Stats.exportAll(Iterables.transform(ManagementFactory.getGarbageCollectorMXBeans(),
          gcMXBean -> new StatImpl<Long>(
              "jvm_gc_" + Stats.normalizeName(gcMXBean.getName()) + "_collection_time_ms") {
            @Override public Long read() {
              return gcMXBean.getCollectionTime();
            }
          }
      ));
  
      Stats.exportString(
          new StatImpl<String>("jvm_input_arguments") {
            @Override public String read() {
              return runtimeMXBean.getInputArguments().toString();
            }
          }
      );
  
      for (final String property : System.getProperties().stringPropertyNames()) {
        Stats.exportString(
            new StatImpl<String>("jvm_prop_" + Stats.normalizeName(property)) {
              @Override public String read() { return System.getProperty(property); }
            });
      }
  
      for (final Map.Entry<String, String> environmentVariable : System.getenv().entrySet()) {
        Stats.exportString(
            new StatImpl<String>("system_env_" + Stats.normalizeName(environmentVariable.getKey())) {
              @Override public String read() { return environmentVariable.getValue(); }
            });
      }
    }
  }
  