Package com.googlecode.jmxtrans.model.output

Source Code of com.googlecode.jmxtrans.model.output.LibratoWriter

package com.googlecode.jmxtrans.model.output;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.Base64Variants;
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.google.common.base.Charsets;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
import com.googlecode.jmxtrans.model.Query;
import com.googlecode.jmxtrans.model.Result;
import com.googlecode.jmxtrans.model.Server;
import com.googlecode.jmxtrans.model.ValidationException;
import com.googlecode.jmxtrans.model.naming.KeyUtils;
import com.googlecode.jmxtrans.model.naming.StringUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.NullOutputStream;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
* This writer is a port of the LibratoWriter from the embedded-jmxtrans
* project.
* <p/>
* <a href="https://metrics.librato.com//">Librato Metrics</a>
* <p/>
* This implementation uses <a href="http://dev.librato.com/v1/post/metrics">
* POST {@code /v1/metrics}</a> HTTP API.
* <p/>
* Settings:
* <ul>
* <li>"{@code url}": Librato server URL. Optional, default value:
* {@value #DEFAULT_LIBRATO_API_URL}.</li>
* <li>"{@code username}": Librato username. Mandatory</li>
* <li>"{@code token}": Librato token. Mandatory</li>
* <li>"{@code libratoApiTimeoutInMillis}": read timeout of the calls to Librato
* HTTP API. Optional, default value: 1000.</li>
* </ul>
*
* @author <a href="mailto:cleclerc@cloudbees.com">Cyrille Le Clerc</a>
*/
public class LibratoWriter extends BaseOutputWriter {

  public final static String SETTING_URL = "url";
  public final static String SETTING_USERNAME = "username";
  public final static String SETTING_TOKEN = "token";
  public final static String SETTING_PROXY_HOST = "proxyHost";
  public final static String SETTING_PROXY_PORT = "proxyPort";
  public static final String DEFAULT_LIBRATO_API_URL = "https://metrics-api.librato.com/v1/metrics";
  public static final String SETTING_LIBRATO_API_TIMEOUT_IN_MILLIS = "libratoApiTimeoutInMillis";

  private final org.slf4j.Logger logger = LoggerFactory.getLogger(getClass());

  private final JsonFactory jsonFactory = new JsonFactory();
  /**
   * Librato HTTP API URL
   */
  private final URL url;
  private final int libratoApiTimeoutInMillis;
  /**
   * Librato HTTP API authentication username
   */
  private final String username;
  private final String token;
  private final String basicAuthentication;
  /**
   * Optional proxy for the http API calls
   */
  private final String proxyHost;
  private final Integer proxyPort;
  private Proxy proxy;

  @JsonCreator
  public LibratoWriter(
      @JsonProperty("typeNames") ImmutableList<String> typeNames,
      @JsonProperty("debug") Boolean debugEnabled,
      @JsonProperty("url") URL url,
      @JsonProperty("libratoApiTimeoutInMillis") Integer libratoApiTimeoutInMillis,
      @JsonProperty("username") String username,
      @JsonProperty("token") String token,
      @JsonProperty("proxyHost") String proxyHost,
      @JsonProperty("proxyPort") Integer proxyPort,
      @JsonProperty("settings") Map<String, Object> settings) throws MalformedURLException {
    super(typeNames, debugEnabled, settings);
    this.url = MoreObjects.firstNonNull(
        url,
        new URL(MoreObjects.firstNonNull(
            (String) this.getSettings().get(SETTING_URL),
            DEFAULT_LIBRATO_API_URL)));
    this.libratoApiTimeoutInMillis = MoreObjects.firstNonNull(
        libratoApiTimeoutInMillis,
        Settings.getIntSetting(getSettings(), SETTING_LIBRATO_API_TIMEOUT_IN_MILLIS, 1000));
    this.username = MoreObjects.firstNonNull(
        username,
        (String) getSettings().get(SETTING_USERNAME));
    this.token = MoreObjects.firstNonNull(
        token,
        (String) getSettings().get(SETTING_TOKEN));
    this.basicAuthentication = Base64Variants
        .getDefaultVariant()
        .encode((this.username + ":" + this.token).getBytes(Charsets.US_ASCII));
    this.proxyHost = proxyHost != null ? proxyHost : (String) getSettings().get(SETTING_PROXY_HOST);
    this.proxyPort = proxyPort != null ? proxyPort : Settings.getIntegerSetting(getSettings(), SETTING_PROXY_PORT, null);
    if (this.proxyHost != null && this.proxyPort != null) {
      this.proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(this.proxyHost, this.proxyPort));
    } else {
      this.proxy = null;
    }
  }

  public void validateSetup(Server server, Query query) throws ValidationException {
    logger.info("Start Librato writer connected to '{}', proxy {} with username '{}' ...", url, proxy, username);
  }

  public void doWrite(Server server, Query query, ImmutableList<Result> results) throws Exception {
    logger.debug("Export to '{}', proxy {} metrics {}", url, proxy, query);
    writeToLibrato(server, query, results);
  }

  private void serialize(Server server, Query query, List<Result> results, OutputStream outputStream) throws IOException {
    JsonGenerator g = jsonFactory.createJsonGenerator(outputStream, JsonEncoding.UTF8);
    g.writeStartObject();
    g.writeArrayFieldStart("counters");
    g.writeEndArray();

    String source = getSource(server);

    g.writeArrayFieldStart("gauges");
    List<String> typeNames = getTypeNames();
    for (Result result : results) {
      Map<String, Object> resultValues = result.getValues();
      if (resultValues != null) {
        for (Map.Entry<String, Object> values : resultValues.entrySet()) {
          if (NumberUtils.isNumeric(values.getValue())) {
            g.writeStartObject();
            g.writeStringField("name", KeyUtils.getKeyStringWithDottedKeys(query, result, values, typeNames));
            if (source != null && !source.isEmpty()) {
              g.writeStringField("source", source);
            }
            g.writeNumberField("measure_time", TimeUnit.SECONDS.convert(result.getEpoch(), TimeUnit.MILLISECONDS));
            Object value = values.getValue();
            if (value instanceof Integer) {
              g.writeNumberField("value", (Integer) value);
            } else if (value instanceof Long) {
              g.writeNumberField("value", (Long) value);
            } else if (value instanceof Float) {
              g.writeNumberField("value", (Float) value);
            } else if (value instanceof Double) {
              g.writeNumberField("value", (Double) value);
            }
            g.writeEndObject();
          }
        }
      }
    }
    g.writeEndArray();
    g.writeEndObject();
    g.flush();
    g.close();

  }

  private void writeToLibrato(Server server, Query query, List<Result> results) {
    HttpURLConnection urlConnection = null;
    try {
      if (proxy == null) {
        urlConnection = (HttpURLConnection) url.openConnection();
      } else {
        urlConnection = (HttpURLConnection) url.openConnection(proxy);
      }
      urlConnection.setRequestMethod("POST");
      urlConnection.setDoInput(true);
      urlConnection.setDoOutput(true);
      urlConnection.setReadTimeout(libratoApiTimeoutInMillis);
      urlConnection.setRequestProperty("content-type", "application/json; charset=utf-8");
      urlConnection.setRequestProperty("Authorization", "Basic " + basicAuthentication);

      serialize(server, query, results, urlConnection.getOutputStream());
      int responseCode = urlConnection.getResponseCode();
      if (responseCode != 200) {
        logger.warn("Failure {}:'{}' to send result to Librato server '{}' with proxy {}, username {}", responseCode, urlConnection.getResponseMessage(), url, proxy, username);
      }
      if (logger.isTraceEnabled()) {
        IOUtils.copy(urlConnection.getInputStream(), System.out);
      }
    } catch (Exception e) {
      logger.warn("Failure to send result to Librato server '{}' with proxy {}, username {}", url, proxy, username, e);
    } finally {
      if (urlConnection != null) {
        try {
          InputStream in = urlConnection.getInputStream();
          IOUtils.copy(in, NullOutputStream.NULL_OUTPUT_STREAM);
          IOUtils.closeQuietly(in);
          InputStream err = urlConnection.getErrorStream();
          if (err != null) {
            IOUtils.copy(err, NullOutputStream.NULL_OUTPUT_STREAM);
            IOUtils.closeQuietly(err);
          }
        } catch (IOException e) {
          logger.warn("Exception flushing http connection", e);
        }
      }

    }
  }

  private String getSource(Server server) {
    if (server.getAlias() != null) {
      return server.getAlias();
    } else {
      return StringUtils.cleanupStr(server.getHost());
    }
  }

  public URL getUrl() {
    return url;
  }

  public int getLibratoApiTimeoutInMillis() {
    return libratoApiTimeoutInMillis;
  }

  public String getUsername() {
    return username;
  }

  public String getToken() {
    return token;
  }

  public String getProxyHost() {
    return proxyHost;
  }

  public Integer getProxyPort() {
    return proxyPort;
  }
}
TOP

Related Classes of com.googlecode.jmxtrans.model.output.LibratoWriter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.