| /* |
| * 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.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; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| /** |
| * Helper class to build metrics source object from annotations |
| */ |
| @InterfaceAudience.Private |
| public class MetricsSourceBuilder { |
| private static final Logger LOG = |
| LoggerFactory.getLogger(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; |
| } |
| } |
| } |