Commit 0d4a053f 0d4a053ff1c1f5f222f6710a9f06d62d985fde5d by Christian Gerdes

First working fix of the OraBug issue #8

We now keep 3 measurements internaly. If a delta is calculated and is
negative, it is ignored. If no delta can be calculated between the
3 last measurements, the last valid response is returned instead, until
a new delta can be calculated. When a cached response is reported, it 
will be logged with a timestamp, name of the counter and all 3
measurements ordered by age (youngest first).
Improved logging with timestamps also for exceptions.
1 parent 89849623
No preview for this file type
1 1
2 2
3 import java.io.IOException; 3 import java.io.IOException;
4 import java.util.logging.Level;
5 import java.util.logging.Logger;
4 6
5 import javax.management.remote.JMXServiceURL; 7 import javax.management.remote.JMXServiceURL;
6 import javax.servlet.ServletException; 8 import javax.servlet.ServletException;
...@@ -18,7 +20,7 @@ import se.lil.jm.Registry; ...@@ -18,7 +20,7 @@ import se.lil.jm.Registry;
18 @WebServlet(description = "Calls getData on an existing JmxMon object or creates and calls it", urlPatterns = { "/JmxMonREST/getData" }) 20 @WebServlet(description = "Calls getData on an existing JmxMon object or creates and calls it", urlPatterns = { "/JmxMonREST/getData" })
19 public class JmxMonRESTgetData extends HttpServlet { 21 public class JmxMonRESTgetData extends HttpServlet {
20 private static final long serialVersionUID = 1L; 22 private static final long serialVersionUID = 1L;
21 23 private final static Logger LOGGER = Logger.getLogger(JmxMonRESTgetData.class.getName());
22 /** 24 /**
23 * @see HttpServlet#HttpServlet() 25 * @see HttpServlet#HttpServlet()
24 */ 26 */
...@@ -90,6 +92,7 @@ public class JmxMonRESTgetData extends HttpServlet { ...@@ -90,6 +92,7 @@ public class JmxMonRESTgetData extends HttpServlet {
90 String rst = "{\"error\":true,\"msg\":\"" + e.toString() + ". Caused by: " + thisCause.toString() + "\"}"; 92 String rst = "{\"error\":true,\"msg\":\"" + e.toString() + ". Caused by: " + thisCause.toString() + "\"}";
91 rst.replace("\n"," ").replace("\"","\\\"").trim(); 93 rst.replace("\n"," ").replace("\"","\\\"").trim();
92 response.getWriter().println(rst); 94 response.getWriter().println(rst);
95 LOGGER.log(Level.SEVERE, e.toString());
93 e.printStackTrace(); 96 e.printStackTrace();
94 } 97 }
95 } 98 }
......
1 1
2 2
3 import java.io.IOException; 3 import java.io.IOException;
4 import java.util.logging.Level;
5 import java.util.logging.Logger;
4 6
5 import javax.management.remote.JMXServiceURL; 7 import javax.management.remote.JMXServiceURL;
6 import javax.servlet.ServletException; 8 import javax.servlet.ServletException;
...@@ -18,7 +20,7 @@ import se.lil.jm.Registry; ...@@ -18,7 +20,7 @@ import se.lil.jm.Registry;
18 @WebServlet(description = "Gets JMX Monitors metrics", urlPatterns = { "/JmxMonREST/getMetrics" }) 20 @WebServlet(description = "Gets JMX Monitors metrics", urlPatterns = { "/JmxMonREST/getMetrics" })
19 public class JmxMonRESTgetMetrics extends HttpServlet { 21 public class JmxMonRESTgetMetrics extends HttpServlet {
20 private static final long serialVersionUID = 1L; 22 private static final long serialVersionUID = 1L;
21 23 private final static Logger LOGGER = Logger.getLogger(JmxMonRESTgetMetrics.class.getName());
22 /** 24 /**
23 * @see HttpServlet#HttpServlet() 25 * @see HttpServlet#HttpServlet()
24 */ 26 */
...@@ -97,6 +99,7 @@ public class JmxMonRESTgetMetrics extends HttpServlet { ...@@ -97,6 +99,7 @@ public class JmxMonRESTgetMetrics extends HttpServlet {
97 } catch (Throwable e) { 99 } catch (Throwable e) {
98 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); 100 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
99 response.getWriter().println("{\"error\":true,\"msg\":\""+e.toString().replace("\n"," ").trim()+"\"}"); 101 response.getWriter().println("{\"error\":true,\"msg\":\""+e.toString().replace("\n"," ").trim()+"\"}");
102 LOGGER.log(Level.SEVERE, e.toString());
100 e.printStackTrace(); 103 e.printStackTrace();
101 } 104 }
102 } 105 }
......
1 1
2 2
3 import java.io.IOException; 3 import java.io.IOException;
4 import java.util.logging.Level;
5 import java.util.logging.Logger;
4 6
5 import javax.servlet.ServletException; 7 import javax.servlet.ServletException;
6 import javax.servlet.annotation.WebServlet; 8 import javax.servlet.annotation.WebServlet;
...@@ -17,7 +19,7 @@ import se.lil.om.Registry; ...@@ -17,7 +19,7 @@ import se.lil.om.Registry;
17 @WebServlet(description = "REST API for OraMon", urlPatterns = { "/OraMonREST/getData" }) 19 @WebServlet(description = "REST API for OraMon", urlPatterns = { "/OraMonREST/getData" })
18 public class OraMonRESTgetData extends HttpServlet { 20 public class OraMonRESTgetData extends HttpServlet {
19 private static final long serialVersionUID = 1L; 21 private static final long serialVersionUID = 1L;
20 22 private final static Logger LOGGER = Logger.getLogger(OraMonRESTgetData.class.getName());
21 /** 23 /**
22 * @see HttpServlet#HttpServlet() 24 * @see HttpServlet#HttpServlet()
23 */ 25 */
...@@ -159,6 +161,7 @@ public class OraMonRESTgetData extends HttpServlet { ...@@ -159,6 +161,7 @@ public class OraMonRESTgetData extends HttpServlet {
159 } catch (Throwable e) { 161 } catch (Throwable e) {
160 response.setStatus(500); 162 response.setStatus(500);
161 response.getWriter().println("{\"error\":true,\"msg\":\""+e.toString().replace("\n"," ").replace("\"","\\\"").trim()+"\"}"); 163 response.getWriter().println("{\"error\":true,\"msg\":\""+e.toString().replace("\n"," ").replace("\"","\\\"").trim()+"\"}");
164 LOGGER.log(Level.SEVERE, e.toString());
162 e.printStackTrace(); 165 e.printStackTrace();
163 } 166 }
164 } 167 }
......
1 1
2 2
3 import java.io.IOException; 3 import java.io.IOException;
4 import java.util.logging.Level;
5 import java.util.logging.Logger;
4 6
5 import javax.servlet.ServletException; 7 import javax.servlet.ServletException;
6 import javax.servlet.annotation.WebServlet; 8 import javax.servlet.annotation.WebServlet;
...@@ -17,7 +19,7 @@ import se.lil.om.Registry; ...@@ -17,7 +19,7 @@ import se.lil.om.Registry;
17 @WebServlet(description = "Gets a default set of metrics from an existing monitor", urlPatterns = { "/OraMonREST/getMetrics" }) 19 @WebServlet(description = "Gets a default set of metrics from an existing monitor", urlPatterns = { "/OraMonREST/getMetrics" })
18 public class OraMonRESTgetMetrics extends HttpServlet { 20 public class OraMonRESTgetMetrics extends HttpServlet {
19 private static final long serialVersionUID = 1L; 21 private static final long serialVersionUID = 1L;
20 22 private final static Logger LOGGER = Logger.getLogger(OraMonRESTgetMetrics.class.getName());
21 /** 23 /**
22 * @see HttpServlet#HttpServlet() 24 * @see HttpServlet#HttpServlet()
23 */ 25 */
...@@ -167,6 +169,7 @@ public class OraMonRESTgetMetrics extends HttpServlet { ...@@ -167,6 +169,7 @@ public class OraMonRESTgetMetrics extends HttpServlet {
167 } catch (Throwable e) { 169 } catch (Throwable e) {
168 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); 170 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
169 response.getWriter().println("{\"error\":true,\"msg\":\""+e.toString().replace("\n"," ").trim()+"\"}"); 171 response.getWriter().println("{\"error\":true,\"msg\":\""+e.toString().replace("\n"," ").trim()+"\"}");
172 LOGGER.log(Level.SEVERE, e.toString());
170 e.printStackTrace(); 173 e.printStackTrace();
171 } 174 }
172 } 175 }
......
...@@ -76,3 +76,15 @@ Istället måste detta detekteras när man läser av ett delta i någon av delta ...@@ -76,3 +76,15 @@ Istället måste detta detekteras när man läser av ett delta i någon av delta
76 Innan trodde jag att problemet alltid inleds med ett negativt delta, sedan en spik, sedan normalt. Men så är inte fallet, jag har sett idag tvärtom, det inleds med en spik och sedan 76 Innan trodde jag att problemet alltid inleds med ett negativt delta, sedan en spik, sedan normalt. Men så är inte fallet, jag har sett idag tvärtom, det inleds med en spik och sedan
77 en rättning (vilket känns konstigt) men så blev det på tex file io wait time. Så jag tror tyvärr att enda rätta lösningen på problemet är att spara minst 3 mätningar innan ett delta rapporteras, 77 en rättning (vilket känns konstigt) men så blev det på tex file io wait time. Så jag tror tyvärr att enda rätta lösningen på problemet är att spara minst 3 mätningar innan ett delta rapporteras,
78 samt att man då kan upptäcka ett negativt delta, och i så fall ignorera värdet innan. 78 samt att man då kan upptäcka ett negativt delta, och i så fall ignorera värdet innan.
79
80 2019-02-13
81
82 Måste se över logiken med att hoppa över negativa deltan. De kommer fram i alla fall i guit. Kanske sker 2 på raken? Eller så funkar inte logiken. Behöver börja med att logga.
83 Kom på ett alternativ idag med, en parameter i varje long delta som är "senast rapporterade värdet" och sedan en enkel kontroll, om inte alla 3 senaste mätningarna är "i rad"
84 så rapportera senaste/föregående delta igen. Detta för att undvika att påverka medelvärden som beräknas på rapporterade deltan.
85
86 2019-02-20
87
88 Har nu skrivit om logiken så att vi kollar om vi kan hitta ett positivt delta bland de 3 mätvärden som finns, om vi gör det returnerar vi detta med det senaste mest aktuella
89 värdet först. Lyckas vi inte med det, returnerar vi det cachade värdet vi returnerade förra gången. Om det senare sker loggas detta tillsammans med namn på räknaren samt
90 alla aktuella värden samt det cachade resultatet som returnerades.
......
...@@ -3,8 +3,11 @@ package se.lil.om; ...@@ -3,8 +3,11 @@ package se.lil.om;
3 import java.math.BigDecimal; 3 import java.math.BigDecimal;
4 import java.sql.ResultSet; 4 import java.sql.ResultSet;
5 import java.sql.Timestamp; 5 import java.sql.Timestamp;
6 import java.util.logging.Level;
7 import java.util.logging.Logger;
6 8
7 class LongDelta { 9 class LongDelta {
10 private final static Logger LOGGER = Logger.getLogger(LongDelta.class.getName());
8 private String name = null; 11 private String name = null;
9 12
10 private BigDecimal curValue = null; 13 private BigDecimal curValue = null;
...@@ -19,6 +22,8 @@ class LongDelta { ...@@ -19,6 +22,8 @@ class LongDelta {
19 22
20 private double numMilliSeconds; 23 private double numMilliSeconds;
21 private double delta; 24 private double delta;
25 private double lastGoodDelta = 0;
26 private double lastGoodMilliseconds = 0;
22 private boolean haveGoodDelta = false; 27 private boolean haveGoodDelta = false;
23 28
24 public LongDelta(String name) { 29 public LongDelta(String name) {
...@@ -64,17 +69,30 @@ class LongDelta { ...@@ -64,17 +69,30 @@ class LongDelta {
64 if(this.curValue != null && this.lastValue != null && this.last2Value != null 69 if(this.curValue != null && this.lastValue != null && this.last2Value != null
65 && this.lastFetch != null && this.last2Fetch != null && this.curFetch != null) { 70 && this.lastFetch != null && this.last2Fetch != null && this.curFetch != null) {
66 71
67 // We have values, calculate the number of gets per second 72 // We have values, calculate the deltas
68 73
69 // Handle the Oracle Bug (ref needed) 74 // Handle the Oracle Bug (ref needed)
70 if(curValue.compareTo(lastValue) >= 0 && lastValue.compareTo(last2Value) >= 0) { 75 if(curValue.compareTo(lastValue) >= 0) {
71 // All seems fine, no negative deltas, return the delta for last and last2 76 numMilliSeconds = this.curFetch.getTime() - this.lastFetch.getTime();
77 delta = this.curValue.subtract(this.lastValue).doubleValue();
78 lastGoodMilliseconds = numMilliSeconds;
79 lastGoodDelta = delta;
80 } else if(curValue.compareTo(last2Value) >= 0) {
81 numMilliSeconds = this.curFetch.getTime() - this.last2Fetch.getTime();
82 delta = this.curValue.subtract(this.last2Value).doubleValue();
83 lastGoodMilliseconds = numMilliSeconds;
84 lastGoodDelta = delta;
85 } else if (lastValue.compareTo(last2Value) >= 0) {
72 numMilliSeconds = this.lastFetch.getTime() - this.last2Fetch.getTime(); 86 numMilliSeconds = this.lastFetch.getTime() - this.last2Fetch.getTime();
73 delta = this.lastValue.subtract(this.last2Value).doubleValue(); 87 delta = this.lastValue.subtract(this.last2Value).doubleValue();
88 lastGoodMilliseconds = numMilliSeconds;
89 lastGoodDelta = delta;
74 } else { 90 } else {
75 // negative delta between current and last, or last and last2, return current and last2 instead 91 // None of the 2 last measurements give a positive delta. Log this and return the last calculated delta.
76 numMilliSeconds = this.curFetch.getTime() - this.last2Fetch.getTime(); 92 numMilliSeconds = lastGoodMilliseconds;
77 delta = this.curValue.subtract(this.last2Value).doubleValue(); 93 delta = lastGoodDelta;
94 LOGGER.log(Level.WARNING, "No positive deltas to calculate, returning cached value:["+lastGoodDelta+"]. Name: "
95 + this.name + " Values:["+curValue+"]["+lastValue+"]["+last2Value+"]");
78 } 96 }
79 97
80 haveGoodDelta = true; 98 haveGoodDelta = true;
......
...@@ -146,16 +146,6 @@ public class OraMon { ...@@ -146,16 +146,6 @@ public class OraMon {
146 return getCPURawValue(); 146 return getCPURawValue();
147 } 147 }
148 148
149 // public long getCPURawDiff() throws Throwable {
150 // return cpuTime.getDelta();
151 // }
152 // public long getCPURawDiff(String pdbName) throws Throwable {
153 // if(pdbName != null)
154 // return colPdbCPU.getDelta(pdbName + strCpuTime);
155 // else
156 // return getCPURawDiff();
157 // }
158
159 public double getCPUTimePerSecond() throws Throwable { 149 public double getCPUTimePerSecond() throws Throwable {
160 return cpuTime.getPerSecondValue(); 150 return cpuTime.getPerSecondValue();
161 } 151 }
......