Add tooltip on status view response time range instead of latest RT

This commit is contained in:
TwinProduction 2019-12-28 12:19:52 -05:00
parent b71edc57ca
commit c4f7370397
4 changed files with 61 additions and 19 deletions

View File

@ -1,7 +1,6 @@
package core package core
import ( import (
"errors"
"fmt" "fmt"
"net" "net"
"net/http" "net/http"
@ -26,7 +25,7 @@ type Result struct {
Hostname string `json:"hostname"` Hostname string `json:"hostname"`
Ip string `json:"ip"` Ip string `json:"ip"`
Duration time.Duration `json:"duration"` Duration time.Duration `json:"duration"`
Errors []error `json:"errors"` Errors []string `json:"errors"`
ConditionResults []*ConditionResult `json:"condition-results"` ConditionResults []*ConditionResult `json:"condition-results"`
Success bool `json:"success"` Success bool `json:"success"`
Timestamp time.Time `json:"timestamp"` Timestamp time.Time `json:"timestamp"`
@ -42,13 +41,13 @@ type Service struct {
func (service *Service) getIp(result *Result) { func (service *Service) getIp(result *Result) {
urlObject, err := url.Parse(service.Url) urlObject, err := url.Parse(service.Url)
if err != nil { if err != nil {
result.Errors = append(result.Errors, err) result.Errors = append(result.Errors, err.Error())
return return
} }
result.Hostname = urlObject.Hostname() result.Hostname = urlObject.Hostname()
ips, err := net.LookupIP(urlObject.Hostname()) ips, err := net.LookupIP(urlObject.Hostname())
if err != nil { if err != nil {
result.Errors = append(result.Errors, err) result.Errors = append(result.Errors, err.Error())
return return
} }
result.Ip = ips[0].String() result.Ip = ips[0].String()
@ -61,7 +60,7 @@ func (service *Service) getStatus(result *Result) {
startTime := time.Now() startTime := time.Now()
response, err := client.Get(service.Url) response, err := client.Get(service.Url)
if err != nil { if err != nil {
result.Errors = append(result.Errors, err) result.Errors = append(result.Errors, err.Error())
return return
} }
result.Duration = time.Now().Sub(startTime) result.Duration = time.Now().Sub(startTime)
@ -69,10 +68,11 @@ func (service *Service) getStatus(result *Result) {
} }
func (service *Service) EvaluateConditions() *Result { func (service *Service) EvaluateConditions() *Result {
result := &Result{Success: true} result := &Result{Success: true, Errors: []string{}}
service.getStatus(result)
service.getIp(result) service.getIp(result)
if len(result.Errors) > 0 { if len(result.Errors) == 0 {
service.getStatus(result)
} else {
result.Success = false result.Success = false
} }
for _, condition := range service.Conditions { for _, condition := range service.Conditions {
@ -130,7 +130,7 @@ func (c *Condition) Evaluate(result *Result) bool {
return false return false
} }
} else { } else {
result.Errors = append(result.Errors, errors.New(fmt.Sprintf("invalid condition '%s' has been provided", condition))) result.Errors = append(result.Errors, fmt.Sprintf("invalid condition '%s' has been provided", condition))
return false return false
} }
} }

View File

@ -40,11 +40,13 @@ func loadConfiguration() *config.Config {
func serviceResultsHandler(writer http.ResponseWriter, _ *http.Request) { func serviceResultsHandler(writer http.ResponseWriter, _ *http.Request) {
serviceResults := watchdog.GetServiceResults() serviceResults := watchdog.GetServiceResults()
writer.Header().Add("Content-type", "application/json")
writer.WriteHeader(http.StatusOK) writer.WriteHeader(http.StatusOK)
_, _ = writer.Write(structToJsonBytes(serviceResults)) _, _ = writer.Write(structToJsonBytes(serviceResults))
} }
func healthHandler(writer http.ResponseWriter, _ *http.Request) { func healthHandler(writer http.ResponseWriter, _ *http.Request) {
writer.Header().Add("Content-type", "application/json")
writer.WriteHeader(http.StatusOK) writer.WriteHeader(http.StatusOK)
_, _ = writer.Write(structToJsonBytes(&core.HealthStatus{Status: "UP"})) _, _ = writer.Write(structToJsonBytes(&core.HealthStatus{Status: "UP"}))
} }

View File

@ -3,6 +3,14 @@
<head> <head>
<title>Status</title> <title>Status</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<style>
td > span.badge {
display: inline-block;
width: 20px;
cursor: default;
margin-right: 2px;
}
</style>
</head> </head>
<body> <body>
<div class="container my-3 bg-light rounded p-4 border shadow"> <div class="container my-3 bg-light rounded p-4 border shadow">
@ -30,26 +38,56 @@
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script> <script>
const OK = "<span class=\"badge badge-success\">&#10003;</span>&nbsp;"; const OK = "<span class='badge badge-success' title='__RESPONSE_TIME____CONDITIONS____ERRORS__'>&#10003;</span>";
const NOK = "<span class=\"badge badge-danger\">X</span>&nbsp;"; const NOK = "<span class='badge badge-danger' title='__RESPONSE_TIME____CONDITIONS____ERRORS__'>X</span>";
function generateServiceResultBox(serviceResult) {
let output = (serviceResult.success ? OK : NOK);
output = output.replace("__RESPONSE_TIME__", "Response time:\n" + parseInt(serviceResult.duration/1000000) + "ms");
let conditions = "";
for (let conditionResultIndex in serviceResult['condition-results']) {
let conditionResult = serviceResult['condition-results'][conditionResultIndex];
conditions += "\n- " + (conditionResult.success ? "&#10003;" : "X") + " ~ " + conditionResult.condition;
}
output = output.replace("__CONDITIONS__", "\n\nConditions:" + conditions);
if (serviceResult['errors'].length > 0) {
let errors = "";
for (let errorIndex in serviceResult['errors']) {
errors += "\n- " + serviceResult['errors'][errorIndex];
}
output = output.replace("__ERRORS__", "\n\nErrors: " + errors);
} else {
output = output.replace("__ERRORS__", "");
}
return output;
}
function refreshTable() { function refreshTable() {
$.getJSON("/api/v1/results", function (data) { $.getJSON("/api/v1/results", function (data) {
let tableBody = ""; let tableBody = "";
for (let serviceName in data) { for (let serviceName in data) {
let serviceStatus = ""; let serviceStatusOverTime = "";
let hostname =data[serviceName][data[serviceName].length-1].hostname let hostname = data[serviceName][data[serviceName].length-1].hostname
let minResponseTime = null;
let maxResponseTime = null;
for (let key in data[serviceName]) { for (let key in data[serviceName]) {
let entry = data[serviceName][key]; let serviceResult = data[serviceName][key];
console.log(data[serviceName][key]); console.log(serviceResult);
serviceStatus = (entry.success ? OK : NOK) + serviceStatus; serviceStatusOverTime = generateServiceResultBox(serviceResult) + serviceStatusOverTime;
const responseTime = parseInt(serviceResult.duration/1000000);
if (minResponseTime == null || minResponseTime > responseTime) {
minResponseTime = responseTime;
}
if (maxResponseTime == null || maxResponseTime < responseTime) {
maxResponseTime = responseTime;
}
} }
tableBody += "" tableBody += ""
+ "<tr>" + "<tr>"
+ " <td>" + serviceName + "</td>" + " <td>" + serviceName + "</td>"
+ " <td>" + serviceStatus + "</td>" + " <td>" + serviceStatusOverTime + "</td>"
+ " <td><a href=\"//" + hostname + "\">" + hostname + "</a></td>" + " <td><a href=\"//" + hostname + "\">" + hostname + "</a></td>"
+ " <td>" + parseInt(data[serviceName][data[serviceName].length-1].duration / 1000000) + "ms </td>" + " <td>" + (minResponseTime === maxResponseTime ? minResponseTime : (minResponseTime + "-" + maxResponseTime)) + "ms</td>"
+ "</tr>"; + "</tr>";
} }
$("#results").html(tableBody); $("#results").html(tableBody);
@ -59,7 +97,7 @@
refreshTable(); refreshTable();
setInterval(function() { setInterval(function() {
refreshTable(); refreshTable();
}, 3000); }, 10000);
</script> </script>
</body> </body>
</html> </html>

View File

@ -41,5 +41,7 @@ func Monitor(cfg *config.Config) {
time.Sleep(service.Interval) time.Sleep(service.Interval)
} }
}(service) }(service)
// To prevent multiple requests from running exactly at the same time
time.Sleep(100 * time.Millisecond)
} }
} }