Package com.errplane.api

Source Code of com.errplane.api.Errplane

package com.errplane.api;

import java.io.IOException;
import java.io.OutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.SocketException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;

import com.errplane.http.HTTPPostHelper;
import com.errplane.util.ExceptionHelper;
import com.errplane.util.Json;
import com.errplane.util.ReportHelper;

/**
* This class is the entrypoint for the Errplane library.  Use it to report
* data to Errplane.
*
* @author gdix
*
*/
public class Errplane {

  private static final String EXCEPTIONS_TIMESERIES = "exceptions";

  private static AtomicInteger reportCount = new AtomicInteger(0);

  private static AtomicInteger reportCapacity = new AtomicInteger(10000);

  private static AtomicInteger breadcrumbCapacity = new AtomicInteger(10);

  private static ConcurrentLinkedQueue<ReportHelper> reportQueue =
    new ConcurrentLinkedQueue<ReportHelper>();

  private static ConcurrentLinkedQueue<String> breadcrumbQueue =
    new ConcurrentLinkedQueue<String>();

  private static URL errplaneUrl;

  private static String urlStr = "https://w.apiv3.errplane.com/databases/";

  private static String udpHost = "udp.apiv3.errplane.com";

  private static DatagramSocket udpSocket;

  private static String app;

  private static String api;

  private static String environment;

  private static String hostname;

  private static int udpPort = 8126;

  private static String database;

  private static InetSocketAddress address;

  /**
   * This method initializes Errplane so it is ready to send data.
   * @param appKey the application key.
   * @param apiKey the api key.
   * @param env the environment (development, staging, or production).
   * @return true if initialization succeeded.
   */
  public static boolean init(String appKey, String apiKey, String env) {

    if ((appKey == null) || (apiKey == null) || (env == null)) {
      return false;
    }

    try {
      hostname = InetAddress.getLocalHost().getHostName();
    } catch (UnknownHostException e) {
      return false;
    }
    app = appKey;
    api = apiKey;
    environment = env;

    return initUrl() && initUdpConnection();
  }

  public static boolean setUrl(String url) {
    urlStr = url;
    return initUrl();
  }

  /**
   *
   * @param host
   * @return
   */
  public static boolean setUdpHostAndPort(String host, int port) {
    udpHost = host;
    udpPort = port;
    return initUdpConnection();
  }

  private static boolean initUdpConnection() {
    try {
      if (udpSocket != null) {
        udpSocket.close();
        udpSocket = null;
      }

      address = new InetSocketAddress(udpHost, udpPort);
      udpSocket = new DatagramSocket();
      udpSocket.connect(address);

    } catch (SocketException e) {
      e.printStackTrace();
      return false;
    }
    return true;
  }

  private static boolean initUrl() {
    try {
      database = app+environment;
      errplaneUrl = new URL((urlStr+database+"/points?api_key="+api));
    } catch (MalformedURLException e) {
      e.printStackTrace();
      return false;
    }
    return true;
  }

  public static int getCount() {
    return reportCount.get();
  }

  public static void setReportCapacity(int capacity) {
    reportCapacity.set(capacity);
  }

  public static void setBreadcrumbCapacity(int capacity) {
    breadcrumbCapacity.set(capacity);
  }

  /**
     The user associated with the current Errplane session.

     @param sessUser the session user to be sent with exception details.
  */
  public static synchronized void setSessionUser(String sessUser) {
  }

  /**
   * Converts the passed in bytes to a hex String
   * @param bytes the bytes to convert to hex
   * @return converted hex String
   */
  public static String getHex(byte[] bytes) {
    final char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
    char[] hexChars = new char[bytes.length * 2];
    int v;
    for ( int j = 0; j < bytes.length; j++ ) {
      v = bytes[j] & 0xFF;
      hexChars[j * 2] = hexArray[v >>> 4];
      hexChars[j * 2 + 1] = hexArray[v & 0x0F];
    }
    return new String(hexChars);
  }

  /**
     Try to clear any outstanding Errplane reports.  Returns the number of
     reports sent.
  */
  public static synchronized int flush() {
    int numRemoved = 0;
    if (!reportQueue.isEmpty() && (errplaneUrl != null)) {
      int bytesWritten = 0;
      HTTPPostHelper postHelper = new HTTPPostHelper();
      try {
        while (!reportQueue.isEmpty() && (numRemoved < 200)) {
          ReportHelper rh = reportQueue.remove();
          numRemoved++;
          String rptBody = rh.getReportBody();
          bytesWritten += rptBody.length() + 1;
          OutputStream os = postHelper.getOutputStream(errplaneUrl, bytesWritten);
          os.write(rptBody.getBytes());
          os.write('\n');
          if (!postHelper.sendPost(bytesWritten)) {
            System.out.println("Cannot send tick to server");
          }
        }
      }
      catch (Exception e) {
        e.printStackTrace();
      }

      if (numRemoved > 0) {
        reportCount.addAndGet(-numRemoved);
      }
    }
    return numRemoved;
  }

  /**
     Leave a trail indicating what might have lead to an Exception.  The last 10 are sent
     with exception details.  If pushing a breadcrumb on the queue when it already has
     10 breadcrumbs, the oldest will be popped off the back of the queue.

     @param bc the meaningful breadcrumb to push on the queue.
  */
  public static void breadcrumb(String bc) {
    breadcrumbQueue.add(bc);
  }

  /**
   * Convenience method for creating a ExceptionData object for use in an
   * Exception report.
   * @param c the controller where the Exception occurred
   * @param a the action where the Exception occurred
   * @param u the user agent that initiated the Exception
   * @return a new ExceptionData object to pass along to the Exception report
   */
  public static ExceptionData getExceptionData(String c, String a, String u) {
    return new ExceptionData(c, a, u);
  }

  private static void addReportHelper(String name, double val, String context, Map<String, String> dimensions) {
    ReportHelper rh = new ReportHelper(name);
    rh.setReportValue(val);
    rh.setContext(context);
    rh.setDimensions(dimensions);
    reportQueue.add(rh);
    reportCount.addAndGet(1);
  }

  /**
     Posts a datapoint with a default int value of 1 to the timeline[s] specified.
     @param name the name[s] of the timeline[s] to post the data point to.
     @return false if Errplane was not previously initialized or the name exceeds 249 characters.
  */
  public static boolean report(String name) {
    return report(name, 1.0, null, null);
  }

  /**
     Posts a datapoint with the value specified to the timeline[s] specified.
     @param name the name[s] of the timeline[s] to post the data point to.
     @param value the int value to post to the timeline.
     @return false if Errplane was not previously initialized or the name exceeds 249 characters.
     @deprecated use {@link #report(String,double)} instead
  */
  @Deprecated
  public static boolean report(String name, int value) {
    return report(name, value, null, null);
  }

  /**
     Posts a datapoint with the value specified to the timeline[s] specified.
     @param name the name[s] of the timeline[s] to post the data point to.
     @param value the double value to post to the timeline.
     @return false if Errplane was not previously initialized or the name exceeds 249 characters.
  */
  public static boolean report(String name, double value) {
    return report(name, value, null, null);
  }

  /**
     Posts a datapoint with a default int value of 1 and a context to the timeline[s] specified.
     @param name the name[s] of the timeline[s] to post the data point to.
     @param context the context to post along with the datapoint to the timeline.
     @return false if Errplane was not previously initialized or the name exceeds 249 characters.
  */
  public static boolean report(String name, String context) {
    return report(name, 1, context, null);
  }

  /**
     Posts a datapoint with the int value and a context to the timeline[s] specified.
     @param name the name[s] of the timeline[s] to post the data point to.
     @param value the int value to post to the timeline[s].
     @param context the context to post along with the datapoint to the timeline.
     @return false if Errplane was not previously initialized or the name exceeds 249 characters.
     @deprecated use {@link #report(String,double,String)} instead
  */
  @Deprecated
  public static boolean report(String name, int value, String context) {
    return report(name,value,context, null);
  }

  /**
     Posts a datapoint with a default int value of 1 and a context to the name[s] specified.
     @param name the name[s] of the timeline[s] to post the data point to.
     @param value the double value to post to the timeline[s].
     @param context the context to post along with the datapoint to the timeline.
     @return false if Errplane was not previously initialized or the name exceeds 249 characters.
  */
  public static boolean report(String name, double value, String context) {
    return report(name, value, context, null);
  }

  /**
     Posts a datapoint with a value, context and dimensions
  */
  public static boolean report(String name, double value, String context, Map<String, String> dimensions) {
    if ((name == null) || (name.length() >= 250)) {
      return false;
    }

    addReportHelper(name,value,context, dimensions);

    return true;
  }


  /**
   * see {@link #aggregate(String, double, String, Map)}
   *
   * @param name
   * @param value
   * @return
   */
  public static boolean aggregate(String name, double value) {
    return aggregate(name, value, null, null);
  }

  /**
   * see {@link #aggregate(String, double, String, Map)}
   *
   * @param name
   * @param value
   * @param context
   * @return
   */
  public static boolean aggregate(String name, double value, String context) {
    return aggregate(name, value, context, null);
  }

  /**
   * Similar to report, but aggregate the values (mean, count, etc.)
   *
   * @param name
   * @param value
   * @param context
   * @param dimensions
   * @return
   */
  public static boolean aggregate(String name, double value, String context, Map<String, String> dimensions) {
    return sendUdpCommon("t", name, value, context, dimensions);
  }


  /**
   * see {@link #sum(String, double, String, Map)}
   *
   * @param name
   * @param value
   * @return
   */
  public static boolean sum(String name, double value) {
    return sum(name, value, null, null);
  }

  /**
   * see {@link #sum(String, double, String, Map)}
   *
   * @param name
   * @param value
   * @param context
   * @return
   */
  public static boolean sum(String name, double value, String context) {
    return sum(name, value, context, null);
  }

  /**
   * Similar to report, but increment a counter
   *
   * @param name
   * @param value
   * @param context
   * @param dimensions
   * @return
   */
  public static boolean sum(String name, double value, String context, Map<String, String> dimensions) {
    return sendUdpCommon("c", name, value, context, dimensions);
  }

  private static boolean sendUdpCommon(String type, String name, double value, String context, Map<String, String> dimensions) {
    // example
    // {"a":"962cdc9b-15e7-4b25-9a0d-24a45cfc6bc1","d":"app4you2lovestaging","o":"t","w":[{"n":"some_aggregate","p":[{"c":"","d":null,"v":30.091186058528706}]}]}

    List<Map<String, Object>> metrics = new ArrayList<Map<String, Object>>();
    Map<String, Object> metric = new HashMap<String, Object>();
    metric.put("n", name);

    List<Map<String, Object>> points = new ArrayList<Map<String, Object>>();
    Map<String, Object> point = new HashMap<String, Object>();
    point.put("v", value);
    if (context != null)
      point.put("c", context);
    if (dimensions != null)
      point.put("d", dimensions);

    points.add(point);
    metric.put("p", points);
    metrics.add(metric);

    Map<String, Object> payload = new HashMap<String, Object>();
    payload.put("o", type);
    payload.put("d", database);
    payload.put("a", api);
    payload.put("w", metrics);

    byte[] payloadString = Json.marshalToJson(payload).getBytes();
    try {
      DatagramPacket packet = new DatagramPacket(payloadString, payloadString.length);
      udpSocket.send(packet);
    } catch (IOException e) {
      e.printStackTrace();
      return false;
    }
    return true;
  }

  /**
     Posts an exception using either the default hash method or the overridden one (if provided).
     @param ex the exception to report.
     @param exData the additional exception data to be sent with the report
     @return false if Errplane was not previously initialized.
  */
  public static boolean reportException(Exception ex, ExceptionData exData) {
    return reportException(ex, null, exData);
  }



  /**
     Posts an exception using either the default hash method or the overridden one (if provided).
     @param ex the exception to report.
     @param hash the overridden hash to use rather than the default.
     @param customData the NSString to place in the custom_data section of the exception detail
     reporting to Errplane.
     @param exData the additional exception data to be sent with the report
     @return false if Errplane was not previously initialized.
  */
  public static boolean reportException(Exception ex, String customData, ExceptionData exData) {
    if (ex == null) {
      return false;
    }

    ExceptionHelper helper = new ExceptionHelper(ex, exData, breadcrumbQueue.toArray(), customData, hostname);

    return report(EXCEPTIONS_TIMESERIES, 1.0, helper.createExceptionContext(), helper.createExceptionDimensions());
  }

  /**
   * Starts a timer using the specified name for recording duration of
   * executed code.
   * @param name the time series name.
   * @return true if Errplane reported successfully.
   */
  public static TimerTask startTimer(String name) {
    if ((name == null) || (name.length() >= 250)) {
      return null;
    }
    return (new TimerTask(name));
  }
}
TOP

Related Classes of com.errplane.api.Errplane

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.