org.apache.hadoop.hdfs.server.common.MetricsLoggerTask.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.hdfs.server.common.MetricsLoggerTask.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.hadoop.hdfs.server.common;

import java.lang.management.ManagementFactory;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.impl.Log4JLogger;
import org.apache.hadoop.metrics2.util.MBeans;
import org.apache.log4j.Appender;
import org.apache.log4j.AsyncAppender;

/**
 * MetricsLoggerTask can be used as utility to dump metrics to log.
 */
public class MetricsLoggerTask implements Runnable {

    public static final Log LOG = LogFactory.getLog(MetricsLoggerTask.class);

    private static ObjectName objectName = null;

    static {
        try {
            objectName = new ObjectName("Hadoop:*");
        } catch (MalformedObjectNameException m) {
            // This should not occur in practice since we pass
            // a valid pattern to the constructor above.
        }
    }

    private Log metricsLog;
    private String nodeName;
    private short maxLogLineLength;

    public MetricsLoggerTask(Log metricsLog, String nodeName, short maxLogLineLength) {
        this.metricsLog = metricsLog;
        this.nodeName = nodeName;
        this.maxLogLineLength = maxLogLineLength;
    }

    /**
     * Write metrics to the metrics appender when invoked.
     */
    @Override
    public void run() {
        // Skip querying metrics if there are no known appenders.
        if (!metricsLog.isInfoEnabled() || !hasAppenders(metricsLog) || objectName == null) {
            return;
        }

        metricsLog.info(" >> Begin " + nodeName + " metrics dump");
        final MBeanServer server = ManagementFactory.getPlatformMBeanServer();

        // Iterate over each MBean.
        for (final ObjectName mbeanName : server.queryNames(objectName, null)) {
            try {
                MBeanInfo mBeanInfo = server.getMBeanInfo(mbeanName);
                final String mBeanNameName = MBeans.getMbeanNameName(mbeanName);
                final Set<String> attributeNames = getFilteredAttributes(mBeanInfo);

                final AttributeList attributes = server.getAttributes(mbeanName,
                        attributeNames.toArray(new String[attributeNames.size()]));

                for (Object o : attributes) {
                    final Attribute attribute = (Attribute) o;
                    final Object value = attribute.getValue();
                    final String valueStr = (value != null) ? value.toString() : "null";
                    // Truncate the value if it is too long
                    metricsLog.info(mBeanNameName + ":" + attribute.getName() + "=" + trimLine(valueStr));
                }
            } catch (Exception e) {
                metricsLog.error("Failed to get " + nodeName + " metrics for mbean " + mbeanName.toString(), e);
            }
        }
        metricsLog.info(" << End " + nodeName + " metrics dump");
    }

    private String trimLine(String valueStr) {
        if (maxLogLineLength <= 0) {
            return valueStr;
        }

        return (valueStr.length() < maxLogLineLength ? valueStr : valueStr.substring(0, maxLogLineLength) + "...");
    }

    private static boolean hasAppenders(Log logger) {
        if (!(logger instanceof Log4JLogger)) {
            // Don't bother trying to determine the presence of appenders.
            return true;
        }
        Log4JLogger log4JLogger = ((Log4JLogger) logger);
        return log4JLogger.getLogger().getAllAppenders().hasMoreElements();
    }

    /**
     * Get the list of attributes for the MBean, filtering out a few attribute
     * types.
     */
    private static Set<String> getFilteredAttributes(MBeanInfo mBeanInfo) {
        Set<String> attributeNames = new HashSet<>();
        for (MBeanAttributeInfo attributeInfo : mBeanInfo.getAttributes()) {
            if (!attributeInfo.getType().equals("javax.management.openmbean.TabularData")
                    && !attributeInfo.getType().equals("javax.management.openmbean.CompositeData")
                    && !attributeInfo.getType().equals("[Ljavax.management.openmbean.CompositeData;")) {
                attributeNames.add(attributeInfo.getName());
            }
        }
        return attributeNames;
    }

    /**
     * Make the metrics logger async and add all pre-existing appenders to the
     * async appender.
     */
    public static void makeMetricsLoggerAsync(Log metricsLog) {
        if (!(metricsLog instanceof Log4JLogger)) {
            LOG.warn("Metrics logging will not be async since " + "the logger is not log4j");
            return;
        }
        org.apache.log4j.Logger logger = ((Log4JLogger) metricsLog).getLogger();
        logger.setAdditivity(false); // Don't pollute actual logs with metrics dump

        @SuppressWarnings("unchecked")
        List<Appender> appenders = Collections.list(logger.getAllAppenders());
        // failsafe against trying to async it more than once
        if (!appenders.isEmpty() && !(appenders.get(0) instanceof AsyncAppender)) {
            AsyncAppender asyncAppender = new AsyncAppender();
            // change logger to have an async appender containing all the
            // previously configured appenders
            for (Appender appender : appenders) {
                logger.removeAppender(appender);
                asyncAppender.addAppender(appender);
            }
            logger.addAppender(asyncAppender);
        }
    }
}