001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  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 */
018package org.apache.hadoop.hbase.util;
019
020import java.beans.IntrospectionException;
021import java.io.IOException;
022import java.io.PrintWriter;
023import java.io.StringWriter;
024import java.lang.management.GarbageCollectorMXBean;
025import java.lang.management.ManagementFactory;
026import java.lang.management.MemoryPoolMXBean;
027import java.lang.management.RuntimeMXBean;
028import java.util.Hashtable;
029import java.util.List;
030import java.util.Set;
031import javax.management.InstanceNotFoundException;
032import javax.management.MBeanAttributeInfo;
033import javax.management.MBeanInfo;
034import javax.management.MBeanServer;
035import javax.management.MalformedObjectNameException;
036import javax.management.ObjectName;
037import javax.management.ReflectionException;
038import javax.management.openmbean.CompositeData;
039import org.apache.yetus.audience.InterfaceAudience;
040import org.slf4j.Logger;
041import org.slf4j.LoggerFactory;
042
043import org.apache.hbase.thirdparty.com.google.common.base.Splitter;
044import org.apache.hbase.thirdparty.com.google.common.collect.Iterables;
045
046@InterfaceAudience.Private
047public final class JSONMetricUtil {
048
049  private static final Logger LOG = LoggerFactory.getLogger(JSONMetricUtil.class);
050
051  private static MBeanServer mbServer = ManagementFactory.getPlatformMBeanServer();
052  // MBeans ObjectName domain names
053  public static final String JAVA_LANG_DOMAIN = "java.lang";
054  public static final String JAVA_NIO_DOMAIN = "java.nio";
055  public static final String SUN_MGMT_DOMAIN = "com.sun.management";
056  public static final String HADOOP_DOMAIN = "Hadoop";
057
058  // MBeans ObjectName properties key names
059  public static final String TYPE_KEY = "type";
060  public static final String NAME_KEY = "name";
061  public static final String SERVICE_KEY = "service";
062  public static final String SUBSYSTEM_KEY = "sub";
063
064  /**
065   * Utility for getting metric values. Collection of static methods intended for easier access to
066   * metric values.
067   */
068  private JSONMetricUtil() {
069    // Not to be called
070  }
071
072  public static MBeanAttributeInfo[] getMBeanAttributeInfo(ObjectName bean)
073    throws IntrospectionException, InstanceNotFoundException, ReflectionException,
074    IntrospectionException, javax.management.IntrospectionException {
075    MBeanInfo mbinfo = mbServer.getMBeanInfo(bean);
076    return mbinfo.getAttributes();
077  }
078
079  public static Object getValueFromMBean(ObjectName bean, String attribute) {
080    Object value = null;
081    try {
082      value = mbServer.getAttribute(bean, attribute);
083    } catch (Exception e) {
084      LOG.error("Unable to get value from MBean= " + bean.toString() + "for attribute=" + attribute
085        + " " + e.getMessage());
086    }
087    return value;
088  }
089
090  /**
091   * Returns a subset of mbeans defined by qry. Modeled after DumpRegionServerMetrics#dumpMetrics.
092   * Example: String qry= "java.lang:type=Memory"
093   * @throws MalformedObjectNameException if json have bad format
094   * @throws IOException                  /
095   * @return String representation of json array.
096   */
097  public static String dumpBeanToString(String qry)
098    throws MalformedObjectNameException, IOException {
099    StringWriter sw = new StringWriter(1024 * 100); // Guess this size
100    try (PrintWriter writer = new PrintWriter(sw)) {
101      JSONBean dumper = new JSONBean();
102      try (JSONBean.Writer jsonBeanWriter = dumper.open(writer)) {
103        MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
104        jsonBeanWriter.write(mbeanServer, new ObjectName(qry), null, false);
105      }
106    }
107    sw.close();
108    return sw.toString();
109  }
110
111  /**
112   * Method for building map used for constructing ObjectName. Mapping is done with arrays indices
113   * @param keys   Map keys
114   * @param values Map values
115   * @return Map or null if arrays are empty or have different number of elements
116   */
117  @SuppressWarnings("JdkObsolete") // javax requires hashtable param for ObjectName constructor
118  public static Hashtable<String, String> buldKeyValueTable(String[] keys, String[] values) {
119    if (keys.length != values.length) {
120      LOG.error("keys and values arrays must be same size");
121      return null;
122    }
123    if (keys.length == 0 || values.length == 0) {
124      LOG.error("keys and values arrays can not be empty;");
125      return null;
126    }
127    Hashtable<String, String> table = new Hashtable<>();
128    for (int i = 0; i < keys.length; i++) {
129      table.put(keys[i], values[i]);
130    }
131    return table;
132  }
133
134  public static ObjectName buildObjectName(String pattern) throws MalformedObjectNameException {
135    return new ObjectName(pattern);
136  }
137
138  public static ObjectName buildObjectName(String domain, Hashtable<String, String> keyValueTable)
139    throws MalformedObjectNameException {
140    return new ObjectName(domain, keyValueTable);
141  }
142
143  public static Set<ObjectName> getRegistredMBeans(ObjectName name, MBeanServer mbs) {
144    return mbs.queryNames(name, null);
145  }
146
147  public static String getProcessPID() {
148    return Iterables.get(Splitter.on('@').split(ManagementFactory.getRuntimeMXBean().getName()), 0);
149  }
150
151  public static String getCommmand() throws MalformedObjectNameException, IOException {
152    RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean();
153    return runtimeBean.getSystemProperties().get("sun.java.command");
154  }
155
156  public static List<GarbageCollectorMXBean> getGcCollectorBeans() {
157    List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans();
158    return gcBeans;
159  }
160
161  public static long getLastGcDuration(ObjectName gcCollector) {
162    long lastGcDuration = 0;
163    Object lastGcInfo = getValueFromMBean(gcCollector, "LastGcInfo");
164    if (lastGcInfo != null && lastGcInfo instanceof CompositeData) {
165      CompositeData cds = (CompositeData) lastGcInfo;
166      lastGcDuration = (long) cds.get("duration");
167    }
168    return lastGcDuration;
169  }
170
171  public static List<MemoryPoolMXBean> getMemoryPools() {
172    List<MemoryPoolMXBean> mPools = ManagementFactory.getMemoryPoolMXBeans();
173    return mPools;
174  }
175
176  public static float calcPercentage(long a, long b) {
177    if (a == 0 || b == 0) {
178      return 0;
179    }
180    return ((float) a / (float) b) * 100;
181  }
182}