org.jmxtrans.embedded.output.CopperEggWriter.java Source code

Java tutorial

Introduction

Here is the source code for org.jmxtrans.embedded.output.CopperEggWriter.java

Source

/*
 * Copyright (c) 2010-2013 the original author or authors
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */
package org.jmxtrans.embedded.output;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringWriter;
import java.io.StringReader;
import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.io.File;
import java.net.*;
import java.nio.charset.Charset;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Collections;
import java.util.Comparator;

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.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.MappingJsonFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.databind.JsonMappingException;

import org.jmxtrans.embedded.EmbeddedJmxTransException;
import org.jmxtrans.embedded.QueryResult;
import org.jmxtrans.embedded.util.io.IoUtils2;
import org.jmxtrans.embedded.util.StringUtils2;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import java.lang.management.ManagementFactory;

/**
 * <a href="https://copperegg.com/">CopperEgg Metrics</a> implementation of the {@linkplain org.jmxtrans.embedded.output.OutputWriter}.
 *
 * This implementation uses v2 of the <a href="http://dev.copperegg.com/">CopperEgg API</a>
 *
 * Settings:
 * <ul>
 * <li>"{@code url}": CopperEgg API server URL.
 * Optional, default value: {@link #DEFAULT_COPPEREGG_API_URL}.</li>
 * <li>"{@code user}": CopperEgg user. Mandatory</li>
 * <li>"{@code token}": CopperEgg APIKEY. Mandatory</li>
 * <li>"{@code coppereggApiTimeoutInMillis}": read timeout of the calls to CopperEgg HTTP API.
 * Optional, default value: {@link #DEFAULT_COPPEREGG_API_TIMEOUT_IN_MILLIS}.</li>
 * <li>"{@code enabled}": flag to enable/disable the writer. Optional, default value: {$code true}.</li>
 * <li>"{@code source}": CopperEgg . Optional, default value: {@link #DEFAULT_SOURCE} (the hostname of the server).</li>
 * </ul>
 * LibratoWriter.java author:
 * @author <a href="mailto:cleclerc@cloudbees.com">Cyrille Le Clerc</a>
 *
 * CopperEggWriter.java was derived from LibratoWriter.java 
 * @author <a href="mailto:sjohnson@copperegg.com">Scott Johnson</a>
 */
public class CopperEggWriter extends AbstractOutputWriter implements OutputWriter {
    public static final String METRIC_TYPE_GAUGE = "gauge";
    public static final String METRIC_TYPE_COUNTER = "counter";
    public static final String DEFAULT_COPPEREGG_API_URL = "https://api.copperegg.com/v2/revealmetrics";
    public static final String SETTING_COPPEREGG_API_TIMEOUT_IN_MILLIS = "coppereggApiTimeoutInMillis";
    public static final int DEFAULT_COPPEREGG_API_TIMEOUT_IN_MILLIS = 20000;
    public static final String SETTING_SOURCE = "source";
    public static final String DEFAULT_SOURCE = "#hostname#";
    private final static String DEFAULT_COPPEREGG_CONFIGURATION_PATH = "classpath:copperegg_config.json";
    private final Logger logger = LoggerFactory.getLogger(getClass());
    private final AtomicInteger exceptionCounter = new AtomicInteger();
    private JsonFactory jsonFactory = new JsonFactory();

    /**
      * CopperEgg API URL
      */
    private URL url;
    private String url_str;
    private int coppereggApiTimeoutInMillis = DEFAULT_COPPEREGG_API_TIMEOUT_IN_MILLIS;
    private long myPID = 0;
    private String myhost;
    private String myPID_host;
    private String config_location;

    private static Map<String, String> dashMap = new HashMap<String, String>();
    private static Map<String, String> metricgroupMap = new HashMap<String, String>();

    private String jvm_os_groupID = null;
    private String jvm_gc_groupID = null;
    private String jvm_runtime_groupID = null;
    private String jvm_class_groupID = null;
    private String jvm_thread_groupID = null;
    private String heap_metric_groupID = null;
    private String nonheap_metric_groupID = null;
    private String tomcat_thread_pool_groupID = null;
    private String tomcat_grp_groupID = null;
    private String tomcat_manager_groupID = null;
    private String tomcat_servlet_groupID = null;
    private String tomcat_db_groupID = null;
    private String jmxtrans_metric_groupID = null;
    private String app_groupID = null;
    private String app_sales_groupID = null;

    /**
     * CopperEgg API authentication username
     */
    private String user;
    /**
     * CopperEgg APIKEY
     */
    private String token;
    private String basicAuthentication;
    /**
     * Optional proxy for the http API calls
     */
    @Nullable
    private Proxy proxy;
    /**
     * CopperEgg measurement property 'source',
     */
    @Nullable
    private String source;

    /**
     * Load settings
     */
    @Override
    public void start() {

        config_location = DEFAULT_COPPEREGG_CONFIGURATION_PATH;
        String path = config_location.substring("classpath:".length());

        long thisPID = getPID();
        if (myPID == thisPID) {
            logger.info("Started from two threads with the same PID, {}", thisPID);
            return;
        }
        myPID = thisPID;
        try {
            String str = String.valueOf(myPID);
            url_str = getStringSetting(SETTING_URL, DEFAULT_COPPEREGG_API_URL);
            url = new URL(url_str);
            user = getStringSetting(SETTING_USERNAME);
            token = getStringSetting(SETTING_TOKEN);
            user = token;
            basicAuthentication = Base64Variants.getDefaultVariant()
                    .encode((user + ":" + "U").getBytes(Charset.forName("US-ASCII")));

            if (getStringSetting(SETTING_PROXY_HOST, null) != null
                    && !getStringSetting(SETTING_PROXY_HOST).isEmpty()) {
                proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(getStringSetting(SETTING_PROXY_HOST),
                        getIntSetting(SETTING_PROXY_PORT)));
            }

            coppereggApiTimeoutInMillis = getIntSetting(SETTING_COPPEREGG_API_TIMEOUT_IN_MILLIS,
                    DEFAULT_COPPEREGG_API_TIMEOUT_IN_MILLIS);

            source = getStringSetting(SETTING_SOURCE, DEFAULT_SOURCE);
            source = getStrategy().resolveExpression(source);
            myhost = source;
            myPID_host = myhost + '.' + str;

            try {
                InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
                if (in == null) {
                    logger.warn("No file found for classpath:" + config_location);
                } else {
                    read_config(in);
                }
            } catch (Exception e) {
                exceptionCounter.incrementAndGet();
                logger.warn("Exception in start " + e);
            }

            ensure_metric_groups();
            ensure_dashboards();

            logger.info("jvm_os_groupID : {}", jvm_os_groupID);
            logger.info("jvm_gc_groupID : {}", jvm_gc_groupID);
            logger.info("jvm_runtime_groupID : {}", jvm_runtime_groupID);
            logger.info("jvm_class_groupID : {}", jvm_class_groupID);
            logger.info("jvm_thread_groupID : {}", jvm_thread_groupID);
            logger.info("heap_metric_groupID : {}", heap_metric_groupID);
            logger.info("nonheap_metric_groupID : {}", nonheap_metric_groupID);
            logger.info("tomcat_thread_pool_groupID : {}", tomcat_thread_pool_groupID);
            logger.info("tomcat_grp_groupID : {}", tomcat_grp_groupID);
            logger.info("tomcat_servlet_groupID : {}", tomcat_servlet_groupID);
            logger.info("tomcat_manager_groupID : {}", tomcat_manager_groupID);
            logger.info("tomcat_db_groupID  : {}", tomcat_db_groupID);
            logger.info("jmxtrans_metric_groupID : {}", jmxtrans_metric_groupID);
            logger.info("app_groupID : {}", app_groupID);
            logger.info("app_sales_groupID : {}", app_sales_groupID);

            logger.info("Started CopperEggWriter Successfully on jvm '{}', connected to '{}', proxy {}", myPID_host,
                    url, proxy);
        } catch (MalformedURLException e) {
            exceptionCounter.incrementAndGet();
            throw new EmbeddedJmxTransException(e);
        }
    }

    /**
     * Export collected metrics to CopperEgg
     */
    @Override
    public void write(Iterable<QueryResult> results) {

        List<QueryResult> jvm_os_counters = new ArrayList<QueryResult>();
        List<QueryResult> jvm_gc_counters = new ArrayList<QueryResult>();
        List<QueryResult> jvm_runtime_counters = new ArrayList<QueryResult>();
        List<QueryResult> jvm_class_counters = new ArrayList<QueryResult>();
        List<QueryResult> jvm_thread_counters = new ArrayList<QueryResult>();
        List<QueryResult> heap_counters = new ArrayList<QueryResult>();
        List<QueryResult> nonheap_counters = new ArrayList<QueryResult>();
        List<QueryResult> tomcat_thread_pool_counters = new ArrayList<QueryResult>();
        List<QueryResult> tomcat_grp_counters = new ArrayList<QueryResult>();
        List<QueryResult> tomcat_manager_counters = new ArrayList<QueryResult>();
        List<QueryResult> tomcat_servlet_counters = new ArrayList<QueryResult>();
        List<QueryResult> tomcat_db_counters = new ArrayList<QueryResult>();
        List<QueryResult> jmxtrans_counters = new ArrayList<QueryResult>();
        List<QueryResult> app_counters = new ArrayList<QueryResult>();
        List<QueryResult> app_sales_counters = new ArrayList<QueryResult>();

        long epochInMillis = 0;
        String myname = null;
        Object myval = null;
        long thisPID = 0;
        String tmp = null;
        String pidHost = null;

        String delims = "[.]";
        for (QueryResult result : results) {
            epochInMillis = result.getEpochInMillis();
            myname = result.getName();
            myval = result.getValue();
            String valstr = myval.toString();
            thisPID = getPID();
            tmp = String.valueOf(thisPID);
            pidHost = source + "." + tmp;

            String[] parts = myname.split(delims);
            if (parts.length > 0) {
                String p1 = parts[0];
                if ((jmxtrans_metric_groupID != null) && (p1.equals("jmxtrans"))) {
                    QueryResult new_result = new QueryResult(myname, pidHost, myval, epochInMillis);
                    jmxtrans_counters.add(new_result);
                } else if (p1.equals("jvm")) {
                    if (parts[1].equals("os")) {
                        if (parts[2].equals("OpenFileDescriptorCount")) {
                            QueryResult new_result = new QueryResult(myname, pidHost, myval, epochInMillis);
                            jvm_os_counters.add(new_result);
                        } else if (parts[2].equals("CommittedVirtualMemorySize")) {
                            float fval = Float.parseFloat(valstr);
                            try {
                                fval = fval / (1024.0f * 1024.0f);
                            } catch (Exception e) {
                                exceptionCounter.incrementAndGet();
                                logger.info("Exception doing Float: ", e);
                            }
                            QueryResult new_result = new QueryResult(myname, pidHost, fval, epochInMillis);
                            jvm_os_counters.add(new_result);
                        } else if (parts[2].equals("ProcessCpuTime")) {
                            float fval = Float.parseFloat(valstr);
                            try {
                                fval = fval / (1000.0f * 1000.0f * 1000.0f);
                            } catch (Exception e) {
                                exceptionCounter.incrementAndGet();
                                logger.warn("Exception doing Float: ", e);
                            }
                            QueryResult new_result = new QueryResult(myname, pidHost, fval, epochInMillis);
                            jvm_os_counters.add(new_result);
                        }
                    } else if ((parts[1].equals("runtime")) && (parts[2].equals("Uptime"))) {
                        float fval = Float.parseFloat(valstr);
                        try {
                            fval = fval / (1000.0f * 60.0f);
                        } catch (Exception e) {
                            exceptionCounter.incrementAndGet();
                            logger.warn("Exception doing Float: ", e);
                        }
                        QueryResult new_result = new QueryResult(myname, pidHost, fval, epochInMillis);
                        jvm_runtime_counters.add(new_result);
                    } else if ((parts[1].equals("loadedClasses")) && (parts[2].equals("LoadedClassCount"))) {
                        // jvm.loadedClasses.LoadedClassCount 5099 1374549969
                        QueryResult new_result = new QueryResult(myname, pidHost, myval, epochInMillis);
                        jvm_class_counters.add(new_result);
                    } else if ((parts[1].equals("thread")) && (parts[2].equals("ThreadCount"))) {
                        // jvm.thread.ThreadCount 13 1374549940
                        QueryResult new_result = new QueryResult(myname, pidHost, myval, epochInMillis);
                        jvm_thread_counters.add(new_result);
                    } else if ((parts[1].equals("gc"))
                            && ((parts[2].equals("Copy")) || (parts[2].equals("MarkSweepCompact")))
                            && ((parts[3].equals("CollectionCount")) || (parts[3].equals("CollectionTime")))) {
                        // jvm.gc.Copy.CollectionCount 68 1374549940
                        QueryResult new_result = new QueryResult(myname, pidHost, myval, epochInMillis);
                        jvm_gc_counters.add(new_result);
                    } else if (parts[1].equals("memorypool")) {
                        if (((parts[2].equals("Perm_Gen")) || (parts[2].equals("Code_Cache")))
                                && ((parts[4].equals("committed")) || (parts[4].equals("used")))) {
                            myname = "jvmNonHeapMemoryUsage";
                            String fullID = pidHost + "." + parts[2] + "." + parts[4];
                            float fval = Float.parseFloat(valstr);
                            try {
                                fval = fval / (1024.0f * 1024.0f);
                            } catch (Exception e) {
                                exceptionCounter.incrementAndGet();
                                logger.warn("Exception doing Float: ", e);
                            }
                            QueryResult new_result = new QueryResult(myname, fullID, fval, epochInMillis);
                            nonheap_counters.add(new_result);
                        } else if (((parts[2].equals("Eden_Space")) || (parts[2].equals("Survivor_Space"))
                                || (parts[2].equals("Tenured_Gen")))
                                && ((parts[4].equals("committed")) || (parts[4].equals("used")))) {
                            myname = "jvmHeapMemoryUsage";
                            String fullID = pidHost + "." + parts[2] + "." + parts[4];
                            float fval = Float.parseFloat(valstr);
                            try {
                                fval = fval / (1024.0f * 1024.0f);
                            } catch (Exception e) {
                                exceptionCounter.incrementAndGet();
                                logger.warn("Exception doingFloat: ", e);
                            }
                            QueryResult new_result = new QueryResult(myname, fullID, fval, epochInMillis);
                            heap_counters.add(new_result);
                        }
                    }
                } else if (p1.equals("tomcat")) {
                    if ((parts[1].equals("thread-pool")) && ((parts[3].equals("currentThreadsBusy"))
                            || (parts[3].equals("currentThreadCount")))) {
                        // tomcat.thread_pool.http-bio-8080.currentThreadCount 0 1374549955
                        String connector = parts[2];
                        myname = parts[0] + "." + parts[1] + "." + parts[3];
                        String fullID = pidHost + "." + connector;
                        QueryResult new_result = new QueryResult(myname, fullID, myval, epochInMillis);
                        tomcat_thread_pool_counters.add(new_result);
                    } else if ((parts[1].equals("global-request-processor"))) {
                        // tomcat.global-request-processor.http-bio-8080.bytesSent
                        String connector = parts[2];
                        myname = parts[0] + "." + parts[1] + "." + parts[3];
                        String fullID = pidHost + "." + connector;
                        if (parts[3].equals("processingTime")) {
                            float fval = Float.parseFloat(valstr);
                            try {
                                fval = fval / (1024.0f);
                            } catch (Exception e) {
                                exceptionCounter.incrementAndGet();
                                logger.warn("Exception doingFloat: ", e);
                            }
                            QueryResult new_result = new QueryResult(myname, fullID, fval, epochInMillis);
                            tomcat_grp_counters.add(new_result);
                        } else {
                            QueryResult new_result = new QueryResult(myname, fullID, myval, epochInMillis);
                            tomcat_grp_counters.add(new_result);
                        }
                    } else if ((parts[1].equals("manager")) && (parts[4].equals("activeSessions"))) {
                        //  tomcat.manager.localhost._docs.activeSessions 0 1374549955
                        String myhost = parts[2];
                        String mycontext = parts[3];
                        myname = parts[0] + "." + parts[1] + "." + parts[4];
                        String fullID = pidHost + "." + myhost + "." + mycontext;
                        QueryResult new_result = new QueryResult(myname, fullID, myval, epochInMillis);
                        tomcat_manager_counters.add(new_result);
                    } else if ((parts[1].equals("servlet")) && ((parts[4].equals("processingTime"))
                            || (parts[4].equals("errorCount")) || (parts[4].equals("requestCount")))) {
                        // tomcat.servlet.__localhost_cocktail-app-1_0_9-SNAPSHOT.spring-mvc.processingTime
                        String myWebmodule = parts[2];
                        String myServletname = parts[3];
                        myname = parts[0] + "." + parts[1] + "." + parts[4];
                        String fullID = pidHost + "." + myWebmodule + "." + myServletname;
                        QueryResult new_result = new QueryResult(myname, fullID, myval, epochInMillis);
                        tomcat_servlet_counters.add(new_result);
                    } else if ((tomcat_db_groupID != null) && (parts[1].equals("data-source"))) {
                        String myhost = parts[2];
                        String mycontext = parts[3];
                        String mydbname = parts[4];
                        myname = parts[0] + "." + parts[1] + "." + parts[5];
                        String fullID = pidHost + "." + myhost + "." + mycontext + "." + mydbname;
                        QueryResult new_result = new QueryResult(myname, fullID, myval, epochInMillis);
                        tomcat_db_counters.add(new_result);
                    }
                } else if ((app_groupID != null) && (p1.equals("cocktail"))) {
                    if (!(parts[1].equals("CreatedCocktailCount")) && !(parts[1].equals("UpdatedCocktailCount"))) {
                        QueryResult new_result = new QueryResult(myname, pidHost, myval, epochInMillis);
                        app_counters.add(new_result);
                    }
                } else if (((app_sales_groupID != null) && (p1.equals("sales")))
                        && ((parts[1].equals("ordersCounter")) || (parts[1].equals("itemsCounter"))
                                || (parts[1].equals("revenueInCentsCounter")))) {
                    QueryResult new_result = new QueryResult(myname, pidHost, myval, epochInMillis);
                    app_sales_counters.add(new_result);
                }
            } else {
                logger.warn("parts return NULL!!!");
            }
        }
        if (jvm_os_counters.size() > 0) {
            sort_n_send(jvm_os_groupID, jvm_os_counters);
        }
        if (jvm_gc_counters.size() > 0) {
            sort_n_send(jvm_gc_groupID, jvm_gc_counters);
        }
        if (jvm_runtime_counters.size() > 0) {
            sort_n_send(jvm_runtime_groupID, jvm_runtime_counters);
        }
        if (jvm_class_counters.size() > 0) {
            sort_n_send(jvm_class_groupID, jvm_class_counters);
        }
        if (jvm_thread_counters.size() > 0) {
            sort_n_send(jvm_thread_groupID, jvm_thread_counters);
        }
        if (heap_counters.size() > 0) {
            sort_n_send(heap_metric_groupID, heap_counters);
        }
        if (nonheap_counters.size() > 0) {
            sort_n_send(nonheap_metric_groupID, nonheap_counters);
        }
        if (tomcat_thread_pool_counters.size() > 0) {
            sort_n_send(tomcat_thread_pool_groupID, tomcat_thread_pool_counters);
        }
        if (tomcat_grp_counters.size() > 0) {
            sort_n_send(tomcat_grp_groupID, tomcat_grp_counters);
        }
        if (tomcat_servlet_counters.size() > 0) {
            sort_n_send(tomcat_servlet_groupID, tomcat_servlet_counters);
        }
        if (tomcat_manager_counters.size() > 0) {
            sort_n_send(tomcat_manager_groupID, tomcat_manager_counters);
        }
        if (tomcat_db_counters.size() > 0) {
            sort_n_send(tomcat_db_groupID, tomcat_db_counters);
        }
        if (jmxtrans_counters.size() > 0) {
            sort_n_send(jmxtrans_metric_groupID, jmxtrans_counters);
        }
        if (app_counters.size() > 0) {
            sort_n_send(app_groupID, app_counters);
        }
        if (app_sales_counters.size() > 0) {
            sort_n_send(app_sales_groupID, app_sales_counters);
        }
    }

    public void sort_n_send(String mg_name, List<QueryResult> mg_counters) {
        Collections.sort(mg_counters, new Comparator<QueryResult>() {
            public int compare(QueryResult o1, QueryResult o2) {
                //Sorts by 'epochInMillis' property
                Integer rslt = o1.getEpochInMillis() < o2.getEpochInMillis() ? -1
                        : o1.getEpochInMillis() > o2.getEpochInMillis() ? 1 : 0;
                if (rslt == 0) {
                    rslt = (o1.getType()).compareTo(o2.getType());
                }
                return rslt;
            }
        });
        send_metrics(mg_name, mg_counters);
    }

    public void send_metrics(String mg_name, List<QueryResult> counters) {
        long timeblock = counters.get(0).getEpoch(TimeUnit.SECONDS);
        String identifier = counters.get(0).getType();
        int remaining = counters.size();
        List<QueryResult> sorted_ctrs = new ArrayList<QueryResult>();

        for (QueryResult counter : counters) {
            remaining = remaining - 1;
            if ((timeblock != (counter.getEpoch(TimeUnit.SECONDS))) || (!identifier.equals(counter.getType()))) {
                one_set(mg_name, sorted_ctrs);
                timeblock = counter.getEpoch(TimeUnit.SECONDS);
                identifier = counter.getType();
                sorted_ctrs.clear();
                sorted_ctrs.add(counter);
            } else {
                sorted_ctrs.add(counter);
            }
            if (remaining == 0) {
                one_set(mg_name, sorted_ctrs);
            }
        }
    }

    public void one_set(String mg_name, List<QueryResult> counters) {
        HttpURLConnection urlCxn = null;
        URL newurl = null;
        try {
            newurl = new URL(url_str + "/samples/" + mg_name + ".json");
            if (proxy == null) {
                urlCxn = (HttpURLConnection) newurl.openConnection();
            } else {
                urlCxn = (HttpURLConnection) newurl.openConnection(proxy);
            }
            if (urlCxn != null) {
                urlCxn.setRequestMethod("POST");
                urlCxn.setDoInput(true);
                urlCxn.setDoOutput(true);
                urlCxn.setReadTimeout(coppereggApiTimeoutInMillis);
                urlCxn.setRequestProperty("content-type", "application/json; charset=utf-8");
                urlCxn.setRequestProperty("Authorization", "Basic " + basicAuthentication);
            }
        } catch (Exception e) {
            exceptionCounter.incrementAndGet();
            logger.warn("Exception: one_set: failed to connect to CopperEgg Service '{}' with proxy {}", newurl,
                    proxy, e);
            return;
        }
        if (urlCxn != null) {
            try {
                cue_serialize(counters, urlCxn.getOutputStream());
                int responseCode = urlCxn.getResponseCode();
                if (responseCode != 200) {
                    logger.warn("one_set: Failure {}: {} to send result to CopperEgg service {}", responseCode,
                            urlCxn.getResponseMessage(), newurl);
                }
                try {
                    InputStream in = urlCxn.getInputStream();
                    IoUtils2.copy(in, IoUtils2.nullOutputStream());
                    IoUtils2.closeQuietly(in);
                    InputStream err = urlCxn.getErrorStream();
                    if (err != null) {
                        IoUtils2.copy(err, IoUtils2.nullOutputStream());
                        IoUtils2.closeQuietly(err);
                    }
                } catch (IOException e) {
                    exceptionCounter.incrementAndGet();
                    logger.warn("Execption one_set: Write-Exception flushing http connection", e);
                }

            } catch (Exception e) {
                exceptionCounter.incrementAndGet();
                logger.warn("Execption: one_set: Failure to send result to CopperEgg Service '{}' with proxy {}",
                        newurl, proxy, e);
            }
        }
    }

    public void cue_serialize(@Nonnull Iterable<QueryResult> counters, @Nonnull OutputStream out)
            throws IOException {
        int first = 0;
        long time = 0;
        String myID = null;
        JsonGenerator g = jsonFactory.createGenerator(out, JsonEncoding.UTF8);

        for (QueryResult counter : counters) {
            if (0 == first) {
                time = counter.getEpoch(TimeUnit.SECONDS);
                myID = counter.getType();
                first = 1;
                g.writeStartObject();
                g.writeStringField("identifier", myID);
                g.writeNumberField("timestamp", time);
                g.writeObjectFieldStart("values");
            }
            if (counter.getValue() instanceof Integer) {
                g.writeNumberField(counter.getName(), (Integer) counter.getValue());
            } else if (counter.getValue() instanceof Long) {
                g.writeNumberField(counter.getName(), (Long) counter.getValue());
            } else if (counter.getValue() instanceof Float) {
                g.writeNumberField(counter.getName(), (Float) counter.getValue());
            } else if (counter.getValue() instanceof Double) {
                g.writeNumberField(counter.getName(), (Double) counter.getValue());
            }
        }
        g.writeEndObject();
        g.writeEndObject();
        g.flush();
        g.close();
    }

    private static long getPID() {
        String processName = java.lang.management.ManagementFactory.getRuntimeMXBean().getName();
        return Long.parseLong(processName.split("@")[0]);
    }

    public int cue_getExceptionCounter() {
        return exceptionCounter.get();
    }

    /**
     * If metric group doesn't exist, create it
     * If it does exist, update it.
     */

    public void ensure_metric_groups() {
        HttpURLConnection urlConnection = null;
        OutputStreamWriter wr = null;
        URL myurl = null;

        try {
            myurl = new URL(url_str + "/metric_groups.json?show_hidden=1");
            urlConnection = (HttpURLConnection) myurl.openConnection();
            urlConnection.setRequestMethod("GET");
            urlConnection.setDoInput(true);
            urlConnection.setDoOutput(true);
            urlConnection.setReadTimeout(coppereggApiTimeoutInMillis);
            urlConnection.setRequestProperty("content-type", "application/json; charset=utf-8");
            urlConnection.setRequestProperty("Authorization", "Basic " + basicAuthentication);

            int responseCode = urlConnection.getResponseCode();
            if (responseCode != 200) {
                logger.warn(
                        "Bad responsecode " + String.valueOf(responseCode) + " from metric_groups Index: " + myurl);
            }
        } catch (Exception e) {
            exceptionCounter.incrementAndGet();
            logger.warn("Failure to execute metric_groups index request " + myurl + "  " + e);
        } finally {
            if (urlConnection != null) {
                try {
                    InputStream in = urlConnection.getInputStream();
                    String theString = convertStreamToString(in);
                    for (Map.Entry<String, String> entry : metricgroupMap.entrySet()) {
                        String checkName = entry.getKey();
                        try {
                            String Rslt = groupFind(checkName, theString, 0);
                            if (Rslt != null) {
                                // Update it
                                Rslt = Send_Commmand("/metric_groups/" + Rslt + ".json?show_hidden=1", "PUT",
                                        entry.getValue(), 0);
                            } else {
                                // create it
                                Rslt = Send_Commmand("/metric_groups.json", "POST", entry.getValue(), 0);
                            }
                            if (Rslt != null) {
                                if (Rslt.toLowerCase().contains("tomcat")) {
                                    if (Rslt.toLowerCase().contains("thread_pool")) {
                                        tomcat_thread_pool_groupID = Rslt;
                                    } else if (Rslt.toLowerCase().contains("grp")) {
                                        tomcat_grp_groupID = Rslt;
                                    } else if (Rslt.toLowerCase().contains("servlet")) {
                                        tomcat_servlet_groupID = Rslt;
                                    } else if (Rslt.toLowerCase().contains("manager")) {
                                        tomcat_manager_groupID = Rslt;
                                    } else if (Rslt.toLowerCase().contains("db")) {
                                        tomcat_db_groupID = Rslt;
                                    }
                                } else if (Rslt.toLowerCase().contains("jmxtrans")) {
                                    jmxtrans_metric_groupID = Rslt;
                                } else if (Rslt.toLowerCase().contains("sales")) {
                                    app_sales_groupID = Rslt;
                                } else if (Rslt.toLowerCase().contains("cocktail")) {
                                    app_groupID = Rslt;
                                } else if (Rslt.toLowerCase().contains("jvm")) {
                                    if (Rslt.toLowerCase().contains("os")) {
                                        jvm_os_groupID = Rslt;
                                    } else if (Rslt.toLowerCase().contains("gc")) {
                                        jvm_gc_groupID = Rslt;
                                    } else if (Rslt.toLowerCase().contains("runtime")) {
                                        jvm_runtime_groupID = Rslt;
                                    } else if (Rslt.toLowerCase().contains("class")) {
                                        jvm_class_groupID = Rslt;
                                    } else if (Rslt.toLowerCase().contains("thread")) {
                                        jvm_thread_groupID = Rslt;
                                    }
                                } else if (Rslt.toLowerCase().contains("nonheap")) {
                                    nonheap_metric_groupID = Rslt;
                                } else if (Rslt.toLowerCase().contains("heap")) {
                                    heap_metric_groupID = Rslt;
                                }
                            }
                        } catch (Exception e) {
                            exceptionCounter.incrementAndGet();
                            logger.warn("Exception in metric_group update or create: " + myurl + "  " + e);
                        }
                    }
                } catch (IOException e) {
                    exceptionCounter.incrementAndGet();
                    logger.warn("Exception flushing http connection" + e);
                }
            }
        }
    }

    /**
     * If dashboard doesn't exist, create it
     * If it does exist, update it.
     */

    private void ensure_dashboards() {
        HttpURLConnection urlConnection = null;
        OutputStreamWriter wr = null;
        URL myurl = null;

        try {
            myurl = new URL(url_str + "/dashboards.json");
            urlConnection = (HttpURLConnection) myurl.openConnection();
            urlConnection.setRequestMethod("GET");
            urlConnection.setDoInput(true);
            urlConnection.setDoOutput(true);
            urlConnection.setReadTimeout(coppereggApiTimeoutInMillis);
            urlConnection.setRequestProperty("content-type", "application/json; charset=utf-8");
            urlConnection.setRequestProperty("Authorization", "Basic " + basicAuthentication);

            int responseCode = urlConnection.getResponseCode();
            if (responseCode != 200) {
                logger.warn(
                        "Bad responsecode " + String.valueOf(responseCode) + " from Dahsboards Index: " + myurl);
            }
        } catch (Exception e) {
            exceptionCounter.incrementAndGet();
            logger.warn("Exception on dashboards index request " + myurl + "  " + e);
        } finally {
            if (urlConnection != null) {
                try {
                    InputStream in = urlConnection.getInputStream();
                    String theString = convertStreamToString(in);
                    for (Map.Entry<String, String> entry : dashMap.entrySet()) {
                        String checkName = entry.getKey();
                        try {
                            String Rslt = groupFind(checkName, theString, 1);
                            if (Rslt != null) {
                                // Update it
                                Rslt = Send_Commmand("/dashboards/" + Rslt + ".json", "PUT", entry.getValue(), 1);
                            } else {
                                // create it
                                Rslt = Send_Commmand("/dashboards.json", "POST", entry.getValue(), 1);
                            }
                        } catch (Exception e) {
                            exceptionCounter.incrementAndGet();
                            logger.warn("Exception in dashboard update or create: " + myurl + "  " + e);
                        }
                    }
                } catch (IOException e) {
                    exceptionCounter.incrementAndGet();
                    logger.warn("Exception flushing http connection" + e);
                }
            }
        }
    }

    private String jparse(String jsonstr, Integer ExpectInt) {

        ObjectMapper mapper = new ObjectMapper();
        String Result = null;
        try {
            JsonNode root = mapper.readTree(jsonstr);
            if (ExpectInt != 0) {
                int myid = root.get("id").asInt();
                Result = String.valueOf(myid);
            } else {
                Result = root.get("id").asText().toString();
            }
        } catch (JsonGenerationException e) {
            exceptionCounter.incrementAndGet();
            logger.warn("JsonGenerationException " + e);
        } catch (JsonMappingException e) {
            exceptionCounter.incrementAndGet();
            logger.warn("JsonMappingException " + e);
        } catch (IOException e) {
            exceptionCounter.incrementAndGet();
            logger.warn("IOException " + e);
        }
        return (Result);
    }

    public String convertStreamToString(InputStream is) throws IOException {
        //
        // To convert the InputStream to String we use the
        // Reader.read(char[] buffer) method. We iterate until the
        // Reader return -1 which means there's no more data to
        // read. We use the StringWriter class to produce the string.
        //
        if (is != null) {
            Writer writer = new StringWriter();

            char[] buffer = new char[1024];
            try {
                Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
                int n;
                while ((n = reader.read(buffer)) != -1) {
                    writer.write(buffer, 0, n);
                }
            } finally {
                is.close();
            }
            return writer.toString();
        } else {
            return "";
        }
    }

    /**
     * read_config()
     * The copperegg_config.json file contains a specification for the metric groups and dashboards to be created / or updated.
     * Mandatory
     */
    public void read_config(InputStream in) throws Exception {

        JsonFactory f = new MappingJsonFactory();
        JsonParser jp = f.createJsonParser(in);

        JsonToken current;

        current = jp.nextToken();
        if (current != JsonToken.START_OBJECT) {
            logger.warn("read_config: Error:  START_OBJECT not found : quiting.");
            return;
        }
        current = jp.nextToken();
        String fieldName = jp.getCurrentName();
        current = jp.nextToken();
        if (fieldName.equals("config")) {
            if (current != JsonToken.START_OBJECT) {
                logger.warn("read_config: Error:  START_OBJECT not found after config : quiting.");
                return;
            }
            current = jp.nextToken();
            String fieldName2 = jp.getCurrentName();
            if (fieldName2.equals("metric_groups")) {
                current = jp.nextToken();
                if (current != JsonToken.START_ARRAY) {
                    logger.warn("read_config: Error:  START_ARRAY not found after metric_groups : quiting.");
                    return;
                }

                current = jp.nextToken();
                while (current != JsonToken.END_ARRAY) {
                    if (current != JsonToken.START_OBJECT) {
                        logger.warn(
                                "read_config: Error:  START_OBJECT not found after metric_groups START_ARRAY : quiting.");
                        return;
                    }
                    current = jp.nextToken();
                    JsonNode node1 = jp.readValueAsTree();
                    String node1string = write_tostring(node1);
                    metricgroupMap.put(node1.get("name").asText(), node1string);
                    current = jp.nextToken();
                }

                current = jp.nextToken();
                String fieldName3 = jp.getCurrentName();

                if (fieldName3.equals("dashboards")) {
                    current = jp.nextToken();
                    if (current != JsonToken.START_ARRAY) {
                        logger.warn("read_config: Error:  START_ARRAY not found after dashboards : quiting.");
                        return;
                    }
                    current = jp.nextToken();
                    while (current != JsonToken.END_ARRAY) {
                        if (current != JsonToken.START_OBJECT) {
                            logger.warn(
                                    "read_config: Error:  START_OBJECT not found after dashboards START_ARRAY : quiting.");
                            return;
                        }
                        current = jp.nextToken();
                        JsonNode node = jp.readValueAsTree();
                        String nodestring = write_tostring(node);
                        dashMap.put(node.get("name").asText(), nodestring);
                        current = jp.nextToken();

                    }
                    if (jp.nextToken() != JsonToken.END_OBJECT) {
                        logger.warn("read_config: Error:  END_OBJECT expected, not found (1): quiting.");
                        return;
                    }
                    if (jp.nextToken() != JsonToken.END_OBJECT) {
                        logger.warn("read_config: Error:  END_OBJECT expected, not found (2): quiting.");
                        return;
                    }
                } else {
                    logger.warn("read_config: Error:  Expected dashboards : quiting.");
                    return;
                }
            } else {
                logger.warn("read_config: Error:  Expected metric_groups : quiting.");
                return;
            }
        }
    }

    public String groupFind(String findName, String findIndex, Integer ExpectInt) throws Exception {
        JsonFactory f = new MappingJsonFactory();
        JsonParser jp = f.createJsonParser(findIndex);

        int count = 0;
        int foundit = 0;
        String Result = null;

        JsonToken current = jp.nextToken();
        if (current != JsonToken.START_ARRAY) {
            logger.warn("groupFind: Error: START_ARRAY expected, not found : quiting.");
            return (Result);
        }
        current = jp.nextToken();
        while (current != JsonToken.END_ARRAY) {
            if (current != JsonToken.START_OBJECT) {
                logger.warn("groupFind: Error: START_OBJECT expected, not found : quiting.");
                return (Result);
            }
            current = jp.nextToken();
            JsonNode node = jp.readValueAsTree();
            String tmpStr = node.get("name").asText().toString();
            if (findName.equals(node.get("name").asText().toString())) {
                if (ExpectInt != 0) {
                    foundit = node.get("id").asInt();
                    Result = String.valueOf(foundit);
                } else {
                    Result = node.get("id").asText().toString();
                }
                break;
            }
            current = jp.nextToken();
            count = count + 1;
        }
        return (Result);
    }

    public String write_tostring(JsonNode json) {
        ObjectMapper mapper = new ObjectMapper();
        StringWriter out = new StringWriter();

        try {
            JsonFactory fac = new JsonFactory();
            JsonGenerator gen = fac.createJsonGenerator(out);

            // Now write:
            mapper.writeTree(gen, json);
            gen.flush();
            gen.close();
            return out.toString();
        } catch (Exception e) {
            exceptionCounter.incrementAndGet();
            logger.warn("Exception in write_tostring: " + e);
        }
        return (null);
    }

    public String Send_Commmand(String command, String msgtype, String payload, Integer ExpectInt) {
        HttpURLConnection urlConnection = null;
        URL myurl = null;
        OutputStreamWriter wr = null;
        int responseCode = 0;
        String id = null;
        int error = 0;

        try {
            myurl = new URL(url_str + command);
            urlConnection = (HttpURLConnection) myurl.openConnection();
            urlConnection.setRequestMethod(msgtype);
            urlConnection.setDoInput(true);
            urlConnection.setDoOutput(true);
            urlConnection.setReadTimeout(coppereggApiTimeoutInMillis);
            urlConnection.addRequestProperty("User-Agent", "Mozilla/4.76");
            urlConnection.setRequestProperty("content-type", "application/json; charset=utf-8");
            urlConnection.setRequestProperty("Authorization", "Basic " + basicAuthentication);

            wr = new OutputStreamWriter(urlConnection.getOutputStream(), "UTF-8");
            wr.write(payload);
            wr.flush();

            responseCode = urlConnection.getResponseCode();
            if (responseCode != 200) {
                logger.warn(
                        "Send Command: Response code " + responseCode + " url is " + myurl + " command " + msgtype);
                error = 1;
            }
        } catch (Exception e) {
            exceptionCounter.incrementAndGet();
            logger.warn("Exception in Send Command: url is " + myurl + " command " + msgtype + "; " + e);
            error = 1;
        } finally {
            if (urlConnection != null) {
                try {
                    if (error > 0) {
                        InputStream err = urlConnection.getErrorStream();
                        String errString = convertStreamToString(err);
                        logger.warn("Reported error : " + errString);
                        IoUtils2.closeQuietly(err);
                    } else {
                        InputStream in = urlConnection.getInputStream();
                        String theString = convertStreamToString(in);
                        id = jparse(theString, ExpectInt);
                        IoUtils2.closeQuietly(in);
                    }
                } catch (IOException e) {
                    exceptionCounter.incrementAndGet();
                    logger.warn("Exception in Send Command : flushing http connection " + e);
                }
            }
            if (wr != null) {
                try {
                    wr.close();
                } catch (IOException e) {
                    exceptionCounter.incrementAndGet();
                    logger.warn("Exception in Send Command: closing OutputWriter " + e);
                }
            }
        }
        return (id);
    }
}