mirror of
https://github.com/openziti/zrok.git
synced 2024-12-22 14:50:55 +01:00
environment metrics wired in and working (#324)
This commit is contained in:
parent
0f6d05f449
commit
43e6c56ec1
@ -94,13 +94,9 @@ func (h *getEnvironmentMetricsHandler) Handle(params metadata.GetEnvironmentMetr
|
||||
return metadata.NewGetEnvironmentMetricsInternalServerError()
|
||||
}
|
||||
defer func() { _ = trx.Rollback() }()
|
||||
env, err := str.GetEnvironment(int(params.EnvID), trx)
|
||||
env, err := str.FindEnvironmentForAccount(params.EnvID, int(principal.ID), trx)
|
||||
if err != nil {
|
||||
logrus.Errorf("error finding environment '%d': %v", int(params.EnvID), err)
|
||||
return metadata.NewGetEnvironmentMetricsUnauthorized()
|
||||
}
|
||||
if int64(env.Id) != principal.ID {
|
||||
logrus.Errorf("unauthorized environemnt '%d' for '%v'", int(params.EnvID), principal.Email)
|
||||
logrus.Errorf("error finding environment '%s' for '%s': %v", params.EnvID, principal.Email, err)
|
||||
return metadata.NewGetEnvironmentMetricsUnauthorized()
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,6 @@ import (
|
||||
"github.com/go-openapi/runtime"
|
||||
cr "github.com/go-openapi/runtime/client"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// NewGetEnvironmentMetricsParams creates a new GetEnvironmentMetricsParams object,
|
||||
@ -66,7 +65,7 @@ type GetEnvironmentMetricsParams struct {
|
||||
Duration *string
|
||||
|
||||
// EnvID.
|
||||
EnvID float64
|
||||
EnvID string
|
||||
|
||||
timeout time.Duration
|
||||
Context context.Context
|
||||
@ -133,13 +132,13 @@ func (o *GetEnvironmentMetricsParams) SetDuration(duration *string) {
|
||||
}
|
||||
|
||||
// WithEnvID adds the envID to the get environment metrics params
|
||||
func (o *GetEnvironmentMetricsParams) WithEnvID(envID float64) *GetEnvironmentMetricsParams {
|
||||
func (o *GetEnvironmentMetricsParams) WithEnvID(envID string) *GetEnvironmentMetricsParams {
|
||||
o.SetEnvID(envID)
|
||||
return o
|
||||
}
|
||||
|
||||
// SetEnvID adds the envId to the get environment metrics params
|
||||
func (o *GetEnvironmentMetricsParams) SetEnvID(envID float64) {
|
||||
func (o *GetEnvironmentMetricsParams) SetEnvID(envID string) {
|
||||
o.EnvID = envID
|
||||
}
|
||||
|
||||
@ -169,7 +168,7 @@ func (o *GetEnvironmentMetricsParams) WriteToRequest(r runtime.ClientRequest, re
|
||||
}
|
||||
|
||||
// path param envId
|
||||
if err := r.SetPathParam("envId", swag.FormatFloat64(o.EnvID)); err != nil {
|
||||
if err := r.SetPathParam("envId", o.EnvID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -567,7 +567,7 @@ func init() {
|
||||
"operationId": "getEnvironmentMetrics",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "number",
|
||||
"type": "string",
|
||||
"name": "envId",
|
||||
"in": "path",
|
||||
"required": true
|
||||
@ -2003,7 +2003,7 @@ func init() {
|
||||
"operationId": "getEnvironmentMetrics",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "number",
|
||||
"type": "string",
|
||||
"name": "envId",
|
||||
"in": "path",
|
||||
"required": true
|
||||
|
@ -12,7 +12,6 @@ import (
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// NewGetEnvironmentMetricsParams creates a new GetEnvironmentMetricsParams object
|
||||
@ -40,7 +39,7 @@ type GetEnvironmentMetricsParams struct {
|
||||
Required: true
|
||||
In: path
|
||||
*/
|
||||
EnvID float64
|
||||
EnvID string
|
||||
}
|
||||
|
||||
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
|
||||
@ -96,12 +95,7 @@ func (o *GetEnvironmentMetricsParams) bindEnvID(rawData []string, hasKey bool, f
|
||||
|
||||
// Required: true
|
||||
// Parameter is provided by construction from the route
|
||||
|
||||
value, err := swag.ConvertFloat64(raw)
|
||||
if err != nil {
|
||||
return errors.InvalidType("envId", "path", "float64", raw)
|
||||
}
|
||||
o.EnvID = value
|
||||
o.EnvID = raw
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -10,13 +10,11 @@ import (
|
||||
"net/url"
|
||||
golangswaggerpaths "path"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// GetEnvironmentMetricsURL generates an URL for the get environment metrics operation
|
||||
type GetEnvironmentMetricsURL struct {
|
||||
EnvID float64
|
||||
EnvID string
|
||||
|
||||
Duration *string
|
||||
|
||||
@ -46,7 +44,7 @@ func (o *GetEnvironmentMetricsURL) Build() (*url.URL, error) {
|
||||
|
||||
var _path = "/metrics/environment/{envId}"
|
||||
|
||||
envID := swag.FormatFloat64(o.EnvID)
|
||||
envID := o.EnvID
|
||||
if envID != "" {
|
||||
_path = strings.Replace(_path, "{envId}", envID, -1)
|
||||
} else {
|
||||
|
@ -425,7 +425,7 @@ paths:
|
||||
parameters:
|
||||
- name: envId
|
||||
in: path
|
||||
type: number
|
||||
type: string
|
||||
required: true
|
||||
- name: duration
|
||||
in: query
|
||||
|
@ -56,7 +56,7 @@ export function getAccountMetrics(options) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} envId
|
||||
* @param {string} envId
|
||||
* @param {object} options Optional options
|
||||
* @param {string} [options.duration]
|
||||
* @return {Promise<module:types.metrics>} environment metrics
|
||||
|
@ -7,6 +7,7 @@ import React, {useEffect, useState} from "react";
|
||||
import * as metadata from "../../../api/metadata";
|
||||
import { Bar, BarChart, CartesianGrid, ResponsiveContainer, XAxis, YAxis } from "recharts";
|
||||
import moment from "moment";
|
||||
import {buildMetrics, bytesToSize} from "../../metrics";
|
||||
|
||||
const AccountDetail = (props) => {
|
||||
const customProperties = {
|
||||
@ -28,7 +29,7 @@ const AccountDetail = (props) => {
|
||||
);
|
||||
}
|
||||
|
||||
const MetricsTab = (props) => {
|
||||
const MetricsTab = () => {
|
||||
const [metrics30, setMetrics30] = useState(buildMetrics([]));
|
||||
const [metrics7, setMetrics7] = useState(buildMetrics([]));
|
||||
const [metrics1, setMetrics1] = useState(buildMetrics([]));
|
||||
@ -147,38 +148,4 @@ const MetricsTab = (props) => {
|
||||
);
|
||||
}
|
||||
|
||||
const buildMetrics = (m) => {
|
||||
let metrics = {
|
||||
data: m.samples,
|
||||
rx: 0,
|
||||
tx: 0
|
||||
}
|
||||
if(m.samples) {
|
||||
m.samples.forEach(s => {
|
||||
metrics.rx += s.rx;
|
||||
metrics.tx += s.tx;
|
||||
});
|
||||
}
|
||||
return metrics;
|
||||
}
|
||||
|
||||
const bytesToSize = (sz) => {
|
||||
let absSz = sz;
|
||||
if(absSz < 0) {
|
||||
absSz *= -1;
|
||||
}
|
||||
const unit = 1000
|
||||
if(absSz < unit) {
|
||||
return '' + absSz + ' B';
|
||||
}
|
||||
let div = unit
|
||||
let exp = 0
|
||||
for(let n = absSz / unit; n >= unit; n /= unit) {
|
||||
div *= unit;
|
||||
exp++;
|
||||
}
|
||||
|
||||
return '' + (sz / div).toFixed(1) + ' ' + "kMGTPE"[exp] + 'B';
|
||||
}
|
||||
|
||||
export default AccountDetail;
|
@ -6,6 +6,7 @@ import {mdiConsoleNetwork} from "@mdi/js";
|
||||
import {getEnvironmentDetail} from "../../../api/metadata";
|
||||
import DetailTab from "./DetailTab";
|
||||
import ActionsTab from "./ActionsTab";
|
||||
import MetricsTab from "./MetricsTab";
|
||||
|
||||
const EnvironmentDetail = (props) => {
|
||||
const [detail, setDetail] = useState({});
|
||||
@ -25,6 +26,9 @@ const EnvironmentDetail = (props) => {
|
||||
<Tab eventKey={"shares"} title={"Shares"}>
|
||||
<SharesTab selection={props.selection} />
|
||||
</Tab>
|
||||
<Tab eventKey={"metrics"} title={"Metrics"}>
|
||||
<MetricsTab selection={props.selection} />
|
||||
</Tab>
|
||||
<Tab eventKey={"detail"} title={"Detail"}>
|
||||
<DetailTab environment={detail.environment} />
|
||||
</Tab>
|
||||
|
129
ui/src/console/detail/environment/MetricsTab.js
Normal file
129
ui/src/console/detail/environment/MetricsTab.js
Normal file
@ -0,0 +1,129 @@
|
||||
import React, {useEffect, useState} from "react";
|
||||
import {buildMetrics, bytesToSize} from "../../metrics";
|
||||
import * as metadata from "../../../api/metadata";
|
||||
import {Col, Container, Row, Tooltip} from "react-bootstrap";
|
||||
import {Bar, BarChart, CartesianGrid, ResponsiveContainer, XAxis, YAxis} from "recharts";
|
||||
import moment from "moment/moment";
|
||||
|
||||
const MetricsTab = (props) => {
|
||||
const [metrics30, setMetrics30] = useState(buildMetrics([]));
|
||||
const [metrics7, setMetrics7] = useState(buildMetrics([]));
|
||||
const [metrics1, setMetrics1] = useState(buildMetrics([]));
|
||||
|
||||
console.log("selection", props.selection);
|
||||
|
||||
useEffect(() => {
|
||||
metadata.getEnvironmentMetrics(props.selection.id)
|
||||
.then(resp => {
|
||||
setMetrics30(buildMetrics(resp.data));
|
||||
});
|
||||
metadata.getEnvironmentMetrics(props.selection.id, {duration: "168h"})
|
||||
.then(resp => {
|
||||
setMetrics7(buildMetrics(resp.data));
|
||||
});
|
||||
metadata.getEnvironmentMetrics(props.selection.id, {duration: "24h"})
|
||||
.then(resp => {
|
||||
setMetrics1(buildMetrics(resp.data));
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
let mounted = true;
|
||||
let interval = setInterval(() => {
|
||||
metadata.getEnvironmentMetrics(props.selection.id)
|
||||
.then(resp => {
|
||||
if(mounted) {
|
||||
setMetrics30(buildMetrics(resp.data));
|
||||
}
|
||||
});
|
||||
metadata.getEnvironmentMetrics(props.selection.id, {duration: "168h"})
|
||||
.then(resp => {
|
||||
setMetrics7(buildMetrics(resp.data));
|
||||
});
|
||||
metadata.getEnvironmentMetrics(props.selection.id, {duration: "24h"})
|
||||
.then(resp => {
|
||||
setMetrics1(buildMetrics(resp.data));
|
||||
});
|
||||
}, 5000);
|
||||
return () => {
|
||||
mounted = false;
|
||||
clearInterval(interval);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Row>
|
||||
<Col>
|
||||
<h3>Last 30 Days:</h3>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col><p>Received: {bytesToSize(metrics30.rx)}</p></Col>
|
||||
<Col><p>Sent: {bytesToSize(metrics30.tx)}</p></Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col>
|
||||
<ResponsiveContainer width={"100%"} height={150}>
|
||||
<BarChart data={metrics30.data}>
|
||||
<CartesianGrid strokeDasharay={"3 3"} />
|
||||
<XAxis dataKey={(v) => v.timestamp} scale={"time"} tickFormatter={(v) => moment(v).format("MMM DD") } style={{ fontSize: '75%'}}/>
|
||||
<YAxis tickFormatter={(v) => bytesToSize(v)} style={{ fontSize: '75%' }}/>
|
||||
<Bar stroke={"#231069"} fill={"#04adef"} dataKey={"rx"} legendType={"circle"}/>
|
||||
<Bar stroke={"#231069"} fill={"#9BF316"} dataKey={"tx"} />
|
||||
<Tooltip />
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col>
|
||||
<h3>Last 7 Days:</h3>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col><p>Received: {bytesToSize(metrics7.rx)}</p></Col>
|
||||
<Col><p>Sent: {bytesToSize(metrics7.tx)}</p></Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col>
|
||||
<ResponsiveContainer width={"100%"} height={150}>
|
||||
<BarChart data={metrics7.data}>
|
||||
<CartesianGrid strokeDasharay={"3 3"} />
|
||||
<XAxis dataKey={(v) => v.timestamp} scale={"time"} tickFormatter={(v) => moment(v).format("MMM DD") } style={{ fontSize: '75%'}}/>
|
||||
<YAxis tickFormatter={(v) => bytesToSize(v)} style={{ fontSize: '75%' }}/>
|
||||
<Bar stroke={"#231069"} fill={"#04adef"} dataKey={"rx"} legendType={"circle"}/>
|
||||
<Bar stroke={"#231069"} fill={"#9BF316"} dataKey={"tx"} />
|
||||
<Tooltip />
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col>
|
||||
<h3>Last 24 Hours:</h3>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col><p>Received: {bytesToSize(metrics1.rx)}</p></Col>
|
||||
<Col><p>Sent: {bytesToSize(metrics1.tx)}</p></Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col>
|
||||
<ResponsiveContainer width={"100%"} height={150}>
|
||||
<BarChart data={metrics1.data}>
|
||||
<CartesianGrid strokeDasharay={"3 3"} />
|
||||
<XAxis dataKey={(v) => v.timestamp} scale={"time"} tickFormatter={(v) => moment(v).format("MMM DD") } style={{ fontSize: '75%'}}/>
|
||||
<YAxis tickFormatter={(v) => bytesToSize(v)} style={{ fontSize: '75%' }}/>
|
||||
<Bar stroke={"#231069"} fill={"#04adef"} dataKey={"rx"} legendType={"circle"}/>
|
||||
<Bar stroke={"#231069"} fill={"#9BF316"} dataKey={"tx"} />
|
||||
<Tooltip />
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
export default MetricsTab;
|
33
ui/src/console/metrics.js
Normal file
33
ui/src/console/metrics.js
Normal file
@ -0,0 +1,33 @@
|
||||
export const buildMetrics = (m) => {
|
||||
let metrics = {
|
||||
data: m.samples,
|
||||
rx: 0,
|
||||
tx: 0
|
||||
}
|
||||
if(m.samples) {
|
||||
m.samples.forEach(s => {
|
||||
metrics.rx += s.rx;
|
||||
metrics.tx += s.tx;
|
||||
});
|
||||
}
|
||||
return metrics;
|
||||
}
|
||||
|
||||
export const bytesToSize = (sz) => {
|
||||
let absSz = sz;
|
||||
if(absSz < 0) {
|
||||
absSz *= -1;
|
||||
}
|
||||
const unit = 1000
|
||||
if(absSz < unit) {
|
||||
return '' + absSz + ' B';
|
||||
}
|
||||
let div = unit
|
||||
let exp = 0
|
||||
for(let n = absSz / unit; n >= unit; n /= unit) {
|
||||
div *= unit;
|
||||
exp++;
|
||||
}
|
||||
|
||||
return '' + (sz / div).toFixed(1) + ' ' + "kMGTPE"[exp] + 'B';
|
||||
}
|
Loading…
Reference in New Issue
Block a user