org.apache.hadoop.metrics2.lib.MetricsSourceBuilder.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.metrics2.lib.MetricsSourceBuilder.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.metrics2.lib;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import static com.google.common.base.Preconditions.*;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.metrics2.MetricsCollector;
import org.apache.hadoop.metrics2.MetricsException;
import org.apache.hadoop.metrics2.MetricsInfo;
import org.apache.hadoop.metrics2.MetricsSource;
import org.apache.hadoop.metrics2.annotation.Metric;
import org.apache.hadoop.metrics2.annotation.Metrics;
import org.apache.hadoop.util.ReflectionUtils;

/**
 * Helper class to build metrics source object from annotations
 */
@InterfaceAudience.Private
public class MetricsSourceBuilder {
    private static final Log LOG = LogFactory.getLog(MetricsSourceBuilder.class);

    private final Object source;
    private final MutableMetricsFactory factory;
    private final MetricsRegistry registry;
    private MetricsInfo info;
    private boolean hasAtMetric = false;
    private boolean hasRegistry = false;

    MetricsSourceBuilder(Object source, MutableMetricsFactory factory) {
        this.source = checkNotNull(source, "source");
        this.factory = checkNotNull(factory, "mutable metrics factory");
        Class<?> cls = source.getClass();
        registry = initRegistry(source);

        for (Field field : ReflectionUtils.getDeclaredFieldsIncludingInherited(cls)) {
            add(source, field);
        }
        for (Method method : ReflectionUtils.getDeclaredMethodsIncludingInherited(cls)) {
            add(source, method);
        }
    }

    public MetricsSource build() {
        if (source instanceof MetricsSource) {
            if (hasAtMetric && !hasRegistry) {
                throw new MetricsException("Hybrid metrics: registry required.");
            }
            return (MetricsSource) source;
        } else if (!hasAtMetric) {
            throw new MetricsException("No valid @Metric annotation found.");
        }
        return new MetricsSource() {
            @Override
            public void getMetrics(MetricsCollector builder, boolean all) {
                registry.snapshot(builder.addRecord(registry.info()), all);
            }
        };
    }

    public MetricsInfo info() {
        return info;
    }

    private MetricsRegistry initRegistry(Object source) {
        Class<?> cls = source.getClass();
        MetricsRegistry r = null;
        // Get the registry if it already exists.
        for (Field field : ReflectionUtils.getDeclaredFieldsIncludingInherited(cls)) {
            if (field.getType() != MetricsRegistry.class)
                continue;
            try {
                field.setAccessible(true);
                r = (MetricsRegistry) field.get(source);
                hasRegistry = r != null;
                break;
            } catch (Exception e) {
                LOG.warn("Error accessing field " + field, e);
                continue;
            }
        }
        // Create a new registry according to annotation
        for (Annotation annotation : cls.getAnnotations()) {
            if (annotation instanceof Metrics) {
                Metrics ma = (Metrics) annotation;
                info = factory.getInfo(cls, ma);
                if (r == null) {
                    r = new MetricsRegistry(info);
                }
                r.setContext(ma.context());
            }
        }
        if (r == null)
            return new MetricsRegistry(cls.getSimpleName());
        return r;
    }

    private void add(Object source, Field field) {
        for (Annotation annotation : field.getAnnotations()) {
            if (!(annotation instanceof Metric))
                continue;
            try {
                // skip fields already set
                field.setAccessible(true);
                if (field.get(source) != null)
                    continue;
            } catch (Exception e) {
                LOG.warn("Error accessing field " + field + " annotated with" + annotation, e);
                continue;
            }
            MutableMetric mutable = factory.newForField(field, (Metric) annotation, registry);
            if (mutable != null) {
                try {
                    field.set(source, mutable);
                    hasAtMetric = true;
                } catch (Exception e) {
                    throw new MetricsException("Error setting field " + field + " annotated with " + annotation, e);
                }
            }
        }
    }

    private void add(Object source, Method method) {
        for (Annotation annotation : method.getAnnotations()) {
            if (!(annotation instanceof Metric))
                continue;
            factory.newForMethod(source, method, (Metric) annotation, registry);
            hasAtMetric = true;
        }
    }
}