/* @Author: Rajesh Swarnkar, Qualkitykiosk */ package com.qualitykiosk.honeycomb; import java.io.DataOutputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; import java.util.Collection; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import org.ini4j.InvalidFileFormatException; import com.dynatrace.diagnostics.pdk.ActionEnvironment; import com.dynatrace.diagnostics.pdk.Incident; import com.dynatrace.diagnostics.pdk.Violation; import com.dynatrace.diagnostics.pdk.Violation.TriggerValue; public class HoneycombHelper { private static final Logger log = Logger.getLogger(HoneycombMain.class.getName()); // Other Imp variables String s_jsontext; boolean b_sendFlag = false; MessageModifier msgModifier; // String json_systemProfileName; // List of JSON Field String s_applicationName; String s_incidentName; String s_status; String s_severity; String s_breachValue; String s_actualValue; String s_startTime; String s_endTime; String s_message; String s_splitting; String s_measureName; String s_componentName; String s_uid; // Default Constructor public HoneycombHelper(){} /** * This is the helper method which is called from HoneycombMain.execute() * This does all the tasks of the execute() * */ public int hcHelper(ActionEnvironment env, PluginData pd) throws InvalidFileFormatException, FileNotFoundException, IOException{ // From the PluginData Object get the inifile path to create messagemodifier object msgModifier = new MessageModifier(pd.getIniFileNamePath()); // Fetch the incidents in to collection Collection incidents = env.getIncidents(); // Get the name of system profile // json_systemProfileName = env.getSystemProfileName(); // log.log(Level.FINE,"Incidents are fetched from the System Profile : "+json_systemProfileName); log.log(Level.FINER,"Fetching of Incindets done..."); log.log(Level.INFO, "Fount Total "+ incidents.size()+" Incident(s)."); // SET:${applicationName} s_applicationName = env.getSystemProfileName(); log.log(Level.FINER,"Now Iterating over incidents..."); // Loop - 1 for (Incident incident : incidents) { b_sendFlag = true; // SET:${incidentName} s_incidentName = incident.getIncidentRule().getName(); // SET:${status} s_status = "OPEN"; if (incident.getState() == Incident.STATE_CLOSE_INCIDENT) s_status = "CLOSE"; // SET:${startTime} s_startTime = incident.getStartTime().getTimestampInMs() + ""; // SET:${endTime} s_endTime = incident.getEndTime().getTimestampInMs() + ""; // SET:${message} s_message = incident.getMessage(); // SET:${uid} s_uid = incident.getKey().getUUID(); // Get violations for (Violation violation : incident.getViolations()) { // SET:${severity} s_severity = violation.getViolatedThreshold().getType().name(); // SET:${breachValue} s_breachValue = violation.getViolatedThreshold().getValue().getValue() + ""; if (s_breachValue.equals("NaN")) s_breachValue = "0"; // NaN fix // SET:${measureName} // Fix for measure name value having JSON Non-Safe character or non-required chars String tempViolatedMeasureName = violation.getViolatedMeasure().getName(); tempViolatedMeasureName = tempViolatedMeasureName.replaceAll("\\[|\\]|\\n|\\t|\\r|'", ""); // This will replace [ or ] or newlines with null char s_measureName = tempViolatedMeasureName; // SET:${componentName} s_componentName = violation.getViolatedMeasure().getMetric().getGroup(); log.log(Level.FINER,"Metric Type or Component Name: "+s_componentName); /* * Algorithm: * 0. Send Flag = True, ie. By default assume JSON will be posted * 1. Decide what is type of Incident is by using ${componentName} * 2. If ${componentName} contains text "Business Transaction" then its of alert type BT else its Non-BT Type of Alert ie. INFRA type * 3. If ${componentName} is BT type then either its splitting may contain DASH or may NOT contain Dash * 3.1 If ${componentName} has dash in split then set send flag to false * 3.2 If ${componentName} does not has dash, then set send flag to true * 4. If ${componentName} is of type INFRA then disregard splitting by setting it to dash, set the send flag to true * 5. Before the violation loop ends, send the JSON based on the send flag value. * */ String all_splittings = ""; if (s_componentName.toLowerCase().contains("Business Transaction".toLowerCase())){ log.log(Level.FINER,"componentName contains 'Business Transaction', hence its BT type of alert."); // SET:${splitting} List plugin_split_values = violation.getViolatedMeasure().getSplittings(); log.log(Level.FINE,"Found "+plugin_split_values.size()+" Splitting(s) in the Incident : " + incident.getIncidentRule().getName()+"."); if(plugin_split_values.size()==0){ all_splittings = "-"; b_sendFlag = false; } else { String delim = ""; for (String s1 : plugin_split_values){ s1 = s1.replaceAll("\\[|\\]|\\n|\\t|\\r|'", ""); // This will replace [ or ] or newlines with null char all_splittings = all_splittings + delim + s1; delim = ","; } b_sendFlag = true; }// end of inner else log.log(Level.FINER,"Splitting value after removal of JSON Non-Safe characters is : " + all_splittings); s_splitting = all_splittings; log.log(Level.FINE,"Combined Splitting: "+s_splitting); }// end of if else{ log.log(Level.FINER,"componentName does not contains 'Business Transaction', hence its Non-BT or INFRA type of alert."); s_splitting = "-"; b_sendFlag = true; log.log(Level.FINE,"For Non-BT type alert, Splitting was: "+s_splitting); } // WARNING : This may cause issue if there are multiple trigger values for each BT/M. In such case JSON array would be best // SET:${actualValue} // Get Trigger values of each violations Collection triggerValues = violation.getTriggerValues(); for (TriggerValue triggerValue : triggerValues) { s_actualValue = triggerValue.getValue().getValue() + ""; log.log(Level.FINEST,"Trigger Value: "+s_actualValue); } /** * Now since we have got the splittings, we can apply ProcCode and ActCode Transformations, using the MessageModifier.java * **/ // CALL THE METHODS THAT WILL TRANSFORM MESSAGE BASED ON PROCCODE and ACTCODE s_splitting = msgModifier.modifyMessage01(s_splitting); log.log(Level.FINE,"Modified Splitting : "+s_splitting); /** * Finally Build the JSON Text Which is to be sent * * */ // SET:${jsontext} s_jsontext = "{" + "\"applicationName\":\"" + s_applicationName + "\"," + // string "\"incidentName\":\"" + s_incidentName + "\"," + // string "\"status\":\"" + s_status + "\"," + // string "\"severity\":\"" + s_severity + "\"," + // string "\"breachValue\":" + s_breachValue + "," + // double "\"actualValue\":" + s_actualValue + "," + // double "\"startTime\":" + s_startTime + "," + // double "\"endTime\":\"" + s_endTime + "\"," + // string !! "\"message\":\"" + s_message + "\"," + // string "\"splitting\":\"" + s_splitting + "\"," + // string "\"measureName\":\"" + s_measureName + "\"," + // string "\"componentName\":\"" + s_componentName + "\"," + // string "\"uid\":\"" + s_uid + "\"" + // string !!!! last value "}"; // Enable below log lines for all JSON // log.log(Level.INFO,"JSON Text: "); // log.log(Level.INFO,s_jsontext); // log.log(Level.INFO,"sendFlag: "+b_sendFlag+", uid: "+s_uid+", startTime: "+s_startTime+", endTime: "+s_endTime+", incidentName: "+s_incidentName); /** * Incorporate the logic to post the JSON via HTTP * * */ if(b_sendFlag==true){ // log.log(Level.INFO,"JSON Text: "); // log.log(Level.INFO,s_jsontext); log.log(Level.INFO,"%%[[ sendFlag: "+b_sendFlag+", uid: "+s_uid+", startTime: "+s_startTime+", endTime: "+s_endTime+", incidentName: "+s_incidentName+", json_text: "+s_jsontext+" ]]%%"); postJsonToUrlViaHttp(s_jsontext,pd.getUrlToPost()); } // dummy logic to enable logging of the JSON which is not posted to server if(b_sendFlag==false && pd.getIsLogJsonOnSkip()==true){ log.log(Level.INFO,"%%[[ sendFlag: "+b_sendFlag+", uid: "+s_uid+", startTime: "+s_startTime+", endTime: "+s_endTime+", incidentName: "+s_incidentName+", json_text: "+s_jsontext+" ]]%%"); } log.log(Level.FINER,"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); // indicates a single iteration of violation has ended }// end of violation iterator loop }// end of incident iterator loop return 0; }// End of hcHelper() method public int postJsonToUrlViaHttp(String jsontext, String targetUrlString) throws IOException{ log.log(Level.FINEST,"Inside postJsonToUrlViaHttp(), Post URL received :"+ targetUrlString); // Http URL Object HttpURLConnection conn = null; int json_post_status = -1; try{ URL url = new URL(targetUrlString); conn = (HttpURLConnection) url.openConnection(); log.log(Level.FINER,"Success Connection to URL :"+ targetUrlString); conn.setRequestMethod("POST"); conn.setDoOutput(true); conn.setRequestProperty("content-type", "application/json; charset=utf-8"); } catch(Exception ex){ log.log(Level.SEVERE,"Exception occurred while parsing or connecting to URL : "+targetUrlString); // log.log(Level.SEVERE, ex.getMessage(), ex); // Enable this for full trace } if (conn!=null) { DataOutputStream dos = new DataOutputStream(conn.getOutputStream()); dos.writeBytes(s_jsontext); dos.flush(); dos.close(); json_post_status = conn.getResponseCode(); if(json_post_status==200) log.log(Level.INFO,"JSON Post successeded. HTTP ResponseCode :"+ json_post_status); else log.log(Level.SEVERE,"JSON Post failed. HTTP ResponseCode :"+ json_post_status); conn.disconnect(); } return json_post_status; } }