From 051661fa22c7b0f4ce1cc86c63107b4cf99bc5aa Mon Sep 17 00:00:00 2001 From: Jean-Didier Date: Tue, 8 Aug 2023 10:29:36 +0200 Subject: [PATCH 01/16] fix bug 412 chardet dependency --- .../database/inputapi/requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/morphemic-persistent-storage/database/inputapi/requirements.txt b/morphemic-persistent-storage/database/inputapi/requirements.txt index 6bf935bd..220c4e20 100644 --- a/morphemic-persistent-storage/database/inputapi/requirements.txt +++ b/morphemic-persistent-storage/database/inputapi/requirements.txt @@ -1,4 +1,5 @@ influxdb stomp.py requests -python-slugify \ No newline at end of file +python-slugify +chardet \ No newline at end of file -- GitLab From b7b9815f2b335fb2bf7502954609cc085aea79f1 Mon Sep 17 00:00:00 2001 From: Jean-Didier Date: Wed, 9 Aug 2023 11:55:10 +0200 Subject: [PATCH 02/16] fix bug 413 --- grouping/PPO_cg.py | 4 +--- grouping/requirements.txt | 3 ++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/grouping/PPO_cg.py b/grouping/PPO_cg.py index f64153e7..26c6ef37 100644 --- a/grouping/PPO_cg.py +++ b/grouping/PPO_cg.py @@ -4,9 +4,8 @@ from tensorflow.keras import layers import scipy.signal import time from threading import Thread -import json, os, time,uvicorn, requests, sys, logging +import json, os, time,uvicorn, requests, logging from fastapi import FastAPI -from test_application import UtilitySimulator from pydantic import BaseModel from action_creator import prepareX, makeY_, find_solutions, final_list from gym import Env @@ -17,7 +16,6 @@ import random import requests from random import shuffle import string -from collections import deque import tensorflow as tf from tensorflow.keras import layers from itertools import combinations diff --git a/grouping/requirements.txt b/grouping/requirements.txt index 3284d8f0..f17d39a5 100644 --- a/grouping/requirements.txt +++ b/grouping/requirements.txt @@ -8,4 +8,5 @@ stomp.py slugify gym==0.17.3 numpy>=1.19.2 -requests==2.26.0 \ No newline at end of file +requests==2.26.0 +typing-extensions==3.10.0.0 \ No newline at end of file -- GitLab From 5ce6b20706ad878a6a953e556f3b11985b6872a6 Mon Sep 17 00:00:00 2001 From: Jan Marchel Date: Wed, 9 Aug 2023 13:53:24 +0000 Subject: [PATCH 03/16] Update file requirements.txt --- grouping/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grouping/requirements.txt b/grouping/requirements.txt index f17d39a5..e29585a6 100644 --- a/grouping/requirements.txt +++ b/grouping/requirements.txt @@ -9,4 +9,4 @@ slugify gym==0.17.3 numpy>=1.19.2 requests==2.26.0 -typing-extensions==3.10.0.0 \ No newline at end of file +typing-extensions>=3.10.0.0 \ No newline at end of file -- GitLab From 5068a56f29e531a7654e6206c43215804e6c9155 Mon Sep 17 00:00:00 2001 From: Jan Marchel Date: Wed, 9 Aug 2023 14:00:44 +0000 Subject: [PATCH 04/16] Update file requirements.txt --- grouping/requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/grouping/requirements.txt b/grouping/requirements.txt index e29585a6..208e03c3 100644 --- a/grouping/requirements.txt +++ b/grouping/requirements.txt @@ -9,4 +9,3 @@ slugify gym==0.17.3 numpy>=1.19.2 requests==2.26.0 -typing-extensions>=3.10.0.0 \ No newline at end of file -- GitLab From 6aa8c5f2f5981b6b6f47268d6ba4f651e013434f Mon Sep 17 00:00:00 2001 From: Jean-Didier Date: Wed, 9 Aug 2023 19:06:42 +0200 Subject: [PATCH 05/16] fix bug 414 requirement --- grouping/requirements.txt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/grouping/requirements.txt b/grouping/requirements.txt index 208e03c3..29d23cf4 100644 --- a/grouping/requirements.txt +++ b/grouping/requirements.txt @@ -1,11 +1,11 @@ -tensorflow==2.6.0 -keras==2.6.0 -scipy==1.7.2 +tensorflow +keras +scipy uvicorn -fastapi==0.73.0 -pydantic==1.9.0 +fastapi +pydantic stomp.py slugify -gym==0.17.3 -numpy>=1.19.2 -requests==2.26.0 +gym +numpy +requests -- GitLab From 5ad4f000e56c067880c78ea0e047e251a782ecb0 Mon Sep 17 00:00:00 2001 From: Andreas Tsagkaropoulos Date: Thu, 24 Aug 2023 17:36:12 +0300 Subject: [PATCH 06/16] Redirected all output to standard output for the SLO Violation Detector Docker container --- morphemic-slo-severity-calculator/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/morphemic-slo-severity-calculator/Dockerfile b/morphemic-slo-severity-calculator/Dockerfile index 6a304b53..ce4c31c2 100644 --- a/morphemic-slo-severity-calculator/Dockerfile +++ b/morphemic-slo-severity-calculator/Dockerfile @@ -9,4 +9,4 @@ COPY src/main/resources/config/eu.morphemic.slo_violation_detector.properties /h COPY src/main/resources/config/eu.melodic.event.brokerclient.properties /home/src/main/resources/config/eu.melodic.event.brokerclient.properties COPY target/SLOSeverityCalculator-4.0-SNAPSHOT.jar /home/SLOSeverityCalculator-4.0-SNAPSHOT.jar WORKDIR /home -CMD ["/bin/sh","-c","java -jar SLOSeverityCalculator-4.0-SNAPSHOT.jar > $LOG_FILE"] +CMD ["/bin/sh","-c","java -jar SLOSeverityCalculator-4.0-SNAPSHOT.jar 2>&1 > $LOG_FILE"] -- GitLab From 165c1add493121193b3131ff4a76879b438d427f Mon Sep 17 00:00:00 2001 From: Andreas Tsagkaropoulos Date: Fri, 25 Aug 2023 11:27:41 +0300 Subject: [PATCH 07/16] Introduction of modifiable severity threshold for proactive adaptation --- .../src/main/java/configuration/Constants.java | 1 + .../src/main/java/runtime/Main.java | 10 +++++++--- .../eu.morphemic.slo_violation_detector.properties | 1 + 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/morphemic-slo-severity-calculator/src/main/java/configuration/Constants.java b/morphemic-slo-severity-calculator/src/main/java/configuration/Constants.java index c8c7789c..cc850ada 100644 --- a/morphemic-slo-severity-calculator/src/main/java/configuration/Constants.java +++ b/morphemic-slo-severity-calculator/src/main/java/configuration/Constants.java @@ -36,6 +36,7 @@ public class Constants { public static String configuration_file_location = "src/main/resources/config/eu.morphemic.slo_violation_detector.properties"; public static String amq_library_configuration_location = "src/main/resources/config/eu.melodic.event.brokerclient.properties"; public static String topic_for_severity_announcement = "prediction.slo_severity_value"; + public static double slo_violation_probability_threshold = 0.5; //The threshold over which the probability of a predicted slo violation should be to have a violation detection public static int kept_values_per_metric = 5; //Default to be overriden from the configuration file. This indicates how many metric values are kept to calculate the "previous" metric value during the rate of change calculation public static String roc_calculation_mode = "prototype"; public static boolean self_publish_rule_file = false; //default value to be overriden diff --git a/morphemic-slo-severity-calculator/src/main/java/runtime/Main.java b/morphemic-slo-severity-calculator/src/main/java/runtime/Main.java index 47f858c9..87d2ff97 100644 --- a/morphemic-slo-severity-calculator/src/main/java/runtime/Main.java +++ b/morphemic-slo-severity-calculator/src/main/java/runtime/Main.java @@ -14,7 +14,6 @@ import metric_retrieval.AttributeSubscription; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; -import org.json.simple.parser.ParseException; import slo_processing.SLORule; import slo_processing.SLOSubRule; import utilities.MathUtils; @@ -91,6 +90,7 @@ public class Main { single_slo_rule_active = Boolean.parseBoolean(prop.getProperty("single_slo_rule_active")); time_horizon_seconds = Integer.parseInt(prop.getProperty("time_horizon_seconds")); + slo_violation_probability_threshold = Double.parseDouble(prop.getProperty("slo_violation_probability_threshold")); slo_violation_determination_method = prop.getProperty("slo_violation_determination_method"); maximum_acceptable_forward_predictions = Integer.parseInt(prop.getProperty("maximum_acceptable_forward_predictions")); ArrayList unbounded_metric_strings = new ArrayList(Arrays.asList(prop.getProperty("metrics_bounds").split(","))); @@ -570,9 +570,9 @@ public class Main { double rule_severity = process_rule_value(rule.getRule_representation(), targeted_prediction_time, rule.getRule_format()); double slo_violation_probability = determine_slo_violation_probability(rule_severity); Logger.getAnonymousLogger().log(info_logging_level, "The overall " + slo_violation_determination_method + " severity - calculated from real data - for adaptation time " + targeted_prediction_time + " ( " + (new Date((new Timestamp(targeted_prediction_time * 1000)).getTime())) + " ) is " + rule_severity + " and is calculated " + time_horizon_seconds + " seconds beforehand"); - Logger.getAnonymousLogger().log(info_logging_level, "The probability of an SLO violation is " + ((int) (slo_violation_probability * 100)) + "%" + (slo_violation_probability<0.5?" so it will not be published":" and it will be published")); + Logger.getAnonymousLogger().log(info_logging_level, "The probability of an SLO violation is " + ((int) (slo_violation_probability * 100)) + "%" + (slo_violation_probability< slo_violation_probability_threshold ?" so it will not be published":" and it will be published")); - if (slo_violation_probability>=0.5) { + if (slo_violation_probability>= slo_violation_probability_threshold) { JSONObject severity_json = new JSONObject(); severity_json.put("severity", rule_severity); severity_json.put("probability", slo_violation_probability); @@ -666,12 +666,16 @@ public class Main { public static double determine_slo_violation_probability(double rule_severity) { if (slo_violation_determination_method.equals("all-metrics")) { //39.64 is the mean severity value when examining all integer severity values for roc x probability x confidence_interval x delta_value in (-100,100)x(0,100)x(0,100)x(-100,100) + /* if (rule_severity >= 40) { return Math.min((50 + 50*(rule_severity - 40) / 60)/100,1); // in case we desire the probability to start from 50% // return Math.min((100*(rule_severity - 40) / 60)/100,1); // in case we desire the probability to start from 0% } else { return 0; } + + */ + return Math.min(rule_severity/100,100); }else if (slo_violation_determination_method.equals("prconf-delta")){ //Logger.getAnonymousLogger().log(warning_logging_level,"The calculation of probability for the prconf-delta method needs to be implemented"); //return 0; diff --git a/morphemic-slo-severity-calculator/src/main/resources/config/eu.morphemic.slo_violation_detector.properties b/morphemic-slo-severity-calculator/src/main/resources/config/eu.morphemic.slo_violation_detector.properties index 917e6caf..4891a40b 100644 --- a/morphemic-slo-severity-calculator/src/main/resources/config/eu.morphemic.slo_violation_detector.properties +++ b/morphemic-slo-severity-calculator/src/main/resources/config/eu.morphemic.slo_violation_detector.properties @@ -8,6 +8,7 @@ broker_ip_url = tcp://localhost:61616?wireFormat.maxInactivityDuration=0 broker_username = morphemic broker_password = morphemic +slo_violation_probability_threshold = 0.1 slo_violation_determination_method = prconf-delta time_horizon_seconds = 120 maximum_acceptable_forward_predictions = 30 \ No newline at end of file -- GitLab From 803699e91494d551c7cd7a88fe7d5b64e16b4cd7 Mon Sep 17 00:00:00 2001 From: Andreas Tsagkaropoulos Date: Sat, 26 Aug 2023 00:59:19 +0300 Subject: [PATCH 08/16] Handling of the case of 'unequal' constraint Improvement of the documentation of the rule id assignment in the case of newer-format rules --- .../src/main/java/slo_processing/SLORule.java | 43 +++++++++++++++++-- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/morphemic-slo-severity-calculator/src/main/java/slo_processing/SLORule.java b/morphemic-slo-severity-calculator/src/main/java/slo_processing/SLORule.java index 0b5a8338..3ce4249c 100644 --- a/morphemic-slo-severity-calculator/src/main/java/slo_processing/SLORule.java +++ b/morphemic-slo-severity-calculator/src/main/java/slo_processing/SLORule.java @@ -90,7 +90,12 @@ public class SLORule { } else { String attribute = (String) rule_json.get("attribute"); String threshold = (String) rule_json.get("threshold"); - subrules.add(new SLOSubRule(attribute, rule_operator, Double.parseDouble(threshold), Integer.parseInt(rule_id))); + if (rule_operator.equals("<>")) { + subrules.add(new SLOSubRule(attribute, "<", Double.parseDouble(threshold), Integer.parseInt(rule_id))); + subrules.add(new SLOSubRule(attribute, ">", Double.parseDouble(threshold), Integer.parseInt(rule_id)+1000000)); //assuming that there are less than 1000000 subrules + } else { + subrules.add(new SLOSubRule(attribute, rule_operator, Double.parseDouble(threshold), Integer.parseInt(rule_id))); + } } } //newer format @@ -104,14 +109,19 @@ public class SLORule { } else { String attribute = (String) rule_json.get("metric"); Double threshold = (Double) rule_json.get("threshold"); - subrules.add(new SLOSubRule(attribute, rule_operator, threshold,get_id_for(attribute))); + if (is_composite_rule_from_threshold_operator(rule_operator)) { + subrules.add(new SLOSubRule(attribute, ">", threshold,get_id_for(attribute))); + subrules.add(new SLOSubRule(attribute, "<", threshold,get_id_for(attribute))); //TODO perhaps here change the id + }else{ + subrules.add(new SLOSubRule(attribute, rule_operator, threshold,get_id_for(attribute))); + } } } return subrules; } /** - *This method is used to create a mapping between attribute names and id's in the case of 'newer' format SLO definitions + *This method is used to assign id's to attribute names and create a mapping between them, in the case of 'newer' format SLO definitions * @param attribute The name of the monitoring metric (attribute) for which the rule is formulated * @return An Integer identifier */ @@ -128,9 +138,11 @@ public class SLORule { String rule_id = (String)rule_json.get("id"); String rule_operator = (String)rule_json.get("operator"); String rule_metric = (String)rule_json.get("metric"); + String rule_threshold = (String)rule_json.get("threshold"); JSONArray subrules_json_array = new JSONArray(); boolean composite_rule = false; + boolean special_operator_subrule = false; //older format if ((rule_format.equals(SLOFormatVersion.older)) && is_composite_rule_from_id(rule_id)) { subrules_json_array = (JSONArray) rule_json.get(rule_id); @@ -141,6 +153,24 @@ public class SLORule { subrules_json_array = (JSONArray) rule_json.get("constraints"); composite_rule = true; } + else if (is_composite_rule_from_threshold_operator(rule_operator)){ + subrules_json_array = new JSONArray(); + composite_rule = true; + special_operator_subrule = true; + // operator, metric, name (unnecessary), threshold + //create simple json object for the two deterministic subrules (the greater-than and the less-than) + JSONObject first_simple_subrule_json = new JSONObject(); + JSONObject second_simple_subrule_json = new JSONObject(); + first_simple_subrule_json.put("operator",">"); + first_simple_subrule_json.put("threshold",rule_threshold); + first_simple_subrule_json.put("metric",rule_metric); + second_simple_subrule_json.put("operator","<"); + second_simple_subrule_json.put("threshold",rule_threshold); + second_simple_subrule_json.put("metric",rule_metric); + subrules_json_array.add(first_simple_subrule_json); + subrules_json_array.add(second_simple_subrule_json); + //subrules_json_array.add + } if (composite_rule){ ArrayList individual_severity_contributions = new ArrayList<>(); boolean and_subrules_invalidated = false; @@ -154,6 +184,9 @@ public class SLORule { }else if (rule_format.equals(SLOFormatVersion.newer)){ logical_operator = rule_operator.toLowerCase(); } + if (special_operator_subrule){ + logical_operator = "or"; + } if (logical_operator.equals("and")){ if (subrule_result<0){ //return -1; //all other rules are invalidated @@ -222,6 +255,10 @@ public class SLORule { return (!operator.isEmpty() && Arrays.stream(logic_operators).anyMatch(e-> e.equals(lowercase_operator))); } + private static boolean is_composite_rule_from_threshold_operator (String operator){ + return operator.equals("<>"); + } + private static String get_logical_operator_part(String rule_id) { return rule_id.split("-")[0]; //possibly contains the name of a logical operator } -- GitLab From 704a8d5da8ee2fc1bf005c231f3655f1b871651b Mon Sep 17 00:00:00 2001 From: Andreas Tsagkaropoulos Date: Mon, 28 Aug 2023 15:52:45 +0300 Subject: [PATCH 09/16] Correction in the parsing of a json field in the incoming rule json Generalization of unbounded test structure Introduction of a new unbounded monitoring attribute test for an attribute having the unequal constraint --- .../src/main/java/slo_processing/SLORule.java | 2 +- .../UnboundedMonitoringAttributeTests.java | 24 +++++++++++-------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/morphemic-slo-severity-calculator/src/main/java/slo_processing/SLORule.java b/morphemic-slo-severity-calculator/src/main/java/slo_processing/SLORule.java index 3ce4249c..f7c6f400 100644 --- a/morphemic-slo-severity-calculator/src/main/java/slo_processing/SLORule.java +++ b/morphemic-slo-severity-calculator/src/main/java/slo_processing/SLORule.java @@ -138,7 +138,7 @@ public class SLORule { String rule_id = (String)rule_json.get("id"); String rule_operator = (String)rule_json.get("operator"); String rule_metric = (String)rule_json.get("metric"); - String rule_threshold = (String)rule_json.get("threshold"); + Double rule_threshold = (Double)rule_json.get("threshold"); JSONArray subrules_json_array = new JSONArray(); boolean composite_rule = false; diff --git a/morphemic-slo-severity-calculator/src/test/java/UnboundedMonitoringAttributeTests.java b/morphemic-slo-severity-calculator/src/test/java/UnboundedMonitoringAttributeTests.java index f9da72a5..d9be7f41 100644 --- a/morphemic-slo-severity-calculator/src/test/java/UnboundedMonitoringAttributeTests.java +++ b/morphemic-slo-severity-calculator/src/test/java/UnboundedMonitoringAttributeTests.java @@ -63,7 +63,7 @@ class MetricConfiguration{ public class UnboundedMonitoringAttributeTests { /** - * This 30-second test assumes the availability of a broker, which is configured in the standard configuration file location employed by the Main method. It also assumes that random input of a custom metric centered around 75 is provided (using an independent data provider). Based on this constant input, the standard deviation and mean is calculated, and the lower/upper bounds are estimated - it is assumed that the metric is upwards and downwards unbounded. The assertions of the test are estimations based on repeated iterations with 100-sample data. + * This 30-second test assumes the availability of a broker, which is configured in the standard configuration file location employed by the Main method. It also assumes that random input of a custom metric centered around a value (75 for the first test) is provided (using an independent data provider). Based on this constant input, the standard deviation and mean is calculated, and the lower/upper bounds are estimated - in the case of the first test it is assumed that the metric is upwards and downwards unbounded. The assertions of the test are estimations based on repeated iterations with 100-sample data. */ //private String metric_1_name = "custom_metric_1"; @@ -71,11 +71,15 @@ public class UnboundedMonitoringAttributeTests { @Test public void unbounded_monitoring_attribute_test_1() throws IOException, ParseException { - unbounded_monitoring_attribute_test_core("src/main/resources/test_v3_custom_metric_1_simple.json","custom_metric_1",new Double[]{20.0,35.0},new Double[]{110.0,130.0},0.0); + unbounded_monitoring_attribute_test_core("src/main/resources/test_v3_custom_metric_1_simple.json","custom_metric_1",new Double[]{20.0,35.0},new Double[]{110.0,130.0},0.0,50,100, 90,10,0.80); + } + @Test + public void unbounded_monitoring_attribute_test_2() throws IOException, ParseException { + unbounded_monitoring_attribute_test_core("src/main/resources/test_v3_custom_metric_unequal.json","number_of_users",new Double[]{-50.0,0.0},new Double[]{0.0,50.0},0.0,-25,20,5,0.3,0.90); } - public void unbounded_monitoring_attribute_test_core(String json_file_name, String metric_1_name, Double[] metric_lower_bound_range, Double[] metric_upper_bound_range, Double severity_lower_bound) throws IOException, ParseException { + public void unbounded_monitoring_attribute_test_core(String json_file_name, String metric_1_name, Double[] metric_lower_bound_range, Double[] metric_upper_bound_range, double severity_lower_bound, double base_metric_value, double metric_max_value, double forecasted_metric_value,double generated_data_confidence_interval, double probability) throws IOException, ParseException { Main.can_modify_slo_rules.setValue(true); Properties prop = new Properties(); @@ -105,7 +109,7 @@ public class UnboundedMonitoringAttributeTests { slo_rules.add(slo_rule); initialize_subrule_and_attribute_associations(slo_rules); - data_publisher_for_unbounded_test_1(metric_1_name); + data_publisher_for_unbounded_test(metric_1_name, metric_max_value, base_metric_value,forecasted_metric_value,generated_data_confidence_interval,probability); ArrayList running = new ArrayList<>(); for (String metric_name : metric_names) { @@ -141,7 +145,7 @@ public class UnboundedMonitoringAttributeTests { HashMap> predicted_attributes = getPredicted_monitoring_attributes(); try { double forecasted_value = ((Number)((JSONObject)new JSONParser().parse(message)).get(EventFields.PredictionMetricEventFields.metric_value)).doubleValue(); - double probability_confidence = ((Number)((JSONObject)new JSONParser().parse(message)).get(EventFields.PredictionMetricEventFields.probability)).doubleValue(); + double probability_confidence = 100*((Number)((JSONObject)new JSONParser().parse(message)).get(EventFields.PredictionMetricEventFields.probability)).doubleValue(); //double confidence_interval = ((Number)((JSONObject)new JSONParser().parse(message)).get(EventFields.PredictionMetricEventFields.confidence_interval)).doubleValue(); JSONArray json_array_confidence_interval = ((JSONArray)((JSONObject)new JSONParser().parse(message)).get(EventFields.PredictionMetricEventFields.confidence_interval)); double confidence_interval = ((Number)json_array_confidence_interval.get(1)).doubleValue() - ((Number)json_array_confidence_interval.get(0)).doubleValue(); @@ -220,10 +224,10 @@ public class UnboundedMonitoringAttributeTests { } - public void data_publisher_for_unbounded_test_1(String metric_name){ + public void data_publisher_for_unbounded_test(String metric_name, double metric_max_value, double base_metric_value, double forecasted_metric_value, double confidence_interval, double probability ){ int publish_interval_in_milliseconds = 100; - MetricConfiguration custom_metric_1 = new MetricConfiguration(metric_name,50,90,10,0.80); + MetricConfiguration custom_metric_1 = new MetricConfiguration(metric_name,base_metric_value,forecasted_metric_value,confidence_interval,probability); //MetricConfiguration ram_metric = new MetricConfiguration("ram",90,100,5,100); @@ -232,13 +236,13 @@ public class UnboundedMonitoringAttributeTests { for (MetricConfiguration metric: metrics) { Thread publishing_thread = new Thread(() -> { - perpetual_metric_publisher(metric.name,metric.base_metric_value,metric.forecasted_metric_value,metric.confidence_interval,metric.probability,publish_interval_in_milliseconds); + perpetual_metric_publisher(metric.name,metric.base_metric_value,metric.forecasted_metric_value,metric.confidence_interval,metric.probability, metric_max_value, publish_interval_in_milliseconds); }); publishing_thread.start(); } } - private static void perpetual_metric_publisher(String metric_name, double base_metric_value, double forecasted_metric_value, double confidence_interval, double probability, int publish_interval_in_milliseconds) { + private static void perpetual_metric_publisher(String metric_name, double base_metric_value, double forecasted_metric_value, double confidence_interval, double probability, double metric_max_value, int publish_interval_in_milliseconds) { BrokerPublisher realtime_data_publisher = new BrokerPublisher(metric_name, "tcp://localhost:61616", "admin", "admin","src/main/resources/config/eu.melodic.event.brokerclient.properties"); BrokerPublisher forecasted_data_publisher = new BrokerPublisher("prediction."+metric_name, "tcp://localhost:61616", "admin", "admin","src/main/resources/config/eu.melodic.event.brokerclient.properties"); @@ -247,7 +251,7 @@ public class UnboundedMonitoringAttributeTests { JSONObject realtime_metric_json_object = new JSONObject(); //Create values centered around 82.5 double random_value = ThreadLocalRandom.current().nextDouble(); - realtime_metric_json_object.put("metricValue", base_metric_value+random_value*(100-base_metric_value)); + realtime_metric_json_object.put("metricValue", base_metric_value+random_value*(metric_max_value-base_metric_value)); realtime_metric_json_object.put("timestamp",System.currentTimeMillis()); realtime_data_publisher.publish(realtime_metric_json_object.toJSONString()); -- GitLab From 7676d568d15081c044cf9fc19f181fcf61cf9041 Mon Sep 17 00:00:00 2001 From: Andreas Tsagkaropoulos Date: Mon, 28 Aug 2023 18:46:19 +0300 Subject: [PATCH 10/16] Simultaneous calculation of rate of change and delta for greater-than and less-than rules, and miscellaneous code changes to support this. --- .../src/main/java/slo_processing/SLORule.java | 8 +- .../utilities/SLOViolationCalculator.java | 57 ++++++++--- .../PredictedMonitoringAttribute.java | 94 +++++++++++-------- .../java/DerivedMonitoringAttributeTests.java | 2 +- .../src/test/java/SeverityTests.java | 18 ++-- 5 files changed, 115 insertions(+), 64 deletions(-) diff --git a/morphemic-slo-severity-calculator/src/main/java/slo_processing/SLORule.java b/morphemic-slo-severity-calculator/src/main/java/slo_processing/SLORule.java index f7c6f400..460a0823 100644 --- a/morphemic-slo-severity-calculator/src/main/java/slo_processing/SLORule.java +++ b/morphemic-slo-severity-calculator/src/main/java/slo_processing/SLORule.java @@ -217,7 +217,7 @@ public class SLORule { else{ //String attribute_name = (String) rule_json.get("attribute"); //String operator = (String) rule_json.get("operator"); - //boolean greater_than_rule = operator.equals(">") || operator.equals(">="); + boolean is_greater_than_rule = rule_operator.equals(">") || rule_operator.equals(">="); //double threshold = Double.parseDouble((String) rule_json.get("threshold")); Integer subrule_id=0; if (rule_format.equals(SLOFormatVersion.older)) { @@ -231,14 +231,14 @@ public class SLORule { } PredictedMonitoringAttribute new_prediction_attribute = getPredicted_monitoring_attributes().get(subrule_id).get(targeted_prediction_time); - if (new_prediction_attribute==null || !new_prediction_attribute.isInitialized() || new_prediction_attribute.getDelta()threshold){ - this.delta = 100*(forecasted_value - threshold)/(getMonitoring_attributes_statistics().get(name).getUpper_bound()-threshold); - }else /*if (getMonitoring_attributes_statistics().get(name).getUpper_bound()<=threshold)*/{ - if (forecasted_value>threshold){ - this.delta = 100; - }else if (forecasted_value==threshold){ - this.delta = 0; - }else{ - this.delta = -100; - } + this.rate_of_change_for_greater_than_rule = getRateOfChange(forecasted_value, current_value,name); + this.rate_of_change_for_less_than_rule = -this.rate_of_change_for_greater_than_rule; //inversion necessary, as when a rate of change is positive, it means that the metric is increasing and thus not directed towards the interval in which a less-than rule is fired. + + //Calculations for greater_than rule delta metric + + if(getMonitoring_attributes_statistics().get(name).getUpper_bound()>threshold){ + this.delta_for_greater_than_rule = 100*(forecasted_value - threshold)/(getMonitoring_attributes_statistics().get(name).getUpper_bound()-threshold); + }else /*if (getMonitoring_attributes_statistics().get(name).getUpper_bound()<=threshold)*/{ + if (forecasted_value>threshold){ + this.delta_for_greater_than_rule = 100; + }else if (forecasted_value==threshold){ + this.delta_for_greater_than_rule = 0; + }else{ + this.delta_for_greater_than_rule = -100; } + } + this.delta_for_greater_than_rule = Math.min(Math.max(this.delta_for_greater_than_rule,-100),100); + //this.previous_delta = 100*Math.abs(current_value - threshold)/(getMonitoring_attributes_statistics().get(name).getUpper_bound()-threshold); - //this.previous_delta = 100*Math.abs(current_value - threshold)/(getMonitoring_attributes_statistics().get(name).getUpper_bound()-threshold); - }else{ - this.rate_of_change = -this.rate_of_change; //inversion necessary, as when a rate of change is positive, it means that the metric is increasing and thus not directed towards the interval in which a less-than rule is fired. + //Calculations for less_than rule delta metric - if(threshold>getMonitoring_attributes_statistics().get(name).getLower_bound()) { + if(threshold>getMonitoring_attributes_statistics().get(name).getLower_bound()) { - this.delta = 100 * (threshold - forecasted_value) / (threshold - getMonitoring_attributes_statistics().get(name).getLower_bound()); + this.delta_for_less_than_rule = 100 * (threshold - forecasted_value) / (threshold - getMonitoring_attributes_statistics().get(name).getLower_bound()); - //this.previous_delta = 100*Math.abs(current_value-threshold)/(threshold-getMonitoring_attributes_statistics().get(name).getLower_bound()); + //this.previous_delta = 100*Math.abs(current_value-threshold)/(threshold-getMonitoring_attributes_statistics().get(name).getLower_bound()); + }else{ + if (threshold>forecasted_value){ + this.delta_for_less_than_rule = 100; + }else if (threshold==forecasted_value){ + this.delta_for_less_than_rule = 0; }else{ - if (threshold>forecasted_value){ - this.delta = 100; - }else if (threshold==forecasted_value){ - this.delta = 0; - }else{ - this.delta = -100; - } + this.delta_for_less_than_rule = -100; } - - //this.previous_delta = 100*Math.abs(current_value-threshold)/(threshold-getMonitoring_attributes_statistics().get(name).getLower_bound()); } - this.delta = Math.min(Math.max(this.delta,-100),100); + this.delta_for_less_than_rule = Math.min(Math.max(this.delta_for_less_than_rule,-100),100); + //this.previous_delta = 100*Math.abs(current_value-threshold)/(threshold-getMonitoring_attributes_statistics().get(name).getLower_bound()); + this.probability_confidence = probability_confidence; this.confidence_interval_width = confidence_interval_width; //actual_metric_values = get_last_n_actual_values(Constants.elements_considered_in_prediction, MonitoringAttribute.get_monitoring_attributes_values_map().get(name),true); @@ -201,14 +204,20 @@ public class PredictedMonitoringAttribute { return new_values; } - public double getDelta() { - return delta; + public double getDelta_for_greater_than_rule() { + return delta_for_greater_than_rule; + } + public double getDelta_for_less_than_rule() { + return delta_for_less_than_rule; } - public void setDelta(double delta) { - this.delta = delta; + public void setDelta_for_greater_than_rule(double delta) { + this.delta_for_greater_than_rule = delta_for_greater_than_rule; } + public void setDelta_for_less_than_rule(double delta) { + this.delta_for_less_than_rule = delta_for_less_than_rule; + } public double getThreshold() { return threshold; } @@ -217,12 +226,19 @@ public class PredictedMonitoringAttribute { this.threshold = threshold; } - public double getRate_of_change() { - return rate_of_change; + public double getRate_of_change_for_greater_than_rule() { + return rate_of_change_for_greater_than_rule; + } + public double getRate_of_change_for_less_than_rule() { + return rate_of_change_for_less_than_rule; + } + + public void setRate_of_change_for_greater_than_rule(double rate_of_change_for_greater_than_rule) { + this.rate_of_change_for_greater_than_rule = rate_of_change_for_greater_than_rule; } - public void setRate_of_change(double rate_of_change) { - this.rate_of_change = rate_of_change; + public void setRate_of_change_for_less_than_rule(double rate_of_change_for_less_than_rule) { + this.rate_of_change_for_less_than_rule = rate_of_change_for_less_than_rule; } public double getProbability_confidence() { diff --git a/morphemic-slo-severity-calculator/src/test/java/DerivedMonitoringAttributeTests.java b/morphemic-slo-severity-calculator/src/test/java/DerivedMonitoringAttributeTests.java index 81c5aeb4..295d5508 100644 --- a/morphemic-slo-severity-calculator/src/test/java/DerivedMonitoringAttributeTests.java +++ b/morphemic-slo-severity-calculator/src/test/java/DerivedMonitoringAttributeTests.java @@ -32,6 +32,6 @@ public class DerivedMonitoringAttributeTests { PredictedMonitoringAttribute prediction_attribute = new PredictedMonitoringAttribute("cpu",true,70,1,100.0,100,1,System.currentTimeMillis(),System.currentTimeMillis()+20000); - assert prediction_attribute.getRate_of_change() == 100.0; + assert prediction_attribute.getRate_of_change_for_greater_than_rule() == 100.0; } } diff --git a/morphemic-slo-severity-calculator/src/test/java/SeverityTests.java b/morphemic-slo-severity-calculator/src/test/java/SeverityTests.java index aeff7ea8..feac8819 100644 --- a/morphemic-slo-severity-calculator/src/test/java/SeverityTests.java +++ b/morphemic-slo-severity-calculator/src/test/java/SeverityTests.java @@ -35,11 +35,11 @@ public class SeverityTests { PredictedMonitoringAttribute prediction_attribute = new PredictedMonitoringAttribute("cpu",true,70,1,100.0,100,10,System.currentTimeMillis(),System.currentTimeMillis()+20000); - assert (prediction_attribute.getRate_of_change() < 100.0000000001 && prediction_attribute.getRate_of_change()>99.9999999999); //maximum value + assert (prediction_attribute.getRate_of_change_for_greater_than_rule() < 100.0000000001 && prediction_attribute.getRate_of_change_for_greater_than_rule()>99.9999999999); //maximum value assert (prediction_attribute.getConfidence_interval_width() <10.000000000001 && prediction_attribute.getConfidence_interval_width()>9.9999999999); assert(prediction_attribute.getProbability_confidence()<100.0000000001 && prediction_attribute.getProbability_confidence()>99.99999999); - assert(prediction_attribute.getDelta()<100.0000000001 && prediction_attribute.getDelta()>99.99999999); - assert Math.floor(SLOViolationCalculator.get_Severity_all_metrics_method(prediction_attribute)*100) == 9678; + assert(prediction_attribute.getDelta_for_greater_than_rule()<100.0000000001 && prediction_attribute.getDelta_for_greater_than_rule()>99.99999999); + assert Math.floor(SLOViolationCalculator.get_Severity_all_metrics_method(prediction_attribute,true)*100) == 9678; } @Test @@ -60,11 +60,11 @@ public class SeverityTests { PredictedMonitoringAttribute prediction_attribute = new PredictedMonitoringAttribute("cpu",true,70,1,80.0,90,5,System.currentTimeMillis(),System.currentTimeMillis()+20000); - assert (prediction_attribute.getRate_of_change() > 99.99999999 && prediction_attribute.getRate_of_change()< 100.00000001); //zero value + assert (prediction_attribute.getRate_of_change_for_greater_than_rule() > 99.99999999 && prediction_attribute.getRate_of_change_for_greater_than_rule()< 100.00000001); //zero value assert (prediction_attribute.getConfidence_interval_width() <5.000000000001 && prediction_attribute.getConfidence_interval_width()>4.9999999999); assert (prediction_attribute.getProbability_confidence()<90.0000000001 && prediction_attribute.getProbability_confidence()>89.99999999); - assert (prediction_attribute.getDelta()<33.3333333334 && prediction_attribute.getDelta()>33.3333333332); - assert Math.floor(SLOViolationCalculator.get_Severity_all_metrics_method(prediction_attribute)*100) == 7836; + assert (prediction_attribute.getDelta_for_greater_than_rule()<33.3333333334 && prediction_attribute.getDelta_for_greater_than_rule()>33.3333333332); + assert Math.floor(SLOViolationCalculator.get_Severity_all_metrics_method(prediction_attribute,true)*100) == 7836; } @Test @@ -85,11 +85,11 @@ public class SeverityTests { PredictedMonitoringAttribute prediction_attribute = new PredictedMonitoringAttribute("cpu",true,75,1,92.0,88,7.8,System.currentTimeMillis(),System.currentTimeMillis()+20000); - assert (prediction_attribute.getRate_of_change()> 6.97674418604 && prediction_attribute.getRate_of_change()< 6.97674418605 ); //zero value + assert (prediction_attribute.getRate_of_change_for_greater_than_rule()> 6.97674418604 && prediction_attribute.getRate_of_change_for_greater_than_rule()< 6.97674418605 ); //zero value assert (prediction_attribute.getConfidence_interval_width() >7.7999999 && prediction_attribute.getConfidence_interval_width()<7.8000001); assert (prediction_attribute.getProbability_confidence()<88.0000000001 && prediction_attribute.getProbability_confidence()>87.99999999); - assert (prediction_attribute.getDelta()<68.0000000001 && prediction_attribute.getDelta()>67.99999999); - assert Math.floor(SLOViolationCalculator.get_Severity_all_metrics_method(prediction_attribute)*100) == 6125; + assert (prediction_attribute.getDelta_for_greater_than_rule()<68.0000000001 && prediction_attribute.getDelta_for_greater_than_rule()>67.99999999); + assert Math.floor(SLOViolationCalculator.get_Severity_all_metrics_method(prediction_attribute,true)*100) == 6125; } -- GitLab From 9ad2da0072c5a1093bd21b4811e842ee13111917 Mon Sep 17 00:00:00 2001 From: Andreas Tsagkaropoulos Date: Tue, 29 Aug 2023 14:40:01 +0300 Subject: [PATCH 11/16] Addition of two python libraries which are necessary for the exponential smoothing predictor to function correctly --- morphemic-forecasting-exponentialsmoothing/src/requirements.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/morphemic-forecasting-exponentialsmoothing/src/requirements.txt b/morphemic-forecasting-exponentialsmoothing/src/requirements.txt index 2bc1ae39..97acd300 100644 --- a/morphemic-forecasting-exponentialsmoothing/src/requirements.txt +++ b/morphemic-forecasting-exponentialsmoothing/src/requirements.txt @@ -1,3 +1,5 @@ stomp.py==6.1.0 python-slugify jproperties +influxdb +pandas \ No newline at end of file -- GitLab From 644f1c83f95a6b5aeb58de04e3035a5efa763ae9 Mon Sep 17 00:00:00 2001 From: Andreas Tsagkaropoulos Date: Tue, 29 Aug 2023 14:44:25 +0300 Subject: [PATCH 12/16] Addition of two python libraries which are necessary for the exponential smoothing predictor to function correctly --- .../src/requirements.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/morphemic-forecasting-exponentialsmoothing/src/requirements.txt b/morphemic-forecasting-exponentialsmoothing/src/requirements.txt index 26f28a6f..342c42d9 100644 --- a/morphemic-forecasting-exponentialsmoothing/src/requirements.txt +++ b/morphemic-forecasting-exponentialsmoothing/src/requirements.txt @@ -3,4 +3,6 @@ python-slugify jproperties requests msgpack -numpy \ No newline at end of file +numpy +pandas +influxdb \ No newline at end of file -- GitLab From f9383d5f19ac71a13d5f1e8589a58dfa43b22f18 Mon Sep 17 00:00:00 2001 From: Andreas Tsagkaropoulos Date: Thu, 31 Aug 2023 01:52:48 +0300 Subject: [PATCH 13/16] Fix of data parsing for the case that NaN output is produced for a particular metric Introduction of new DebugDataSubscription class which should allow the remote gathering of realtime debugging information of the component --- morphemic-slo-severity-calculator/Dockerfile | 2 +- .../AttributeSubscription.java | 8 +- .../src/main/java/runtime/Main.java | 2 + .../main/java/slo_processing/SLOSubRule.java | 5 + .../java/utilities/DebugDataSubscription.java | 95 +++++++++++++++++++ .../PredictedMonitoringAttribute.java | 8 ++ 6 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 morphemic-slo-severity-calculator/src/main/java/utilities/DebugDataSubscription.java diff --git a/morphemic-slo-severity-calculator/Dockerfile b/morphemic-slo-severity-calculator/Dockerfile index ce4c31c2..e60b40f0 100644 --- a/morphemic-slo-severity-calculator/Dockerfile +++ b/morphemic-slo-severity-calculator/Dockerfile @@ -9,4 +9,4 @@ COPY src/main/resources/config/eu.morphemic.slo_violation_detector.properties /h COPY src/main/resources/config/eu.melodic.event.brokerclient.properties /home/src/main/resources/config/eu.melodic.event.brokerclient.properties COPY target/SLOSeverityCalculator-4.0-SNAPSHOT.jar /home/SLOSeverityCalculator-4.0-SNAPSHOT.jar WORKDIR /home -CMD ["/bin/sh","-c","java -jar SLOSeverityCalculator-4.0-SNAPSHOT.jar 2>&1 > $LOG_FILE"] +CMD ["/bin/sh","-c","java -jar SLOSeverityCalculator-4.0-SNAPSHOT.jar > $LOG_FILE 2>&1"] diff --git a/morphemic-slo-severity-calculator/src/main/java/metric_retrieval/AttributeSubscription.java b/morphemic-slo-severity-calculator/src/main/java/metric_retrieval/AttributeSubscription.java index 19522878..5398fcaf 100644 --- a/morphemic-slo-severity-calculator/src/main/java/metric_retrieval/AttributeSubscription.java +++ b/morphemic-slo-severity-calculator/src/main/java/metric_retrieval/AttributeSubscription.java @@ -87,7 +87,13 @@ public class AttributeSubscription { double forecasted_value = ((Number)((JSONObject)new JSONParser().parse(message)).get(EventFields.PredictionMetricEventFields.metric_value)).doubleValue(); double probability_confidence = 100*((Number)((JSONObject)new JSONParser().parse(message)).get(EventFields.PredictionMetricEventFields.probability)).doubleValue(); JSONArray json_array_confidence_interval = ((JSONArray)((JSONObject)new JSONParser().parse(message)).get(EventFields.PredictionMetricEventFields.confidence_interval)); - double confidence_interval = ((Number)json_array_confidence_interval.get(1)).doubleValue() - ((Number)json_array_confidence_interval.get(0)).doubleValue(); + + double confidence_interval; + if (((String)json_array_confidence_interval.get(1)).toLowerCase().equals("nan")){ + confidence_interval = Double.NEGATIVE_INFINITY; + }else { + confidence_interval = ((Number) json_array_confidence_interval.get(1)).doubleValue() - ((Number) json_array_confidence_interval.get(0)).doubleValue(); + } long timestamp = ((Number)((JSONObject)new JSONParser().parse(message)).get(EventFields.PredictionMetricEventFields.timestamp)).longValue(); long targeted_prediction_time = ((Number)((JSONObject)new JSONParser().parse(message)).get(EventFields.PredictionMetricEventFields.prediction_time)).longValue(); Logger.getAnonymousLogger().log(info_logging_level,"RECEIVED message with predicted value for "+predicted_attribute_name+" equal to "+ forecasted_value); diff --git a/morphemic-slo-severity-calculator/src/main/java/runtime/Main.java b/morphemic-slo-severity-calculator/src/main/java/runtime/Main.java index 87d2ff97..7ed0cdc2 100644 --- a/morphemic-slo-severity-calculator/src/main/java/runtime/Main.java +++ b/morphemic-slo-severity-calculator/src/main/java/runtime/Main.java @@ -16,6 +16,7 @@ import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import slo_processing.SLORule; import slo_processing.SLOSubRule; +import utilities.DebugDataSubscription; import utilities.MathUtils; import utility_beans.*; @@ -218,6 +219,7 @@ public class Main { } stop_all_running_threads(); + DebugDataSubscription.initiate(prop.getProperty("broker_ip_url"),prop.getProperty("broker_username"), prop.getProperty("broker_password")); initialize_monitoring_datastructures_with_empty_data(slo_rules); // initialize_subrule_and_attribute_associations(slo_rules); diff --git a/morphemic-slo-severity-calculator/src/main/java/slo_processing/SLOSubRule.java b/morphemic-slo-severity-calculator/src/main/java/slo_processing/SLOSubRule.java index 13ed657e..c5cd5ca4 100644 --- a/morphemic-slo-severity-calculator/src/main/java/slo_processing/SLOSubRule.java +++ b/morphemic-slo-severity-calculator/src/main/java/slo_processing/SLOSubRule.java @@ -61,4 +61,9 @@ public class SLOSubRule { public void setAssociated_predicted_monitoring_attribute(PredictedMonitoringAttribute associated_predicted_monitoring_attribute) { this.associated_predicted_monitoring_attribute = associated_predicted_monitoring_attribute; } + + @Override + public String toString(){ + return ("The rule is "+metric+operator+threshold+"\n+ The associated Predicted Monitoring Attribute is "+associated_predicted_monitoring_attribute.toString()); + } } diff --git a/morphemic-slo-severity-calculator/src/main/java/utilities/DebugDataSubscription.java b/morphemic-slo-severity-calculator/src/main/java/utilities/DebugDataSubscription.java new file mode 100644 index 00000000..ec1989ea --- /dev/null +++ b/morphemic-slo-severity-calculator/src/main/java/utilities/DebugDataSubscription.java @@ -0,0 +1,95 @@ +package utilities; + +import eu.melodic.event.brokerclient.BrokerPublisher; +import eu.melodic.event.brokerclient.BrokerSubscriber; +import org.apache.commons.collections4.queue.CircularFifoQueue; +import runtime.Main; +import slo_processing.SLOSubRule; +import utility_beans.RealtimeMonitoringAttribute; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.function.BiFunction; +import java.util.logging.Logger; + +import static configuration.Constants.amq_library_configuration_location; +import static configuration.Constants.info_logging_level; +import static runtime.Main.running_threads; + +/** + * The objective of this class is to allow a structured synopsis of the current state of the SLO Violation Detector to be created, as a response to a request sent to it through an appropriate topic. + */ +public class DebugDataSubscription { + + private static String debug_data_trigger_topic_name = "sloviolationdetector.debug"; + private static String debug_data_output_topic_name = "sloviolationdetector.debug_output"; + private static String broker_username,broker_password,broker_ip_address; + static BiFunction debug_data_generation = (topic, message) ->{ + + String output_debug_data = ""; + StringBuilder intermediate_debug_string = new StringBuilder(); + intermediate_debug_string = new StringBuilder(intermediate_debug_string + "The following threads are currently running" + "\n"); + + for (String s : running_threads.keySet()){ + intermediate_debug_string.append(",").append(s); + } + output_debug_data = output_debug_data+intermediate_debug_string; + intermediate_debug_string = new StringBuilder(); + + intermediate_debug_string = intermediate_debug_string.append("The following Monitoring Attribute values are currently stored:\n"); + for ( Map.Entry entry :RealtimeMonitoringAttribute.getMonitoring_attributes().entrySet() ){ + intermediate_debug_string.append("Metric name: ").append(entry.getKey()); + Double metric_value = RealtimeMonitoringAttribute.get_metric_value(entry.getKey()); + CircularFifoQueue metric_values = entry.getValue().getActual_metric_values(); + if (metric_value.isNaN()){ + intermediate_debug_string.append(" - value was determined as NaN, individual collected values are ").append(metric_values); + } + else if (metric_value.isInfinite()){ + intermediate_debug_string.append(" - value was determined as infinite, individual collected values are ").append(metric_values); + } else { + intermediate_debug_string.append(" - value from individual values").append(metric_values).append(" is ").append(metric_value); + } + + } + output_debug_data = output_debug_data+intermediate_debug_string; + intermediate_debug_string = new StringBuilder(); + + intermediate_debug_string = intermediate_debug_string.append("The following subrules have been parsed and are stored:\n"); + for (Map.Entry> entry : SLOSubRule.getSlo_subrules_per_monitoring_attribute().entrySet()){ + intermediate_debug_string.append("Metric name: ").append(entry.getKey()); + for (SLOSubRule rule : entry.getValue()) { + intermediate_debug_string.append("\n").append(rule.toString()); + } + } + output_debug_data = output_debug_data+intermediate_debug_string; + Logger.getGlobal().log(info_logging_level,"Debug data generated:\n"+output_debug_data); + BrokerPublisher publisher = new BrokerPublisher(debug_data_output_topic_name, broker_ip_address, broker_username, broker_password, amq_library_configuration_location); + publisher.publish(output_debug_data); + return output_debug_data; + }; + public static void initiate(String broker_ip_address, String broker_username, String broker_password) { + BrokerSubscriber debug_data_subscriber = new BrokerSubscriber(debug_data_trigger_topic_name, broker_ip_address, broker_username, broker_password, amq_library_configuration_location); + Thread debug_data_subscription_thread = new Thread(() -> { + try { + synchronized (Main.HAS_MESSAGE_ARRIVED.get_synchronized_boolean(debug_data_trigger_topic_name)) { + //if (Main.HAS_MESSAGE_ARRIVED.get_synchronized_boolean(debug_data_topic_name).getValue()) + debug_data_subscriber.subscribe(debug_data_generation, Main.stop_signal); + } + if (Thread.interrupted()) { + throw new InterruptedException(); + } + } catch (Exception i) { + Logger.getAnonymousLogger().log(info_logging_level, "Possible interruption of debug data subscriber thread for " + debug_data_trigger_topic_name + " - if not stacktrace follows"); + if (!(i instanceof InterruptedException)) { + i.printStackTrace(); + } + } finally { + Logger.getAnonymousLogger().log(info_logging_level, "Removing debug data subscriber thread for " + debug_data_trigger_topic_name); + running_threads.remove("debug_data_subscription_thread_" + debug_data_trigger_topic_name); + } + }); + running_threads.put("debug_data_subscription_thread_" + debug_data_trigger_topic_name, debug_data_subscription_thread); + debug_data_subscription_thread.start(); + } +} diff --git a/morphemic-slo-severity-calculator/src/main/java/utility_beans/PredictedMonitoringAttribute.java b/morphemic-slo-severity-calculator/src/main/java/utility_beans/PredictedMonitoringAttribute.java index 7c7f5720..9bc6053f 100644 --- a/morphemic-slo-severity-calculator/src/main/java/utility_beans/PredictedMonitoringAttribute.java +++ b/morphemic-slo-severity-calculator/src/main/java/utility_beans/PredictedMonitoringAttribute.java @@ -279,4 +279,12 @@ public class PredictedMonitoringAttribute { public void setTimestamp(long timestamp) { this.timestamp = timestamp; } + + @Override + public String toString(){ + String output = ""; + output="{"+name+" deltas: "+delta_for_greater_than_rule+","+delta_for_less_than_rule+" ROCs: "+rate_of_change_for_greater_than_rule+","+rate_of_change_for_less_than_rule+" PrConf:"+probability_confidence+" Confidence Interval: "+confidence_interval_width+"Prediction Timestamp: "+timestamp+"}"; + return output; + } + } -- GitLab From db46b2cf304616d70e3ab4ac3889e25b672aca38 Mon Sep 17 00:00:00 2001 From: Andreas Tsagkaropoulos Date: Fri, 1 Sep 2023 10:00:45 +0300 Subject: [PATCH 14/16] Handling of Number Format and Class Casting exceptions when parsing messages from the Broker, with a focus on the correct parsing of information in the confidence interval field Fix of a bug which did not allow the registration of new adaptation times which should undergo processing Further enhancement of the debug information, by correcting formatting and including a circular buffer of the most recent SLO Violation events --- .../AttributeSubscription.java | 23 +++++++----- .../src/main/java/runtime/Main.java | 6 ++++ .../java/utilities/DebugDataSubscription.java | 35 +++++++++++++++---- 3 files changed, 49 insertions(+), 15 deletions(-) diff --git a/morphemic-slo-severity-calculator/src/main/java/metric_retrieval/AttributeSubscription.java b/morphemic-slo-severity-calculator/src/main/java/metric_retrieval/AttributeSubscription.java index 5398fcaf..fcf378b2 100644 --- a/morphemic-slo-severity-calculator/src/main/java/metric_retrieval/AttributeSubscription.java +++ b/morphemic-slo-severity-calculator/src/main/java/metric_retrieval/AttributeSubscription.java @@ -89,10 +89,12 @@ public class AttributeSubscription { JSONArray json_array_confidence_interval = ((JSONArray)((JSONObject)new JSONParser().parse(message)).get(EventFields.PredictionMetricEventFields.confidence_interval)); double confidence_interval; - if (((String)json_array_confidence_interval.get(1)).toLowerCase().equals("nan")){ - confidence_interval = Double.NEGATIVE_INFINITY; - }else { + try{ confidence_interval = ((Number) json_array_confidence_interval.get(1)).doubleValue() - ((Number) json_array_confidence_interval.get(0)).doubleValue(); + }catch (ClassCastException | NumberFormatException c){ + Logger.getAnonymousLogger().log(info_logging_level,"Catching exception successfully"); + c.printStackTrace(); + confidence_interval = Double.NEGATIVE_INFINITY; } long timestamp = ((Number)((JSONObject)new JSONParser().parse(message)).get(EventFields.PredictionMetricEventFields.timestamp)).longValue(); long targeted_prediction_time = ((Number)((JSONObject)new JSONParser().parse(message)).get(EventFields.PredictionMetricEventFields.prediction_time)).longValue(); @@ -116,13 +118,16 @@ public class AttributeSubscription { PREDICTION_EXISTS.setValue(true); PREDICTION_EXISTS.notifyAll(); } - }else{ - if(adaptation_times.contains(targeted_prediction_time)){ + }else { + if (adaptation_times.contains(targeted_prediction_time)) { Logger.getAnonymousLogger().log(info_logging_level, "Could not add the new targeted prediction time " + targeted_prediction_time + " from topic " + topic + " as it is already present"); - }else if (!adaptation_times_pending_processing.contains(targeted_prediction_time)){ - Logger.getAnonymousLogger().log(info_logging_level, "Could not add the new targeted prediction time " + targeted_prediction_time + " from topic " + topic + " as it is already pending processing"); - }else if (targeted_prediction_time * 1000 - time_horizon_seconds * 1000L - (Clock.systemUTC()).millis()<=0) { + } else if (!adaptation_times_pending_processing.contains(targeted_prediction_time)) { + if (targeted_prediction_time * 1000 - time_horizon_seconds * 1000L - (Clock.systemUTC()).millis() <= 0) { Logger.getAnonymousLogger().log(info_logging_level, "Could not add the new targeted prediction time " + targeted_prediction_time + " from topic " + topic + " as it would expire in " + (targeted_prediction_time * 1000 - System.currentTimeMillis()) + " milliseconds and the prediction horizon is " + time_horizon_seconds * 1000L + " milliseconds"); + }else{ + Logger.getAnonymousLogger().log(info_logging_level,"Adding new prediction time "+targeted_prediction_time+" which expires in " + (targeted_prediction_time * 1000 - System.currentTimeMillis())); + adaptation_times_pending_processing.add(targeted_prediction_time); + } } } ADAPTATION_TIMES_MODIFY.setValue(true); @@ -156,6 +161,8 @@ public class AttributeSubscription { p.printStackTrace(); } catch (InterruptedException e) { Logger.getAnonymousLogger().log(info_logging_level,"Monitoring attribute subscription thread for prediction attribute "+predicted_attribute_name+" is stopped"); + } catch (ClassCastException | NumberFormatException n){ + Logger.getAnonymousLogger().log(info_logging_level,"Error while trying to parse message\n"+message); } return message; }; diff --git a/morphemic-slo-severity-calculator/src/main/java/runtime/Main.java b/morphemic-slo-severity-calculator/src/main/java/runtime/Main.java index 7ed0cdc2..0b60069c 100644 --- a/morphemic-slo-severity-calculator/src/main/java/runtime/Main.java +++ b/morphemic-slo-severity-calculator/src/main/java/runtime/Main.java @@ -11,6 +11,7 @@ package runtime; import eu.melodic.event.brokerclient.BrokerPublisher; import eu.melodic.event.brokerclient.BrokerSubscriber; import metric_retrieval.AttributeSubscription; +import org.apache.commons.collections4.queue.CircularFifoQueue; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; @@ -56,6 +57,8 @@ public class Main { public static Long current_slo_rules_version = -1L;//initialization public static final AtomicBoolean slo_rule_arrived = new AtomicBoolean(false); public static final SynchronizedBoolean can_modify_slo_rules = new SynchronizedBoolean(false); + + public static CircularFifoQueue slo_violation_event_recording_queue = new CircularFifoQueue<>(50); private static Properties prop = new Properties(); public static void main(String[] args) { @@ -581,6 +584,9 @@ public class Main { severity_json.put("predictionTime", targeted_prediction_time); persistent_publisher.publish(severity_json.toJSONString()); } + + slo_violation_event_recording_queue.add(System.currentTimeMillis()); + //Probably not necessary to synchronize the line below as each removal will happen only once in a reconfiguration interval, and reconfiguration intervals are assumed to have a duration of minutes. //Necessary to synchronize because another severity calculation thread might invoke clean_data above, and then a concurrent modification exception may arise synchronized (ADAPTATION_TIMES_MODIFY){ diff --git a/morphemic-slo-severity-calculator/src/main/java/utilities/DebugDataSubscription.java b/morphemic-slo-severity-calculator/src/main/java/utilities/DebugDataSubscription.java index ec1989ea..0d273930 100644 --- a/morphemic-slo-severity-calculator/src/main/java/utilities/DebugDataSubscription.java +++ b/morphemic-slo-severity-calculator/src/main/java/utilities/DebugDataSubscription.java @@ -16,6 +16,7 @@ import java.util.logging.Logger; import static configuration.Constants.amq_library_configuration_location; import static configuration.Constants.info_logging_level; import static runtime.Main.running_threads; +import static runtime.Main.slo_violation_event_recording_queue; /** * The objective of this class is to allow a structured synopsis of the current state of the SLO Violation Detector to be created, as a response to a request sent to it through an appropriate topic. @@ -31,38 +32,58 @@ public class DebugDataSubscription { StringBuilder intermediate_debug_string = new StringBuilder(); intermediate_debug_string = new StringBuilder(intermediate_debug_string + "The following threads are currently running" + "\n"); + boolean flag_first_element_iterated = true; for (String s : running_threads.keySet()){ - intermediate_debug_string.append(",").append(s); + if (flag_first_element_iterated) { + intermediate_debug_string.append(s); + flag_first_element_iterated = false; + }else{ + intermediate_debug_string.append(",\n").append(s); + } } + intermediate_debug_string.append("\n"); output_debug_data = output_debug_data+intermediate_debug_string; intermediate_debug_string = new StringBuilder(); - intermediate_debug_string = intermediate_debug_string.append("The following Monitoring Attribute values are currently stored:\n"); + flag_first_element_iterated = true; + intermediate_debug_string.append("The following Monitoring Attribute values are currently stored:\n"); for ( Map.Entry entry :RealtimeMonitoringAttribute.getMonitoring_attributes().entrySet() ){ - intermediate_debug_string.append("Metric name: ").append(entry.getKey()); + if (flag_first_element_iterated){ + intermediate_debug_string.append("Metric name: ").append(entry.getKey()); + flag_first_element_iterated = false; + }else{ + intermediate_debug_string.append("\nMetric name: ").append(entry.getKey()); + } + Double metric_value = RealtimeMonitoringAttribute.get_metric_value(entry.getKey()); CircularFifoQueue metric_values = entry.getValue().getActual_metric_values(); if (metric_value.isNaN()){ - intermediate_debug_string.append(" - value was determined as NaN, individual collected values are ").append(metric_values); + intermediate_debug_string.append(" - value was determined as NaN, individual collected values are ").append(metric_values).append("\n"); } else if (metric_value.isInfinite()){ - intermediate_debug_string.append(" - value was determined as infinite, individual collected values are ").append(metric_values); + intermediate_debug_string.append(" - value was determined as infinite, individual collected values are ").append(metric_values).append("\n"); } else { - intermediate_debug_string.append(" - value from individual values").append(metric_values).append(" is ").append(metric_value); + intermediate_debug_string.append(" - value from individual values").append(metric_values).append(" is ").append(metric_value).append("\n"); } } output_debug_data = output_debug_data+intermediate_debug_string; intermediate_debug_string = new StringBuilder(); - intermediate_debug_string = intermediate_debug_string.append("The following subrules have been parsed and are stored:\n"); + intermediate_debug_string.append("The following subrules have been parsed and are stored:\n"); for (Map.Entry> entry : SLOSubRule.getSlo_subrules_per_monitoring_attribute().entrySet()){ intermediate_debug_string.append("Metric name: ").append(entry.getKey()); for (SLOSubRule rule : entry.getValue()) { intermediate_debug_string.append("\n").append(rule.toString()); } + intermediate_debug_string.append("\n"); } output_debug_data = output_debug_data+intermediate_debug_string; + intermediate_debug_string = new StringBuilder(); + + output_debug_data = output_debug_data+"\nShowing the adaptation times that pend processing:\n"+ Main.adaptation_times_pending_processing; + intermediate_debug_string.append("\nThese are the timestamps of the latest adaptation events\n").append(slo_violation_event_recording_queue); + Logger.getGlobal().log(info_logging_level,"Debug data generated:\n"+output_debug_data); BrokerPublisher publisher = new BrokerPublisher(debug_data_output_topic_name, broker_ip_address, broker_username, broker_password, amq_library_configuration_location); publisher.publish(output_debug_data); -- GitLab From 21f0b357a11316b58705dc61bfc47335d9fb8546 Mon Sep 17 00:00:00 2001 From: Jan Marchel Date: Fri, 1 Sep 2023 08:39:44 +0000 Subject: [PATCH 15/16] Update file Coordinator.java --- .../service/Coordinator.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/prediction_orchestrator/src/main/java/eu/morphemic/prediction_orchestrator/service/Coordinator.java b/prediction_orchestrator/src/main/java/eu/morphemic/prediction_orchestrator/service/Coordinator.java index cca588b6..c34b8b96 100644 --- a/prediction_orchestrator/src/main/java/eu/morphemic/prediction_orchestrator/service/Coordinator.java +++ b/prediction_orchestrator/src/main/java/eu/morphemic/prediction_orchestrator/service/Coordinator.java @@ -51,13 +51,19 @@ public class Coordinator { //Communication 5 and 1 synchronized void publishIfPooledValuesProvidedForAllMetrics(long predictionTime, int lastValueUpdate, String callingMetricHandler) { - //metricName -> predictionAvailability + /metricName -> predictionAvailability HashMap isPooledPredictionAvailable = new HashMap<>(); - metricHandlers.forEach((metricName, metricHandler) -> - isPooledPredictionAvailable.put(metricName, metricHandler.containsPooledPrediction(predictionTime))); + metricHandlers.forEach((metricName, metricHandler) -> { + boolean isAvailable = metricHandler.containsPooledPrediction(predictionTime); + isPooledPredictionAvailable.put(metricName, isAvailable); + log.debug("Checking pooled prediction for metric {}: {}", metricName, isAvailable ? "Available" : "Not Available"); + }); boolean entireVectorIsReady = isPooledPredictionAvailable.entrySet().stream() - .allMatch(Map.Entry::getValue); + .allMatch(Map.Entry::getValue); + log.debug("Entire vector readiness status: {}", entireVectorIsReady ? "Ready" : "Not Ready"); + + if (entireVectorIsReady) { log.info("Starting publishing pooled predictions for metrics for {} ", PredictionTimeFormatter.rawDateFormat(predictionTime)); -- GitLab From 5ff228c4f95356dbfb04af069e5cad390ee04b99 Mon Sep 17 00:00:00 2001 From: Jean-Didier Date: Fri, 1 Sep 2023 10:51:26 +0200 Subject: [PATCH 16/16] fix bug 411 --- polymorphic_solver/src/ml_models/env.py | 2 +- polymorphic_solver/src/morphemic.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/polymorphic_solver/src/ml_models/env.py b/polymorphic_solver/src/ml_models/env.py index 1c66ae05..9aba2e58 100644 --- a/polymorphic_solver/src/ml_models/env.py +++ b/polymorphic_solver/src/ml_models/env.py @@ -91,7 +91,7 @@ prefix_predicted_metric = os.environ.get("PREFIX_PREDICTED_METRIC","Predictions" polymorphic_solver_topic = os.environ.get("POLYMORPHIC_TOPIC","polymorphic_solver") min_deployment_size_analysis = int(os.environ.get("MINIMUM_COLLECTION_SIZE_ANALYSIS","100")) -exploring_period = int(os.environ.get("EXPLORE_PERIOD","600")) +exploring_period = int(os.environ.get("EXPLORE_PERIOD","900")) def get_value_from_name(name, _type): name = str(name) diff --git a/polymorphic_solver/src/morphemic.py b/polymorphic_solver/src/morphemic.py index e1a6ecf1..ddf7bd93 100644 --- a/polymorphic_solver/src/morphemic.py +++ b/polymorphic_solver/src/morphemic.py @@ -324,16 +324,16 @@ class MorphemicArchetypeManager(): if self.best_camel_utility == None or best_performance > self.best_camel_utility: filename = self.camel_transformer.archetypesToCamels(best_group, self.camel_version, self.current_grouping) if filename: - self.camel_version +=1 print("Current camel model performance = {0}".format(best_performance)) self.best_camel_utility = best_performance if self.importNewCamel(filename): self.notifyMorphemic(filename) self.polymorphic_solver.setCurrentDeploymentConfiguration(best_group) + self.camel_version +=1 self.cleanAllArchetypes() def importNewCamel(self, filename): - data = {"filename": filename, "resource_name": self.application_id + "_version_"+ str(self.camel_version)} + data = {"filename": filename, "resource_name": self.application_id + "Ver"+ str(self.camel_version)} response = requests.post(url=camel_converter_url+"/import_model", data=json.dumps(data), headers={"Content-Type":"application/json"}, timeout=cdo_default_timeout) try: print("Camel converter response", response.text) @@ -357,7 +357,7 @@ class MorphemicArchetypeManager(): def notifyMorphemic(self, camel_name): data = { - "applicationId": self.application_id + "_version_"+ str(self.camel_version), + "applicationId": self.application_id + "Ver"+ str(self.camel_version), "camel_model": camel_name, "grouping": self.current_grouping, "watermark": self.getWatermark(), -- GitLab