org.apache.ambari.server.controller.metrics.timeline.MetricsRequestHelper.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.ambari.server.controller.metrics.timeline.MetricsRequestHelper.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
 * <p/>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p/>
 * 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.ambari.server.controller.metrics.timeline;

import org.apache.ambari.server.controller.internal.URLStreamProvider;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.hadoop.metrics2.sink.timeline.Precision;
import org.apache.http.NameValuePair;
import org.apache.hadoop.metrics2.sink.timeline.TimelineMetric;
import org.apache.hadoop.metrics2.sink.timeline.TimelineMetrics;
import org.apache.http.client.utils.URIBuilder;
import org.codehaus.jackson.map.AnnotationIntrospector;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.ObjectReader;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.codehaus.jackson.xc.JaxbAnnotationIntrospector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ws.rs.HttpMethod;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

/**
 * Helper class to call AMS backend that is utilized by @AMSPropertyProvider
 * and @AMSReportPropertyProvider as well as @TimelineMetricCacheEntryFactory
 */
public class MetricsRequestHelper {
    private final static Logger LOG = LoggerFactory.getLogger(MetricsRequestHelper.class);
    private final static ObjectMapper mapper;
    private final static ObjectReader timelineObjectReader;
    private final URLStreamProvider streamProvider;

    static {
        mapper = new ObjectMapper();
        AnnotationIntrospector introspector = new JaxbAnnotationIntrospector();
        mapper.setAnnotationIntrospector(introspector);
        //noinspection deprecation
        mapper.getSerializationConfig().setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
        timelineObjectReader = mapper.reader(TimelineMetrics.class);
    }

    public MetricsRequestHelper(URLStreamProvider streamProvider) {
        this.streamProvider = streamProvider;
    }

    public TimelineMetrics fetchTimelineMetrics(URIBuilder uriBuilder, Long startTime, Long endTime)
            throws IOException {
        LOG.debug("Metrics request url = " + uriBuilder.toString());
        BufferedReader reader = null;
        TimelineMetrics timelineMetrics = null;
        try {

            HttpURLConnection connection = streamProvider.processURL(uriBuilder.toString(), HttpMethod.GET,
                    (String) null, Collections.<String, List<String>>emptyMap());

            if (!checkConnectionForPrecisionException(connection)) {
                //Try one more time with higher precision
                String higherPrecision = getHigherPrecision(uriBuilder, startTime, endTime);
                if (higherPrecision != null) {
                    LOG.debug("Requesting metrics with higher precision : " + higherPrecision);
                    uriBuilder.setParameter("precision", higherPrecision);
                    String newSpec = uriBuilder.toString();
                    connection = streamProvider.processURL(newSpec, HttpMethod.GET, (String) null,
                            Collections.<String, List<String>>emptyMap());
                    if (!checkConnectionForPrecisionException(connection)) {
                        throw new IOException(
                                "Encountered Precision exception : Higher precision request also failed.");
                    }
                } else {
                    throw new IOException("Encountered Precision exception : Unable to request higher precision");
                }
            }

            InputStream inputStream = connection.getInputStream();
            reader = new BufferedReader(new InputStreamReader(inputStream));
            timelineMetrics = timelineObjectReader.readValue(reader);

            if (LOG.isTraceEnabled()) {
                for (TimelineMetric metric : timelineMetrics.getMetrics()) {
                    LOG.trace("metric: " + metric.getMetricName() + ", size = " + metric.getMetricValues().size()
                            + ", host = " + metric.getHostName() + ", app = " + metric.getAppId() + ", instance = "
                            + metric.getInstanceId() + ", time = " + metric.getTimestamp() + ", startTime = "
                            + new Date(metric.getStartTime()));
                }
            }
        } catch (IOException io) {
            String errorMsg = "Error getting timeline metrics : " + io.getMessage();
            LOG.error(errorMsg);
            if (LOG.isDebugEnabled()) {
                LOG.debug(errorMsg, io);
            }

            if (io instanceof SocketTimeoutException) {
                errorMsg += " Can not connect to collector, socket error.";
                LOG.error(errorMsg);
                throw io;
            }
        } catch (URISyntaxException e) {
            String errorMsg = "Error getting timeline metrics : " + e.getMessage();
            LOG.error(errorMsg);
            if (LOG.isDebugEnabled()) {
                LOG.debug(errorMsg, e);
            }
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    if (LOG.isWarnEnabled()) {
                        if (LOG.isDebugEnabled()) {
                            LOG.warn("Unable to close http input stream : spec=" + uriBuilder.toString(), e);
                        } else {
                            LOG.warn("Unable to close http input stream : spec=" + uriBuilder.toString());
                        }
                    }
                }
            }
        }
        return timelineMetrics;
    }

    private boolean checkConnectionForPrecisionException(HttpURLConnection connection)
            throws IOException, URISyntaxException {

        if (connection != null && connection.getResponseCode() == HttpStatus.SC_BAD_REQUEST) {
            InputStream errorStream = connection.getErrorStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(errorStream));
            String errorMessage = reader.readLine();
            if (errorMessage != null && errorMessage.contains("PrecisionLimitExceededException")) {
                LOG.debug("Encountered Precision exception while requesting metrics : " + errorMessage);
                return false;
            } else {
                throw new IOException(errorMessage);
            }
        }
        return true;
    }

    private String getHigherPrecision(URIBuilder uriBuilder, Long startTime, Long endTime)
            throws URISyntaxException {

        Precision currentPrecision = null;
        List<NameValuePair> queryParams = uriBuilder.getQueryParams();
        for (Iterator<NameValuePair> it = queryParams.iterator(); it.hasNext();) {
            NameValuePair nvp = it.next();
            if (nvp.getName().equals("precision")) {
                currentPrecision = Precision.getPrecision(nvp.getValue());
            }
        }
        if (currentPrecision == null && startTime != null && endTime != null) {
            currentPrecision = Precision.getPrecision(startTime, endTime);
        }
        Precision higherPrecision = Precision.getHigherPrecision(currentPrecision);

        return (higherPrecision != null) ? higherPrecision.toString() : null;
    }

}