/*
* 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}.
* <p/>
* This implementation uses v2 of the CopperEgg API <a href="http://dev.copperegg.com/">
* <p/>
* Settings:
* <ul>
* <li>"{@code url}": CopperEgg API server URL.
* Optional, default value: {@value #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: {@value #DEFAULT_COPPEREGG_API_TIMEOUT_IN_MILLIS}.</li>
* <li>"{@code enabled}": flag to enable/disable the writer. Optional, default value: <code>true</code>.</li>
* <li>"{@code source}": CopperEgg . Optional, default value: {@value #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<p/>
*/
@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);
}
}