org.apache.hama.monitor.ZKCollector.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hama.monitor.ZKCollector.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.hama.monitor;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hama.monitor.Federator.Collector;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;

/**
 * Fire a action to harvest metrics from ZooKeeper.
 */
public final class ZKCollector implements Collector {

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

    private AtomicReference<Reference> reference = new AtomicReference<Reference>();

    static final class Reference {
        final ZooKeeper zk;
        final MetricsRecord record; // name for this search
        final String path; // /path/to/metrics/parent/folder

        public Reference(ZooKeeper zk, MetricsRecord record, String path) {
            this.zk = zk;
            this.record = record;
            this.path = path;
        }
    }

    /**
     * ZKCollector havests metrics information from ZooKeeper.
     * 
     * @param zk is the target repository storing metrics.
     * @param nameOfRecord is the name of MetricsRecord.
     * @param descOfRecord is the description of MetricsRecord.
     * @param path points to the <b>parent</b> directory of stored metrics.
     */
    public ZKCollector(ZooKeeper zk, String nameOfRecord, String descOfRecord, String path) {
        Reference ref = this.reference.get();
        if (null == ref) {
            this.reference.set(new Reference(zk, new MetricsRecord(nameOfRecord, descOfRecord), path));
        }
    }

    @Override
    public MetricsRecord harvest() throws Exception {
        final String path = this.reference.get().path;
        final ZooKeeper zk = this.reference.get().zk;
        LOG.debug("Searching " + path + " in zookeeper.");
        Stat stat = zk.exists(path, false);
        if (null == stat)
            return null; // no need to collect data.
        List<String> children = zk.getChildren(path, false);
        if (LOG.isDebugEnabled()) {
            LOG.debug("Leaves size is " + children.size() + " total znodes in list: " + children);
        }

        // TODO: metrics record contains multiple metrics (1 to many)
        // data is stored under zk e.g. /path/to/metrics/jvm/...
        // within jvm folder metrics is stored in a form of name, value pair
        final MetricsRecord record = reference.get().record;
        if (null != children) {
            for (String child : children) {
                LOG.info("metrics -> " + child);
                // <metricsName_d> indicates data type is double
                String dataType = suffix(child);
                byte[] dataInBytes = zk.getData(path + "/" + child, false, stat);
                if (LOG.isDebugEnabled()) {
                    LOG.debug("Data length (in byte): " + dataInBytes.length);
                }
                DataInputStream input = null;
                try {
                    String name = removeSuffix(child);
                    input = new DataInputStream(new ByteArrayInputStream(dataInBytes));
                    if ("d".equals(dataType)) {
                        double dv = input.readDouble();
                        LOG.info("metrics " + name + " value:" + dv);
                        record.add(new Metric<Double>(name, dv));
                    } else if ("f".equals(dataType)) {
                        float fv = input.readFloat();
                        LOG.info("metrics " + name + " value:" + fv);
                        record.add(new Metric<Float>(name, fv));
                    } else if ("i".equals(dataType)) {
                        int iv = input.readInt();
                        LOG.info("metrics " + name + " value:" + iv);
                        record.add(new Metric<Integer>(name, iv));
                    } else if ("l".equals(dataType)) {
                        long lv = input.readLong();
                        LOG.info("metrics " + name + " value:" + lv);
                        record.add(new Metric<Long>(name, lv));
                    } else if ("b".equals(dataType)) {
                        LOG.info("metrics" + name + " value:" + Arrays.toString(dataInBytes));
                        record.add(new Metric<byte[]>(name, dataInBytes));
                    } else {
                        LOG.warn("Unkown data type for metrics name: " + child);
                    }
                } finally {
                    input.close();
                }
            }
        }
        return record;
    }

    private static String removeSuffix(String path) {
        return path.substring(0, path.length() - 2);
    }

    private static String suffix(String path) {
        if (!"_".equals(path.substring(path.length() - 2, path.length() - 1))) {
            return "?";
        }
        return path.substring(path.length() - 1, path.length());
    }

}