123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334 |
- <div class="standardContainer">
- <div class="ui basic segment">
- <h2>Uptime Monitor</h2>
- <p>Check the online state of proxied targets</p>
- </div>
- <div class="ui divider"></div>
- <div id="utmrender" class="ui basic segment">
- <div class="ui basic segment">
- <h4 class="ui header">
- <i class="red remove icon"></i>
- <div class="content">
- Uptime Monitoring service is currently unavailable
- <div class="sub header">This might be caused by an error in cluster communication within the host servers. Please wait for administrator to resolve the issue.</div>
- </div>
- </h4>
- </div>
- </div>
- <div align="center">
- <button class="ui basic circular green icon button" onclick="reloadUptimeList();"><i class="refresh icon"></i></button>
- </div>
- </div>
- <script>
- var uptime5xxErrorMessage = {
- "500": "Internal Server Error",
- "501": "Not Implemented",
- "502": "Bad Gateway",
- "503": "Service Unavailable",
- "504": "Gateway Timeout",
- "505": "HTTP Version Not Supported",
- "506": "Variant Also Negotiates",
- "507": "Insufficient Storage",
- "508": "Loop Detected",
- "510": "Not Extended",
- "511": "Network Authentication Required",
- "520": "Web Server Returned an Unknown Error (Cloudflare)",
- "521": "Web Server is Down (Cloudflare)",
- "522": "Connection Timed Out (Cloudflare)",
- "523": "Origin is Unreachable (Cloudflare)",
- "524": "A Timeout Occurred (Cloudflare)",
- "525": "SSL Handshake Failed (Cloudflare)",
- "526": "Invalid SSL Certificate (Cloudflare)",
- "527": "Railgun Error (Cloudflare)",
- "530": "Site is Frozen (Pantheon)"
- }
- $('#utmEnable').checkbox({
- onChange: function() {
- var utmEnable = $('input[name="utmEnable"]').is(":checked");
- $.post({
- url: '/api/toggle-utm',
- data: {utmEnable: utmEnable},
- success: function(response) {
- console.log(response);
- },
- error: function(error) {
- console.log(error);
- }
- });
- }
- });
- function initUptimeTable(){
- $.get("/api/utm/list", function(data){
- let records = data;
- renderRecords(records);
- })
- }
- initUptimeTable();
- function reloadUptimeList(){
- $("#utmrender").html(`<div class="ui utmloading segment">
- <div class="ui active inverted dimmer" style="z-index: 2;">
- <div class="ui text loader">Loading</div>
- </div>
- <br><br><br><br>
- </div>`);
- setTimeout(initUptimeTable, 300);
- }
- //For every 5 minutes
- setInterval(function(){
- $.get("/api/utm/list", function(data){
- console.log("Status Updated");
- records = data;
- renderRecords(records);
- });
- }, (300 * 1000));
-
- function renderRecords(records){
- $("#utmrender").html("");
- for (let [key, value] of Object.entries(records)) {
- renderUptimeData(key, value);
- }
- }
- function format_time(s) {
- const date = new Date(s * 1e3);
- return(date.toLocaleString());
- }
- function resolveUptime5xxErrorMessage(errorCode){
- if (uptime5xxErrorMessage[errorCode] != undefined){
- return uptime5xxErrorMessage[errorCode]
- }else{
- return "Unknown Error";
- }
- }
- function showStatusDotInfo(targetDot){
- $(".statusbar .selectedDotInfo").hide();
- let payload = $(targetDot).attr("payload");
- let statusData = JSON.parse(decodeURIComponent(payload));
- let statusDotInfoEle = $(targetDot).parent().parent().find(".selectedDotInfo");
- let statusInfoEle = $(statusDotInfoEle).find(".status_dot_status_info");
- //Fill in the data to the info box
- $(statusDotInfoEle).find(".status_dot_timestamp").text(format_time(statusData.Timestamp));
- $(statusDotInfoEle).find(".status_dot_latency").text(statusData.Latency + "ms");
- $(statusDotInfoEle).find(".status_dot_status_code").text(statusData.StatusCode);
-
- //Set the class of the info box if status code is 5xx
- $(statusDotInfoEle).removeClass("yellow");
- $(statusDotInfoEle).removeClass("red");
- $(statusDotInfoEle).removeClass("green");
- if (statusData.StatusCode >= 500 && statusData.StatusCode < 600){
- $(statusDotInfoEle).addClass("yellow");
- $(statusInfoEle).text(httpErrorStatusCodeToText(statusData.StatusCode));
- }else if (statusData.StatusCode == 0 && !statusData.Online){
- $(statusDotInfoEle).addClass("red");
- $(statusInfoEle).text("Upstream is offline");
- }else{
- $(statusDotInfoEle).addClass("green");
- $(statusInfoEle).text("Upstream Online");
- }
- $(statusDotInfoEle).show();
- }
- function renderUptimeData(key, value){
- if (value.length == 0){
- return
- }
- let id = value[0].ID;
- let name = value[0].Name;
- let url = value[value.length - 1].URL;
- let protocol = value[0].Protocol;
- //Generate the status dot
- let statusDotList = ``;
- for(var i = 0; i < (288 - value.length); i++){
- //Padding
- statusDotList += `<div class="padding statusDot"></div>`
- }
- let ontimeRate = 0;
- for (var i = 0; i < value.length; i++){
- //Render status to html
- let thisStatus = value[i];
- let dotType = "";
- let statusCode = thisStatus.StatusCode;
- let statusDotPayload = encodeURIComponent(JSON.stringify(thisStatus));
- if (!thisStatus.Online && statusCode == 0){
- dotType = "offline";
- }else if (statusCode < 200){
- //1xx
- dotType = "error";
- ontimeRate++;
- }else if (statusCode < 300){
- //2xx
- dotType = "online";
- ontimeRate++;
- }else if (statusCode < 400){
- //3xx
- dotType = "online";
- ontimeRate++;
- }else if (statusCode < 500){
- //4xx
- dotType = "error";
- ontimeRate++;
- }else if (statusCode < 600){
- //5xx
- dotType = "error";
- }else {
- dotType = "offline";
- }
-
- let datetime = format_time(thisStatus.Timestamp);
- statusDotList += `<div title="${datetime}" class="${dotType} statusDot" payload="${statusDotPayload}" onclick="showStatusDotInfo(this);"></div>`
- }
- ontimeRate = ontimeRate / value.length * 100;
- let ontimeColor = "#df484a"
- if (ontimeRate > 0.8){
- ontimeColor = "#3bd671";
- }else if(ontimeRate > 0.5) {
- ontimeColor = "#f29030";
- }
- //Check of online status now
- let currentOnlineStatus = "Unknown";
- let onlineStatusCss = ``;
- let reminderEle = ``;
- if (value[value.length - 1].Online){
- currentOnlineStatus = `<i class="circle icon"></i> Online`;
- onlineStatusCss = `color: #3bd671;`;
- }else{
- if (value[value.length - 1].StatusCode >= 500 && value[value.length - 1].StatusCode < 600){
- var latestStatusCode = value[value.length - 1].StatusCode
- currentOnlineStatus = `<i class="exclamation circle icon"></i>${latestStatusCode} - ${resolveUptime5xxErrorMessage(latestStatusCode)}`;
- onlineStatusCss = `color: #f38020;`;
- reminderEle = `<small style="${onlineStatusCss}">Downstream proxy server is responsive but returning server error</small>`;
- }else if (value[value.length - 1].StatusCode >= 400 && value[value.length - 1].StatusCode <= 405){
- let latestStatusCode = value[value.length - 1].StatusCode;
- switch(latestStatusCode){
- case 400:
- currentOnlineStatus = `<i class="exclamation circle icon"></i> Bad Request`;
- break;
- case 401:
- currentOnlineStatus = `<i class="exclamation circle icon"></i> Unauthorized`;
- break;
- case 403:
- currentOnlineStatus = `<i class="exclamation circle icon"></i> Forbidden`;
- break;
- case 404:
- currentOnlineStatus = `<i class="exclamation circle icon"></i> Not Found`;
- break;
- case 405:
- currentOnlineStatus = `<i class="exclamation circle icon"></i> Method Not Allowed`;
- break;
- default:
- currentOnlineStatus = `<i class="exclamation circle icon"></i> Status Code: ${latestStatusCode}`;
- break;
- }
-
- onlineStatusCss = `color: #f38020;`;
- reminderEle = `<small style="${onlineStatusCss}">Target online but not accessible</small>`;
-
- }else{
- currentOnlineStatus = `<i class="circle icon"></i> Offline`;
- onlineStatusCss = `color: #df484a;`;
- }
-
- }
- //Generate the html
- $("#utmrender").append(`<div class="ui basic segment statusbar">
- <div class="domain">
- <div style="position: absolute; top: 0; right: 0.4em;">
- <p class="onlineStatus" style="display: inline-block; font-size: 1.2em; padding-right: 0.5em; padding-left: 0.3em; ${onlineStatusCss}">${currentOnlineStatus}</p>
- </div>
- <div>
- <h3 class="ui header" style="margin-bottom: 0.2em;">${name}</h3>
- <a href="${url}" target="_blank">${url}</a> | <span style="color: ${ontimeColor};">${(ontimeRate).toFixed(2)}%<span>
- </div>
- <div class="ui basic label protocol" style="position: absolute; bottom: 0; right: 0.2em; margin-bottom: -0.6em;">
- proto: ${protocol}
- </div>
- </div>
- <div class="status" style="marign-top: 1em;">
- ${statusDotList}
- </div>
- ${reminderEle}
- <div class="ui basic segment selectedDotInfo" style="display:none; border: 0.4em;">
- <div class="ui list">
- <div class="item"><b>Timestamp</b>: <span class="status_dot_timestamp"></span></div>
- <div class="item"><b>Latency</b>: <span class="status_dot_latency"></span></div>
- <div class="item"><b>Status Code</b>: <span class="status_dot_status_code"></span></div>
- <div class="item"><b>Status Info</b>: <span class="status_dot_status_info"></span></div>
- </div>
- <button onclick="$(this).parent().hide();" style="position: absolute; right: 0.4em; top: 0.6em;" class="ui basic tiny circular icon button"><i class="ui times icon"></i></button>
- </div>
- <div class="ui divider"></div>
- </div>`);
- }
-
- function httpErrorStatusCodeToText(statusCode){
- switch(statusCode){
- case 400:
- return "Bad Request";
- case 401:
- return "Unauthorized";
- case 403:
- return "Forbidden";
- case 404:
- return "Not Found";
- case 405:
- return "Method Not Allowed";
- case 500:
- return "Internal Server Error";
- case 501:
- return "Not Implemented";
- case 502:
- return "Bad Gateway";
- case 503:
- return "Service Unavailable";
- case 504:
- return "Gateway Timeout";
- case 505:
- return "HTTP Version Not Supported";
- case 506:
- return "Variant Also Negotiates";
- case 507:
- return "Insufficient Storage";
- case 508:
- return "Loop Detected";
- case 510:
- return "Not Extended";
- case 511:
- return "Network Authentication Required";
- case 520:
- return "Web Server Returned an Unknown Error (Cloudflare)";
- case 521:
- return "Web Server is Down (Cloudflare)";
- case 522:
- return "Connection Timed Out (Cloudflare)";
- case 523:
- return "Origin is Unreachable (Cloudflare)";
- case 524:
- return "A Timeout Occurred (Cloudflare)";
- case 525:
- return "SSL Handshake Failed (Cloudflare)";
- case 526:
- return "Invalid SSL Certificate (Cloudflare)";
- case 527:
- return "Railgun Error (Cloudflare)";
- default:
- return "Unknown Error";
- }
- }
- </script>
|