mirror of
https://github.com/hibiken/asynqmon.git
synced 2025-09-22 06:46:34 +08:00
Add redux actions/reducer for metrics
This commit is contained in:
@@ -187,6 +187,9 @@ func muxRouter(opts Options, rc redis.UniversalClient, inspector *asynq.Inspecto
|
|||||||
api.HandleFunc("/redis_info", newRedisInfoHandlerFunc(c)).Methods("GET")
|
api.HandleFunc("/redis_info", newRedisInfoHandlerFunc(c)).Methods("GET")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Time series metrics endpoints.
|
||||||
|
api.HandleFunc("/metrics", newGetMetricsHandlerFunc(http.DefaultClient)).Methods("GET")
|
||||||
|
|
||||||
// Everything else, route to uiAssetsHandler.
|
// Everything else, route to uiAssetsHandler.
|
||||||
router.NotFoundHandler = &uiAssetsHandler{
|
router.NotFoundHandler = &uiAssetsHandler{
|
||||||
rootPath: opts.RootPath,
|
rootPath: opts.RootPath,
|
||||||
|
52
metrics_handler.go
Normal file
52
metrics_handler.go
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
package asynqmon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type getMetricsResponse struct {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
func unixTimeString(t time.Time) string {
|
||||||
|
return strconv.Itoa(int(t.Unix()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func newGetMetricsHandlerFunc(client *http.Client) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
const (
|
||||||
|
baseAddr = "http://localhost:9090"
|
||||||
|
apiPath = "/api/v1/query_range"
|
||||||
|
promQL = "asynq_tasks_enqueued_total"
|
||||||
|
)
|
||||||
|
var b strings.Builder
|
||||||
|
v := url.Values{}
|
||||||
|
b.WriteString(baseAddr)
|
||||||
|
b.WriteString(apiPath)
|
||||||
|
v.Add("query", promQL)
|
||||||
|
now := time.Now()
|
||||||
|
v.Add("start", unixTimeString(now.Add(-30*time.Minute)))
|
||||||
|
v.Add("end", unixTimeString(now))
|
||||||
|
v.Add("step", (1 * time.Minute).String())
|
||||||
|
b.WriteString("?")
|
||||||
|
b.WriteString(v.Encode())
|
||||||
|
url := b.String()
|
||||||
|
fmt.Printf("DEBUG: url: %s\n", url)
|
||||||
|
resp, err := client.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, fmt.Sprintf("request failed: GET %q: %v", url, err), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if _, err := io.Copy(w, resp.Body); err != nil {
|
||||||
|
http.Error(w, fmt.Sprintf("failed to copy: %v", err), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"files": {
|
"files": {
|
||||||
|
<<<<<<< HEAD
|
||||||
"main.js": "/[[.RootPath]]/static/js/main.2bdef890.chunk.js",
|
"main.js": "/[[.RootPath]]/static/js/main.2bdef890.chunk.js",
|
||||||
"main.js.map": "/[[.RootPath]]/static/js/main.2bdef890.chunk.js.map",
|
"main.js.map": "/[[.RootPath]]/static/js/main.2bdef890.chunk.js.map",
|
||||||
"runtime-main.js": "/[[.RootPath]]/static/js/runtime-main.9fea6c1a.js",
|
"runtime-main.js": "/[[.RootPath]]/static/js/runtime-main.9fea6c1a.js",
|
||||||
@@ -13,5 +14,20 @@
|
|||||||
"static/js/runtime-main.9fea6c1a.js",
|
"static/js/runtime-main.9fea6c1a.js",
|
||||||
"static/js/2.d6956563.chunk.js",
|
"static/js/2.d6956563.chunk.js",
|
||||||
"static/js/main.2bdef890.chunk.js"
|
"static/js/main.2bdef890.chunk.js"
|
||||||
|
=======
|
||||||
|
"main.js": "/[[.RootPath]]/static/js/main.aac2a828.chunk.js",
|
||||||
|
"main.js.map": "/[[.RootPath]]/static/js/main.aac2a828.chunk.js.map",
|
||||||
|
"runtime-main.js": "/[[.RootPath]]/static/js/runtime-main.9fea6c1a.js",
|
||||||
|
"runtime-main.js.map": "/[[.RootPath]]/static/js/runtime-main.9fea6c1a.js.map",
|
||||||
|
"static/js/2.8854b145.chunk.js": "/[[.RootPath]]/static/js/2.8854b145.chunk.js",
|
||||||
|
"static/js/2.8854b145.chunk.js.map": "/[[.RootPath]]/static/js/2.8854b145.chunk.js.map",
|
||||||
|
"index.html": "/[[.RootPath]]/index.html",
|
||||||
|
"static/js/2.8854b145.chunk.js.LICENSE.txt": "/[[.RootPath]]/static/js/2.8854b145.chunk.js.LICENSE.txt"
|
||||||
|
},
|
||||||
|
"entrypoints": [
|
||||||
|
"static/js/runtime-main.9fea6c1a.js",
|
||||||
|
"static/js/2.8854b145.chunk.js",
|
||||||
|
"static/js/main.aac2a828.chunk.js"
|
||||||
|
>>>>>>> f697574... Add redux actions/reducer for metrics
|
||||||
]
|
]
|
||||||
}
|
}
|
@@ -1,5 +1,9 @@
|
|||||||
<<<<<<< HEAD
|
<<<<<<< HEAD
|
||||||
|
<<<<<<< HEAD
|
||||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" type="image/png" href="/[[.RootPath]]/favicon.ico"/><link rel="icon" type="image/png" sizes="32x32" href="/[[.RootPath]]/favicon-32x32.png"/><link rel="icon" type="image/png" sizes="16x16" href="/[[.RootPath]]/favicon-16x16.png"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Asynq monitoring web console"/><link rel="apple-touch-icon" sizes="180x180" href="/[[.RootPath]]/apple-touch-icon.png"/><link rel="manifest" href="/[[.RootPath]]/manifest.json"/><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"/><link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons"/><script>window.ROOT_PATH="/[[.RootPath]]"</script><title>Asynq - Monitoring</title></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function t(t){for(var n,i,l=t[0],a=t[1],f=t[2],c=0,s=[];c<l.length;c++)i=l[c],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&s.push(o[i][0]),o[i]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(e[n]=a[n]);for(p&&p(t);s.length;)s.shift()();return u.push.apply(u,f||[]),r()}function r(){for(var e,t=0;t<u.length;t++){for(var r=u[t],n=!0,l=1;l<r.length;l++){var a=r[l];0!==o[a]&&(n=!1)}n&&(u.splice(t--,1),e=i(i.s=r[0]))}return e}var n={},o={1:0},u=[];function i(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,i),r.l=!0,r.exports}i.m=e,i.c=n,i.d=function(e,t,r){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(i.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)i.d(r,n,function(t){return e[t]}.bind(null,n));return r},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="/[[.RootPath]]/";var l=this.webpackJsonpui=this.webpackJsonpui||[],a=l.push.bind(l);l.push=t,l=l.slice();for(var f=0;f<l.length;f++)t(l[f]);var p=a;r()}([])</script><script src="/[[.RootPath]]/static/js/2.d6956563.chunk.js"></script><script src="/[[.RootPath]]/static/js/main.2bdef890.chunk.js"></script></body></html>
|
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" type="image/png" href="/[[.RootPath]]/favicon.ico"/><link rel="icon" type="image/png" sizes="32x32" href="/[[.RootPath]]/favicon-32x32.png"/><link rel="icon" type="image/png" sizes="16x16" href="/[[.RootPath]]/favicon-16x16.png"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Asynq monitoring web console"/><link rel="apple-touch-icon" sizes="180x180" href="/[[.RootPath]]/apple-touch-icon.png"/><link rel="manifest" href="/[[.RootPath]]/manifest.json"/><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"/><link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons"/><script>window.ROOT_PATH="/[[.RootPath]]"</script><title>Asynq - Monitoring</title></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function t(t){for(var n,i,l=t[0],a=t[1],f=t[2],c=0,s=[];c<l.length;c++)i=l[c],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&s.push(o[i][0]),o[i]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(e[n]=a[n]);for(p&&p(t);s.length;)s.shift()();return u.push.apply(u,f||[]),r()}function r(){for(var e,t=0;t<u.length;t++){for(var r=u[t],n=!0,l=1;l<r.length;l++){var a=r[l];0!==o[a]&&(n=!1)}n&&(u.splice(t--,1),e=i(i.s=r[0]))}return e}var n={},o={1:0},u=[];function i(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,i),r.l=!0,r.exports}i.m=e,i.c=n,i.d=function(e,t,r){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(i.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)i.d(r,n,function(t){return e[t]}.bind(null,n));return r},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="/[[.RootPath]]/";var l=this.webpackJsonpui=this.webpackJsonpui||[],a=l.push.bind(l);l.push=t,l=l.slice();for(var f=0;f<l.length;f++)t(l[f]);var p=a;r()}([])</script><script src="/[[.RootPath]]/static/js/2.d6956563.chunk.js"></script><script src="/[[.RootPath]]/static/js/main.2bdef890.chunk.js"></script></body></html>
|
||||||
=======
|
=======
|
||||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" type="image/png" href="/[[.RootPath]]/favicon.ico"/><link rel="icon" type="image/png" sizes="32x32" href="/[[.RootPath]]/favicon-32x32.png"/><link rel="icon" type="image/png" sizes="16x16" href="/[[.RootPath]]/favicon-16x16.png"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Asynq monitoring web console"/><link rel="apple-touch-icon" sizes="180x180" href="/[[.RootPath]]/apple-touch-icon.png"/><link rel="manifest" href="/[[.RootPath]]/manifest.json"/><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"/><link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons"/><script>window.ROOT_PATH="/[[.RootPath]]",window.PROMETHEUS_SERVER_ADDRESS="/[[.PrometheusAddr]]"</script><title>Asynq - Monitoring</title></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function t(t){for(var n,i,l=t[0],a=t[1],f=t[2],c=0,s=[];c<l.length;c++)i=l[c],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&s.push(o[i][0]),o[i]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(e[n]=a[n]);for(p&&p(t);s.length;)s.shift()();return u.push.apply(u,f||[]),r()}function r(){for(var e,t=0;t<u.length;t++){for(var r=u[t],n=!0,l=1;l<r.length;l++){var a=r[l];0!==o[a]&&(n=!1)}n&&(u.splice(t--,1),e=i(i.s=r[0]))}return e}var n={},o={1:0},u=[];function i(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,i),r.l=!0,r.exports}i.m=e,i.c=n,i.d=function(e,t,r){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(i.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)i.d(r,n,function(t){return e[t]}.bind(null,n));return r},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="/[[.RootPath]]/";var l=this.webpackJsonpui=this.webpackJsonpui||[],a=l.push.bind(l);l.push=t,l=l.slice();for(var f=0;f<l.length;f++)t(l[f]);var p=a;r()}([])</script><script src="/[[.RootPath]]/static/js/2.260e42b2.chunk.js"></script><script src="/[[.RootPath]]/static/js/main.525ff6d9.chunk.js"></script></body></html>
|
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" type="image/png" href="/[[.RootPath]]/favicon.ico"/><link rel="icon" type="image/png" sizes="32x32" href="/[[.RootPath]]/favicon-32x32.png"/><link rel="icon" type="image/png" sizes="16x16" href="/[[.RootPath]]/favicon-16x16.png"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Asynq monitoring web console"/><link rel="apple-touch-icon" sizes="180x180" href="/[[.RootPath]]/apple-touch-icon.png"/><link rel="manifest" href="/[[.RootPath]]/manifest.json"/><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"/><link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons"/><script>window.ROOT_PATH="/[[.RootPath]]",window.PROMETHEUS_SERVER_ADDRESS="/[[.PrometheusAddr]]"</script><title>Asynq - Monitoring</title></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function t(t){for(var n,i,l=t[0],a=t[1],f=t[2],c=0,s=[];c<l.length;c++)i=l[c],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&s.push(o[i][0]),o[i]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(e[n]=a[n]);for(p&&p(t);s.length;)s.shift()();return u.push.apply(u,f||[]),r()}function r(){for(var e,t=0;t<u.length;t++){for(var r=u[t],n=!0,l=1;l<r.length;l++){var a=r[l];0!==o[a]&&(n=!1)}n&&(u.splice(t--,1),e=i(i.s=r[0]))}return e}var n={},o={1:0},u=[];function i(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,i),r.l=!0,r.exports}i.m=e,i.c=n,i.d=function(e,t,r){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(i.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)i.d(r,n,function(t){return e[t]}.bind(null,n));return r},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="/[[.RootPath]]/";var l=this.webpackJsonpui=this.webpackJsonpui||[],a=l.push.bind(l);l.push=t,l=l.slice();for(var f=0;f<l.length;f++)t(l[f]);var p=a;r()}([])</script><script src="/[[.RootPath]]/static/js/2.260e42b2.chunk.js"></script><script src="/[[.RootPath]]/static/js/main.525ff6d9.chunk.js"></script></body></html>
|
||||||
>>>>>>> 42627f3... Show metrics icon in sidebar if prometheus-addr is specified
|
>>>>>>> 42627f3... Show metrics icon in sidebar if prometheus-addr is specified
|
||||||
|
=======
|
||||||
|
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" type="image/png" href="/[[.RootPath]]/favicon.ico"/><link rel="icon" type="image/png" sizes="32x32" href="/[[.RootPath]]/favicon-32x32.png"/><link rel="icon" type="image/png" sizes="16x16" href="/[[.RootPath]]/favicon-16x16.png"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Asynq monitoring web console"/><link rel="apple-touch-icon" sizes="180x180" href="/[[.RootPath]]/apple-touch-icon.png"/><link rel="manifest" href="/[[.RootPath]]/manifest.json"/><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"/><link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons"/><script>window.ROOT_PATH="/[[.RootPath]]",window.PROMETHEUS_SERVER_ADDRESS="/[[.PrometheusAddr]]"</script><title>Asynq - Monitoring</title></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function t(t){for(var n,i,l=t[0],a=t[1],f=t[2],c=0,s=[];c<l.length;c++)i=l[c],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&s.push(o[i][0]),o[i]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(e[n]=a[n]);for(p&&p(t);s.length;)s.shift()();return u.push.apply(u,f||[]),r()}function r(){for(var e,t=0;t<u.length;t++){for(var r=u[t],n=!0,l=1;l<r.length;l++){var a=r[l];0!==o[a]&&(n=!1)}n&&(u.splice(t--,1),e=i(i.s=r[0]))}return e}var n={},o={1:0},u=[];function i(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,i),r.l=!0,r.exports}i.m=e,i.c=n,i.d=function(e,t,r){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(i.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)i.d(r,n,function(t){return e[t]}.bind(null,n));return r},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="/[[.RootPath]]/";var l=this.webpackJsonpui=this.webpackJsonpui||[],a=l.push.bind(l);l.push=t,l=l.slice();for(var f=0;f<l.length;f++)t(l[f]);var p=a;r()}([])</script><script src="/[[.RootPath]]/static/js/2.8854b145.chunk.js"></script><script src="/[[.RootPath]]/static/js/main.aac2a828.chunk.js"></script></body></html>
|
||||||
|
>>>>>>> f697574... Add redux actions/reducer for metrics
|
||||||
|
3
ui/build/static/js/2.8854b145.chunk.js
Normal file
3
ui/build/static/js/2.8854b145.chunk.js
Normal file
File diff suppressed because one or more lines are too long
253
ui/build/static/js/2.8854b145.chunk.js.LICENSE.txt
Normal file
253
ui/build/static/js/2.8854b145.chunk.js.LICENSE.txt
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
/*
|
||||||
|
object-assign
|
||||||
|
(c) Sindre Sorhus
|
||||||
|
@license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Copyright (c) 2017 Jed Watson.
|
||||||
|
Licensed under the MIT License (MIT), see
|
||||||
|
http://jedwatson.github.io/classnames
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! Conditions:: INITIAL */
|
||||||
|
|
||||||
|
/*! Production:: $accept : expression $end */
|
||||||
|
|
||||||
|
/*! Production:: css_value : ANGLE */
|
||||||
|
|
||||||
|
/*! Production:: css_value : CHS */
|
||||||
|
|
||||||
|
/*! Production:: css_value : EMS */
|
||||||
|
|
||||||
|
/*! Production:: css_value : EXS */
|
||||||
|
|
||||||
|
/*! Production:: css_value : FREQ */
|
||||||
|
|
||||||
|
/*! Production:: css_value : LENGTH */
|
||||||
|
|
||||||
|
/*! Production:: css_value : PERCENTAGE */
|
||||||
|
|
||||||
|
/*! Production:: css_value : REMS */
|
||||||
|
|
||||||
|
/*! Production:: css_value : RES */
|
||||||
|
|
||||||
|
/*! Production:: css_value : SUB css_value */
|
||||||
|
|
||||||
|
/*! Production:: css_value : TIME */
|
||||||
|
|
||||||
|
/*! Production:: css_value : VHS */
|
||||||
|
|
||||||
|
/*! Production:: css_value : VMAXS */
|
||||||
|
|
||||||
|
/*! Production:: css_value : VMINS */
|
||||||
|
|
||||||
|
/*! Production:: css_value : VWS */
|
||||||
|
|
||||||
|
/*! Production:: css_variable : CSS_VAR LPAREN CSS_CPROP COMMA math_expression RPAREN */
|
||||||
|
|
||||||
|
/*! Production:: css_variable : CSS_VAR LPAREN CSS_CPROP RPAREN */
|
||||||
|
|
||||||
|
/*! Production:: expression : math_expression EOF */
|
||||||
|
|
||||||
|
/*! Production:: math_expression : LPAREN math_expression RPAREN */
|
||||||
|
|
||||||
|
/*! Production:: math_expression : NESTED_CALC LPAREN math_expression RPAREN */
|
||||||
|
|
||||||
|
/*! Production:: math_expression : SUB PREFIX SUB NESTED_CALC LPAREN math_expression RPAREN */
|
||||||
|
|
||||||
|
/*! Production:: math_expression : css_value */
|
||||||
|
|
||||||
|
/*! Production:: math_expression : css_variable */
|
||||||
|
|
||||||
|
/*! Production:: math_expression : math_expression ADD math_expression */
|
||||||
|
|
||||||
|
/*! Production:: math_expression : math_expression DIV math_expression */
|
||||||
|
|
||||||
|
/*! Production:: math_expression : math_expression MUL math_expression */
|
||||||
|
|
||||||
|
/*! Production:: math_expression : math_expression SUB math_expression */
|
||||||
|
|
||||||
|
/*! Production:: math_expression : value */
|
||||||
|
|
||||||
|
/*! Production:: value : NUMBER */
|
||||||
|
|
||||||
|
/*! Production:: value : SUB NUMBER */
|
||||||
|
|
||||||
|
/*! Rule:: $ */
|
||||||
|
|
||||||
|
/*! Rule:: (--[0-9a-z-A-Z-]*) */
|
||||||
|
|
||||||
|
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)% */
|
||||||
|
|
||||||
|
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)Hz\b */
|
||||||
|
|
||||||
|
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)\b */
|
||||||
|
|
||||||
|
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)ch\b */
|
||||||
|
|
||||||
|
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)cm\b */
|
||||||
|
|
||||||
|
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)deg\b */
|
||||||
|
|
||||||
|
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)dpcm\b */
|
||||||
|
|
||||||
|
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)dpi\b */
|
||||||
|
|
||||||
|
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)dppx\b */
|
||||||
|
|
||||||
|
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)em\b */
|
||||||
|
|
||||||
|
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)ex\b */
|
||||||
|
|
||||||
|
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)grad\b */
|
||||||
|
|
||||||
|
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)in\b */
|
||||||
|
|
||||||
|
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)kHz\b */
|
||||||
|
|
||||||
|
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)mm\b */
|
||||||
|
|
||||||
|
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)ms\b */
|
||||||
|
|
||||||
|
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)pc\b */
|
||||||
|
|
||||||
|
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)pt\b */
|
||||||
|
|
||||||
|
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)px\b */
|
||||||
|
|
||||||
|
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)rad\b */
|
||||||
|
|
||||||
|
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)rem\b */
|
||||||
|
|
||||||
|
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)s\b */
|
||||||
|
|
||||||
|
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)turn\b */
|
||||||
|
|
||||||
|
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)vh\b */
|
||||||
|
|
||||||
|
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)vmax\b */
|
||||||
|
|
||||||
|
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)vmin\b */
|
||||||
|
|
||||||
|
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)vw\b */
|
||||||
|
|
||||||
|
/*! Rule:: ([a-z]+) */
|
||||||
|
|
||||||
|
/*! Rule:: (calc) */
|
||||||
|
|
||||||
|
/*! Rule:: (var) */
|
||||||
|
|
||||||
|
/*! Rule:: , */
|
||||||
|
|
||||||
|
/*! Rule:: - */
|
||||||
|
|
||||||
|
/*! Rule:: \( */
|
||||||
|
|
||||||
|
/*! Rule:: \) */
|
||||||
|
|
||||||
|
/*! Rule:: \* */
|
||||||
|
|
||||||
|
/*! Rule:: \+ */
|
||||||
|
|
||||||
|
/*! Rule:: \/ */
|
||||||
|
|
||||||
|
/*! Rule:: \s+ */
|
||||||
|
|
||||||
|
/*! decimal.js-light v2.5.1 https://github.com/MikeMcl/decimal.js-light/LICENCE */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A better abstraction over CSS.
|
||||||
|
*
|
||||||
|
* @copyright Oleg Isonen (Slobodskoi) / Isonen 2014-present
|
||||||
|
* @website https://github.com/cssinjs/jss
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @license React v0.19.1
|
||||||
|
* scheduler.production.min.js
|
||||||
|
*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @license React v16.10.2
|
||||||
|
* react-is.production.min.js
|
||||||
|
*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @license React v16.13.1
|
||||||
|
* react-is.production.min.js
|
||||||
|
*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @license React v16.14.0
|
||||||
|
* react-dom.production.min.js
|
||||||
|
*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @license React v16.14.0
|
||||||
|
* react-jsx-runtime.production.min.js
|
||||||
|
*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @license React v16.14.0
|
||||||
|
* react.production.min.js
|
||||||
|
*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @license React v17.0.1
|
||||||
|
* react-is.production.min.js
|
||||||
|
*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**!
|
||||||
|
* @fileOverview Kickass library to create and place poppers near their reference elements.
|
||||||
|
* @version 1.16.1-lts
|
||||||
|
* @license
|
||||||
|
* Copyright (c) 2016 Federico Zivolo and contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
1
ui/build/static/js/2.8854b145.chunk.js.map
Normal file
1
ui/build/static/js/2.8854b145.chunk.js.map
Normal file
File diff suppressed because one or more lines are too long
2
ui/build/static/js/main.aac2a828.chunk.js
Normal file
2
ui/build/static/js/main.aac2a828.chunk.js
Normal file
File diff suppressed because one or more lines are too long
1
ui/build/static/js/main.aac2a828.chunk.js.map
Normal file
1
ui/build/static/js/main.aac2a828.chunk.js.map
Normal file
File diff suppressed because one or more lines are too long
45
ui/src/actions/metricsActions.ts
Normal file
45
ui/src/actions/metricsActions.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import { Dispatch } from "redux";
|
||||||
|
import { getMetrics, MetricsResponse } from "../api";
|
||||||
|
import { toErrorString, toErrorStringWithHttpStatus } from "../utils";
|
||||||
|
|
||||||
|
// List of metrics related action types.
|
||||||
|
export const GET_METRICS_BEGIN = "GET_METRICS_BEGIN";
|
||||||
|
export const GET_METRICS_SUCCESS = "GET_METRICS_SUCCESS";
|
||||||
|
export const GET_METRICS_ERROR = "GET_METRICS_ERROR";
|
||||||
|
|
||||||
|
interface GetMetricsBeginAction {
|
||||||
|
type: typeof GET_METRICS_BEGIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GetMetricsSuccessAction {
|
||||||
|
type: typeof GET_METRICS_SUCCESS;
|
||||||
|
payload: MetricsResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GetMetricsErrorAction {
|
||||||
|
type: typeof GET_METRICS_ERROR;
|
||||||
|
error: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Union of all metrics related actions.
|
||||||
|
export type MetricsActionTypes =
|
||||||
|
| GetMetricsBeginAction
|
||||||
|
| GetMetricsSuccessAction
|
||||||
|
| GetMetricsErrorAction;
|
||||||
|
|
||||||
|
export function getMetricsAsync() {
|
||||||
|
return async (dispatch: Dispatch<MetricsActionTypes>) => {
|
||||||
|
dispatch({ type: GET_METRICS_BEGIN });
|
||||||
|
try {
|
||||||
|
const response = await getMetrics();
|
||||||
|
console.log("DEBUG: got metrics: ", response);
|
||||||
|
dispatch({ type: GET_METRICS_SUCCESS, payload: response });
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`getMetricsAsync: ${toErrorStringWithHttpStatus(error)}`);
|
||||||
|
dispatch({
|
||||||
|
type: GET_METRICS_ERROR,
|
||||||
|
error: toErrorString(error),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@@ -76,6 +76,27 @@ export interface QueueLocation {
|
|||||||
nodes: string[]; // node addresses
|
nodes: string[]; // node addresses
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface MetricsResponse {
|
||||||
|
data: MetricsResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MetricsResult {
|
||||||
|
result: Metrics[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Metrics {
|
||||||
|
metric: MetricsInfo;
|
||||||
|
values: [number, string]; // [unixtime, value]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MetricsInfo {
|
||||||
|
__name__: string;
|
||||||
|
instance: string;
|
||||||
|
job: string;
|
||||||
|
queue: string;
|
||||||
|
state: string;
|
||||||
|
}
|
||||||
|
|
||||||
// Return value from redis INFO command.
|
// Return value from redis INFO command.
|
||||||
// See https://redis.io/commands/info#return-value.
|
// See https://redis.io/commands/info#return-value.
|
||||||
export interface RedisInfo {
|
export interface RedisInfo {
|
||||||
@@ -854,3 +875,11 @@ export async function getRedisInfo(): Promise<RedisInfoResponse> {
|
|||||||
});
|
});
|
||||||
return resp.data;
|
return resp.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getMetrics(): Promise<MetricsResponse> {
|
||||||
|
const resp = await axios({
|
||||||
|
method: "get",
|
||||||
|
url: `${BASE_URL}/metrics`,
|
||||||
|
});
|
||||||
|
return resp.data;
|
||||||
|
}
|
||||||
|
49
ui/src/reducers/metricsReducer.ts
Normal file
49
ui/src/reducers/metricsReducer.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import {
|
||||||
|
GET_METRICS_BEGIN,
|
||||||
|
GET_METRICS_ERROR,
|
||||||
|
GET_METRICS_SUCCESS,
|
||||||
|
MetricsActionTypes,
|
||||||
|
} from "../actions/metricsActions";
|
||||||
|
import { MetricsResponse } from "../api";
|
||||||
|
|
||||||
|
interface MetricsState {
|
||||||
|
loading: boolean;
|
||||||
|
error: string;
|
||||||
|
data: MetricsResponse | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialState: MetricsState = {
|
||||||
|
loading: false,
|
||||||
|
error: "",
|
||||||
|
data: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function metricsReducer(
|
||||||
|
state = initialState,
|
||||||
|
action: MetricsActionTypes
|
||||||
|
): MetricsState {
|
||||||
|
switch (action.type) {
|
||||||
|
case GET_METRICS_BEGIN:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
loading: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
case GET_METRICS_ERROR:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
loading: false,
|
||||||
|
error: action.error,
|
||||||
|
};
|
||||||
|
|
||||||
|
case GET_METRICS_SUCCESS:
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
error: "",
|
||||||
|
data: action.payload,
|
||||||
|
};
|
||||||
|
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
@@ -7,6 +7,7 @@ import schedulerEntriesReducer from "./reducers/schedulerEntriesReducer";
|
|||||||
import snackbarReducer from "./reducers/snackbarReducer";
|
import snackbarReducer from "./reducers/snackbarReducer";
|
||||||
import queueStatsReducer from "./reducers/queueStatsReducer";
|
import queueStatsReducer from "./reducers/queueStatsReducer";
|
||||||
import redisInfoReducer from "./reducers/redisInfoReducer";
|
import redisInfoReducer from "./reducers/redisInfoReducer";
|
||||||
|
import metricsReducer from "./reducers/metricsReducer";
|
||||||
import { loadState } from "./localStorage";
|
import { loadState } from "./localStorage";
|
||||||
|
|
||||||
const rootReducer = combineReducers({
|
const rootReducer = combineReducers({
|
||||||
@@ -18,6 +19,7 @@ const rootReducer = combineReducers({
|
|||||||
snackbar: snackbarReducer,
|
snackbar: snackbarReducer,
|
||||||
queueStats: queueStatsReducer,
|
queueStats: queueStatsReducer,
|
||||||
redis: redisInfoReducer,
|
redis: redisInfoReducer,
|
||||||
|
metrics: metricsReducer,
|
||||||
});
|
});
|
||||||
|
|
||||||
const preloadedState = loadState();
|
const preloadedState = loadState();
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { createMuiTheme, Theme } from "@material-ui/core/styles";
|
import { createTheme, Theme } from "@material-ui/core/styles";
|
||||||
import { ThemePreference } from "./reducers/settingsReducer";
|
import { ThemePreference } from "./reducers/settingsReducer";
|
||||||
import useMediaQuery from "@material-ui/core/useMediaQuery";
|
import useMediaQuery from "@material-ui/core/useMediaQuery";
|
||||||
|
|
||||||
@@ -9,7 +9,7 @@ export function useTheme(themePreference: ThemePreference): Theme {
|
|||||||
} else if (themePreference === ThemePreference.Never) {
|
} else if (themePreference === ThemePreference.Never) {
|
||||||
prefersDarkMode = false;
|
prefersDarkMode = false;
|
||||||
}
|
}
|
||||||
return createMuiTheme({
|
return createTheme({
|
||||||
// Got color palette from https://htmlcolors.com/palette/31/stripe
|
// Got color palette from https://htmlcolors.com/palette/31/stripe
|
||||||
palette: {
|
palette: {
|
||||||
primary: {
|
primary: {
|
||||||
|
@@ -1,7 +1,11 @@
|
|||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
|
import { connect, ConnectedProps } from "react-redux";
|
||||||
import { makeStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import Container from "@material-ui/core/Container";
|
import Container from "@material-ui/core/Container";
|
||||||
import Grid from "@material-ui/core/Grid";
|
import Grid from "@material-ui/core/Grid";
|
||||||
|
import { getMetricsAsync } from "../actions/metricsActions";
|
||||||
|
import { AppState } from "../store";
|
||||||
|
import { usePolling } from "../hooks";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
container: {
|
container: {
|
||||||
@@ -10,12 +14,23 @@ const useStyles = makeStyles((theme) => ({
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
function MetricsView() {
|
function mapStateToProps(state: AppState) {
|
||||||
const classes = useStyles();
|
return {
|
||||||
|
loading: state.metrics.loading,
|
||||||
|
error: state.metrics.error,
|
||||||
|
data: state.metrics.data,
|
||||||
|
pollInterval: state.settings.pollInterval,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
const connector = connect(mapStateToProps, { getMetricsAsync });
|
||||||
console.log("TODO: Get metrics data!");
|
type Props = ConnectedProps<typeof connector>;
|
||||||
}, []);
|
|
||||||
|
function MetricsView(props: Props) {
|
||||||
|
const classes = useStyles();
|
||||||
|
const { pollInterval, getMetricsAsync } = props;
|
||||||
|
|
||||||
|
usePolling(getMetricsAsync, pollInterval);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container maxWidth="lg" className={classes.container}>
|
<Container maxWidth="lg" className={classes.container}>
|
||||||
@@ -28,4 +43,4 @@ function MetricsView() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default MetricsView;
|
export default connector(MetricsView);
|
||||||
|
Reference in New Issue
Block a user