001/*
002 * JPPF.
003 * Copyright (C) 2005-2018 JPPF Team.
004 * http://www.jppf.org
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019package org.jppf.management.diagnostics.provider;
020
021import static org.jppf.management.diagnostics.provider.MonitoringConstants.*;
022
023import java.lang.management.*;
024
025import javax.management.*;
026
027import org.jppf.management.diagnostics.*;
028import org.jppf.utils.*;
029import org.slf4j.*;
030
031/**
032 * This class is the built-in JPPF monitoring data provider.
033 * @author Laurent Cohen
034 */
035public class DefaultMonitoringDataProvider extends MonitoringDataProvider {
036  /**
037   * Logger for this class.
038   */
039  private static final Logger log = LoggerFactory.getLogger(DefaultMonitoringDataProvider.class);
040  /**
041   * Determines whether the debug level is enabled in the log configuration, without the cost of a method call.
042   */
043  private static final boolean debugEnabled = log.isDebugEnabled();
044  /**
045   * Base path for localzation bundles.
046   */
047  private static final String I18N_BASE = "org.jppf.management.diagnostics.provider.DefaultMonitoringDataProvider";
048  /**
049   * Reference to the platform's {@link ThreadMXBean} instance.
050   */
051  private static final ThreadMXBean threadsMXBean = ManagementFactory.getThreadMXBean();
052  /**
053   * Whether the full operating system MXBean features are available or not.
054   */
055  private static boolean osMXBeanAvailable = true;
056  /**
057   * The object name of the operating system MXBean.
058   */
059  private static ObjectName osMXBeanName = null;
060  /**
061   * The platform MBean server.
062   */
063  private static final MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
064  static {
065    if (threadsMXBean.isThreadCpuTimeSupported()) {
066      if (!threadsMXBean.isThreadCpuTimeEnabled()) threadsMXBean.setThreadCpuTimeEnabled(true);
067      try {
068        Class.forName("com.sun.management.OperatingSystemMXBean");
069        osMXBeanName = new ObjectName("java.lang", "type", "OperatingSystem");
070        if (debugEnabled) log.debug("CPU load collection from OperatingSystemMXBean is enabled");
071      } catch (@SuppressWarnings("unused") final Exception e) {
072        osMXBeanAvailable = false;
073        log.info("OperatingSystemMXBean not avaialble, an approximation of the process CPU load will be computed");
074      }
075    } else if (debugEnabled) log.debug("CPU time collection is not supported - CPU load will be unavailable");
076    if (threadsMXBean.isThreadContentionMonitoringSupported()) threadsMXBean.setThreadContentionMonitoringEnabled(true);
077  }
078  /**
079   * Object that holds all references to Oshi API objects.
080   * This allows using this built-in provider on the console side without needing OShi classes in the classpath.
081   */
082  private Oshi oshi;
083
084  @Override
085  public void defineProperties() {
086    setDoubleProperty(HEAP_USAGE_RATIO, -1d);
087    setDoubleProperty(HEAP_USAGE_MB, -1d);
088    setDoubleProperty(NON_HEAP_USAGE_RATIO, -1d);
089    setDoubleProperty(NON_HEAP_USAGE_MB, -1d);
090    setBooleanProperty(DEADLOCKED, false);
091    setIntProperty(LIVE_THREADS_COUNT, -1);
092    setDoubleProperty(PROCESS_CPU_LOAD, -1d);
093    setDoubleProperty(SYSTEM_CPU_LOAD, -1d);
094    setDoubleProperty(PROCESS_RESIDENT_SET_SIZE, -1d);
095    setDoubleProperty(PROCESS_VIRTUAL_SIZE, -1d);
096    setDoubleProperty(RAM_USAGE_RATIO, -1d);
097    setDoubleProperty(RAM_USAGE_MB, -1d);
098    setDoubleProperty(SWAP_USAGE_RATIO, -1d);
099    setDoubleProperty(SWAP_USAGE_MB, -1d);
100    setDoubleProperty(CPU_TEMPERATURE, -1d);
101    setStringProperty(OS_NAME, "n/a");
102    setDoubleProperty(PROCESS_RESIDENT_SET_SIZE, -1d);
103    setDoubleProperty(PROCESS_VIRTUAL_SIZE, -1d);
104  }
105
106  @Override
107  public void init() {
108    oshi = new Oshi().init();
109  }
110
111  @Override
112  public TypedProperties getValues() {
113    final TypedProperties props = oshi.getValues();
114    final MemoryInformation memInfo = memoryInformation();
115    MemoryUsageInformation mem = memInfo.getHeapMemoryUsage();
116    props.setDouble(HEAP_USAGE_RATIO, 100d * mem.getUsedRatio());
117    props.setDouble(HEAP_USAGE_MB, (double) mem.getUsed() / MB);
118    mem = memInfo.getNonHeapMemoryUsage();
119    props.setDouble(NON_HEAP_USAGE_RATIO, 100d * mem.getUsedRatio());
120    props.setDouble(NON_HEAP_USAGE_MB, (double) mem.getUsed() / MB);
121    final long[] ids = threadsMXBean.findDeadlockedThreads();
122    props.setBoolean(DEADLOCKED, (ids != null) && (ids.length > 0));
123    props.setInt(LIVE_THREADS_COUNT, threadsMXBean.getThreadCount());
124    props.setDouble(PROCESS_CPU_LOAD, 100d * osMXBeanDoubleValue("ProcessCpuLoad"));
125    props.setDouble(SYSTEM_CPU_LOAD, 100d * osMXBeanDoubleValue("SystemCpuLoad"));
126    return props;
127  }
128
129  @Override
130  protected String getLocalizationBase() {
131    return I18N_BASE;
132  }
133
134  /**
135   * Get the memory info for the whole JVM.
136   * @return a {@link MemoryInformation} instance.
137   */
138  private static MemoryInformation memoryInformation() {
139    return new MemoryInformation();
140  }
141
142  /**
143   * Get the value of a double attribute from the OS mxbean.
144   * @param attribute the name of the attribute to get the value from.
145   * @return the attribute value as a double.
146   */
147  private static double osMXBeanDoubleValue(final String attribute) {
148    if (osMXBeanAvailable) {
149      try {
150        return ((Number) mbeanServer.getAttribute(osMXBeanName, attribute)).doubleValue();
151      } catch (final Exception e) {
152        if (debugEnabled) log.debug("error getting attribute '{}': {}", attribute, ExceptionUtils.getMessage(e));
153      }
154    }
155    return -1d;
156  }
157}