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 com.fasterxml.jackson.core.JsonProcessingException;
021import com.fasterxml.jackson.databind.JsonNode;
022import com.fasterxml.jackson.databind.ObjectMapper;
023import java.beans.IntrospectionException;
024import java.io.IOException;
025import java.io.PrintWriter;
026import java.io.StringWriter;
027import java.lang.management.GarbageCollectorMXBean;
028import java.lang.management.ManagementFactory;
029import java.lang.management.MemoryPoolMXBean;
030import java.lang.management.RuntimeMXBean;
031import java.util.Hashtable;
032import java.util.List;
033import java.util.Set;
034import javax.management.InstanceNotFoundException;
035import javax.management.MBeanAttributeInfo;
036import javax.management.MBeanInfo;
037import javax.management.MBeanServer;
038import javax.management.MalformedObjectNameException;
039import javax.management.ObjectName;
040import javax.management.ReflectionException;
041import javax.management.openmbean.CompositeData;
042import org.apache.yetus.audience.InterfaceAudience;
043import org.slf4j.Logger;
044import org.slf4j.LoggerFactory;
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
066 * easier access to 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    }
084    catch(Exception e) {
085      LOG.error("Unable to get value from MBean= "+ bean.toString() +
086        "for attribute=" + attribute + " " + e.getMessage());
087    }
088    return value;
089  }
090
091  /**
092   * Returns a subset of mbeans defined by qry.
093   * Modeled after DumpRegionServerMetrics#dumpMetrics.
094   * Example: String qry= "java.lang:type=Memory"
095   * @throws MalformedObjectNameException if json have bad format
096   * @throws IOException /
097   * @return String representation of json array.
098   */
099  public static String dumpBeanToString(String qry) throws MalformedObjectNameException,
100  IOException {
101    StringWriter sw = new StringWriter(1024 * 100); // Guess this size
102    try (PrintWriter writer = new PrintWriter(sw)) {
103      JSONBean dumper = new JSONBean();
104      try (JSONBean.Writer jsonBeanWriter = dumper.open(writer)) {
105        MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
106        jsonBeanWriter.write(mbeanServer,
107          new ObjectName(qry), null, false);
108      }
109    }
110    sw.close();
111    return sw.toString();
112  }
113
114  public static JsonNode mappStringToJsonNode(String jsonString)
115      throws JsonProcessingException, IOException {
116    ObjectMapper mapper = new ObjectMapper();
117    JsonNode node = mapper.readTree(jsonString);
118    return node;
119  }
120
121
122  public static JsonNode searchJson(JsonNode tree, String searchKey)
123      throws JsonProcessingException, IOException {
124    if (tree == null) {
125      return null;
126    }
127    if(tree.has(searchKey)) {
128      return tree.get(searchKey);
129    }
130    if(tree.isContainerNode()) {
131      for(JsonNode branch: tree) {
132        JsonNode branchResult = searchJson(branch, searchKey);
133        if (branchResult != null && !branchResult.isMissingNode()) {
134          return branchResult;
135        }
136      }
137    }
138    return null;
139  }
140
141  /**
142   * Method for building hashtable used for constructing ObjectName.
143   * Mapping is done with arrays indices
144   * @param keys Hashtable keys
145   * @param values Hashtable values
146   * @return Hashtable or null if arrays are empty * or have different number of elements
147   */
148  public static Hashtable<String, String> buldKeyValueTable(String[] keys, String[] values) {
149    if (keys.length != values.length) {
150      LOG.error("keys and values arrays must be same size");
151      return null;
152    }
153    if (keys.length == 0 || values.length == 0) {
154      LOG.error("keys and values arrays can not be empty;");
155      return null;
156    }
157    Hashtable<String, String> table = new Hashtable<String, String>();
158    for(int i = 0; i < keys.length; i++) {
159      table.put(keys[i], values[i]);
160    }
161    return table;
162  }
163
164  public static ObjectName buildObjectName(String pattern) throws MalformedObjectNameException {
165    return new ObjectName(pattern);
166  }
167
168  public static ObjectName buildObjectName(String domain, Hashtable<String, String> keyValueTable)
169      throws MalformedObjectNameException {
170    return new ObjectName(domain, keyValueTable);
171  }
172
173  public static Set<ObjectName> getRegistredMBeans(ObjectName name, MBeanServer mbs) {
174    return mbs.queryNames(name, null);
175  }
176
177  public static String getProcessPID() {
178    return ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
179  }
180
181  public static String getCommmand() throws MalformedObjectNameException,
182  IOException {
183    RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean();
184    return runtimeBean.getSystemProperties().get("sun.java.command");
185  }
186
187  public static List<GarbageCollectorMXBean> getGcCollectorBeans() {
188    List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans();
189    return gcBeans;
190  }
191
192  public static long getLastGcDuration(ObjectName gcCollector) {
193    long lastGcDuration = 0;
194    Object lastGcInfo = getValueFromMBean(gcCollector, "LastGcInfo");
195    if (lastGcInfo != null && lastGcInfo instanceof CompositeData) {
196      CompositeData cds = (CompositeData)lastGcInfo;
197      lastGcDuration = (long) cds.get("duration");
198    }
199    return lastGcDuration;
200  }
201
202  public static List<MemoryPoolMXBean> getMemoryPools() {
203    List<MemoryPoolMXBean> mPools = ManagementFactory.getMemoryPoolMXBeans();
204    return mPools;
205  }
206
207  public static float calcPercentage(long a, long b) {
208    if (a == 0 || b == 0) {
209      return 0;
210    }
211    return ((float)a / (float)b) *100;
212  }
213}