[release] v0.12.0-unstable5
This commit is contained in:
parent
8a547e1b9c
commit
33590ce369
|
@ -1,3 +1,8 @@
|
||||||
|
## Version 0.12.0
|
||||||
|
- New Dashboard
|
||||||
|
- New metrics gathering system
|
||||||
|
- Added Button to force reset HTTPS cert in settings
|
||||||
|
|
||||||
## Version 0.11.3
|
## Version 0.11.3
|
||||||
- Fix missing even subscriber on export
|
- Fix missing even subscriber on export
|
||||||
|
|
||||||
|
|
|
@ -687,6 +687,15 @@ const ConfigManagement = () => {
|
||||||
</Stack>
|
</Stack>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<CosmosCheckbox
|
||||||
|
label={"Force HTTPS Certificate Renewal On Next Save"}
|
||||||
|
name="ForceHTTPSCertificateRenewal"
|
||||||
|
formik={formik}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</MainCard>
|
</MainCard>
|
||||||
|
|
||||||
|
|
|
@ -45,9 +45,12 @@ function toUTC(date, time) {
|
||||||
return formatDate(now, time);
|
return formatDate(now, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
const PlotComponent = ({ data, defaultSlot = 'day' }) => {
|
const PlotComponent = ({ title, data, defaultSlot = 'latest' }) => {
|
||||||
const [slot, setSlot] = useState(defaultSlot);
|
const [slot, setSlot] = useState(defaultSlot);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
const { primary, secondary } = theme.palette.text;
|
||||||
|
const line = theme.palette.divider;
|
||||||
|
const [series, setSeries] = useState([]);
|
||||||
|
|
||||||
// chart options
|
// chart options
|
||||||
const areaChartOptions = {
|
const areaChartOptions = {
|
||||||
|
@ -69,116 +72,108 @@ const PlotComponent = ({ data, defaultSlot = 'day' }) => {
|
||||||
strokeDashArray: 0
|
strokeDashArray: 0
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let hourlyDates = [];
|
|
||||||
for(let i = 0; i < 48; i++) {
|
|
||||||
let now = new Date();
|
|
||||||
now.setHours(now.getHours() - i);
|
|
||||||
now.setMinutes(0);
|
|
||||||
now.setSeconds(0);
|
|
||||||
// get as YYYY-MM-DD HH:MM:SS
|
|
||||||
hourlyDates.unshift(formatDate(now, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
let dailyDates = [];
|
|
||||||
for(let i = 0; i < 30; i++) {
|
|
||||||
let now = new Date();
|
|
||||||
now.setDate(now.getDate() - i);
|
|
||||||
dailyDates.unshift(formatDate(now));
|
|
||||||
}
|
|
||||||
|
|
||||||
const { primary, secondary } = theme.palette.text;
|
|
||||||
const line = theme.palette.divider;
|
|
||||||
|
|
||||||
const [options, setOptions] = useState(areaChartOptions);
|
const [options, setOptions] = useState(areaChartOptions);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
let xAxis = [];
|
||||||
|
|
||||||
|
if(slot === 'latest') {
|
||||||
|
for(let i = 0; i < 100; i++) {
|
||||||
|
xAxis.unshift(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(slot === 'hourly') {
|
||||||
|
for(let i = 0; i < 48; i++) {
|
||||||
|
let now = new Date();
|
||||||
|
now.setHours(now.getHours() - i);
|
||||||
|
now.setMinutes(0);
|
||||||
|
now.setSeconds(0);
|
||||||
|
xAxis.unshift(formatDate(now, true));
|
||||||
|
}
|
||||||
|
} else if(slot === 'daily') {
|
||||||
|
for(let i = 0; i < 30; i++) {
|
||||||
|
let now = new Date();
|
||||||
|
now.setDate(now.getDate() - i);
|
||||||
|
xAxis.unshift(formatDate(now));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const dataSeries = [];
|
||||||
|
data.forEach((serie) => {
|
||||||
|
dataSeries.push({
|
||||||
|
name: serie.Label,
|
||||||
|
dataAxis: xAxis.map((date) => {
|
||||||
|
if(slot === 'latest') {
|
||||||
|
return serie.Values[serie.Values.length - 1 - date] ?
|
||||||
|
serie.Values[serie.Values.length - 1 - date].Value :
|
||||||
|
0;
|
||||||
|
} else {
|
||||||
|
let key = slot === 'hourly' ? "hour_" : "day_";
|
||||||
|
let k = key + toUTC(date, slot === 'hourly');
|
||||||
|
if (k in serie.ValuesAggl) {
|
||||||
|
return serie.ValuesAggl[k].Value;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
setOptions((prevState) => ({
|
setOptions((prevState) => ({
|
||||||
...prevState,
|
...prevState,
|
||||||
colors: [theme.palette.primary.main, theme.palette.secondary.main],
|
colors: [theme.palette.primary.main, theme.palette.secondary.main],
|
||||||
xaxis: {
|
xaxis: {
|
||||||
categories:
|
categories:
|
||||||
slot === 'hourly'
|
slot === 'hourly'
|
||||||
? hourlyDates.map((date) => date.split(' ')[1])
|
? xAxis.map((date) => date.split(' ')[1])
|
||||||
: dailyDates,
|
: xAxis,
|
||||||
labels: {
|
labels: {
|
||||||
style: {
|
style: {
|
||||||
fontSize: '11px',
|
fontSize: slot === 'latest' ? '0' : '11px',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
axisBorder: {
|
axisBorder: {
|
||||||
show: true,
|
show: true,
|
||||||
color: line
|
color: line
|
||||||
},
|
},
|
||||||
tickAmount: slot === 'hourly' ? hourlyDates.length : dailyDates.length,
|
tickAmount: xAxis.length,
|
||||||
},
|
},
|
||||||
yaxis: [{
|
yaxis: data.map((thisdata, ida) => ({
|
||||||
|
opposite: ida === 1,
|
||||||
labels: {
|
labels: {
|
||||||
style: {
|
style: {
|
||||||
colors: [secondary]
|
colors: [secondary]
|
||||||
|
},
|
||||||
|
|
||||||
|
formatter: (num) => {
|
||||||
|
if (Math.abs(num) >= 1e9) {
|
||||||
|
return (num / 1e9).toFixed(1) + 'G'; // Convert to Millions
|
||||||
|
} else if (Math.abs(num) >= 1e6) {
|
||||||
|
return (num / 1e6).toFixed(1) + 'M'; // Convert to Millions
|
||||||
|
} else if (Math.abs(num) >= 1e3) {
|
||||||
|
return (num / 1e3).toFixed(1) + 'K'; // Convert to Thousands
|
||||||
|
} else {
|
||||||
|
return num.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
text: data[0].Label,
|
text: thisdata.Label,
|
||||||
}
|
}
|
||||||
},
|
})),
|
||||||
{
|
|
||||||
opposite: true,
|
|
||||||
labels: {
|
|
||||||
style: {
|
|
||||||
colors: [secondary]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
text: data[1].Label,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
grid: {
|
grid: {
|
||||||
borderColor: line
|
borderColor: line
|
||||||
},
|
},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
theme: 'light'
|
theme: theme.palette.mode,
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}, [primary, secondary, line, theme, slot]);
|
|
||||||
|
|
||||||
let dataSeries = [];
|
|
||||||
data.forEach((serie) => {
|
|
||||||
dataSeries.push({
|
|
||||||
name: serie.Label,
|
|
||||||
dataDaily: dailyDates.map((date) => {
|
|
||||||
let k = "day_" + toUTC(date);
|
|
||||||
if (k in serie.ValuesAggl) {
|
|
||||||
return serie.ValuesAggl[k].Value;
|
|
||||||
} else {
|
|
||||||
console.log(k)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
dataHourly: hourlyDates.map((date) => {
|
|
||||||
let k = "hour_" + toUTC(date, true);
|
|
||||||
if (k in serie.ValuesAggl) {
|
|
||||||
return serie.ValuesAggl[k].Value;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const [series, setSeries] = useState(dataSeries.map((serie) => {
|
|
||||||
return {
|
|
||||||
name: serie.name,
|
|
||||||
data: slot === 'hourly' ? serie.dataHourly : serie.dataDaily
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setSeries(dataSeries.map((serie) => {
|
setSeries(dataSeries.map((serie) => {
|
||||||
return {
|
return {
|
||||||
name: serie.name,
|
name: serie.name,
|
||||||
data: slot === 'hourly' ? serie.dataHourly : serie.dataDaily
|
data: serie.dataAxis
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}, [slot, data]);
|
}, [slot, data]);
|
||||||
|
@ -187,10 +182,18 @@ const PlotComponent = ({ data, defaultSlot = 'day' }) => {
|
||||||
return <Grid item xs={12} md={7} lg={8}>
|
return <Grid item xs={12} md={7} lg={8}>
|
||||||
<Grid container alignItems="center" justifyContent="space-between">
|
<Grid container alignItems="center" justifyContent="space-between">
|
||||||
<Grid item>
|
<Grid item>
|
||||||
<Typography variant="h5">Server Resources</Typography>
|
<Typography variant="h5">{title}</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item>
|
<Grid item>
|
||||||
<Stack direction="row" alignItems="center" spacing={0}>
|
<Stack direction="row" alignItems="center" spacing={0}>
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
onClick={() => setSlot('latest')}
|
||||||
|
color={slot === 'latest' ? 'primary' : 'secondary'}
|
||||||
|
variant={slot === 'latest' ? 'outlined' : 'text'}
|
||||||
|
>
|
||||||
|
Latest
|
||||||
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size="small"
|
size="small"
|
||||||
onClick={() => setSlot('hourly')}
|
onClick={() => setSlot('hourly')}
|
||||||
|
@ -211,8 +214,8 @@ const PlotComponent = ({ data, defaultSlot = 'day' }) => {
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
<MainCard content={false} sx={{ mt: 1.5 }}>
|
<MainCard content={false} sx={{ mt: 1.5 }}>
|
||||||
<Box sx={{ pt: 1, pr: 2 }} className="force-light">
|
<Box sx={{ pt: 1, pr: 2 }}>
|
||||||
<ReactApexChart options={options} series={series} type="area" height={450} />;
|
<ReactApexChart options={options} series={series} type="area" height={450} />
|
||||||
</Box>
|
</Box>
|
||||||
</MainCard>
|
</MainCard>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
@ -175,7 +175,29 @@ const DashboardDefault = () => {
|
||||||
|
|
||||||
{/* row 2 */}
|
{/* row 2 */}
|
||||||
|
|
||||||
<PlotComponent data={[metrics["cosmos.system.cpu.0"], metrics["cosmos.system.ram"]]}/>
|
<PlotComponent title={'Resources'} data={[metrics["cosmos.system.cpu.0"], metrics["cosmos.system.ram"]]}/>
|
||||||
|
|
||||||
|
<Grid item xs={12} md={5} lg={4}>
|
||||||
|
<Grid container alignItems="center" justifyContent="space-between">
|
||||||
|
<Grid item>
|
||||||
|
<Typography variant="h5">Income Overview</Typography>
|
||||||
|
</Grid>
|
||||||
|
<Grid item />
|
||||||
|
</Grid>
|
||||||
|
<MainCard sx={{ mt: 2 }} content={false}>
|
||||||
|
<Box sx={{ p: 3, pb: 0 }}>
|
||||||
|
<Stack spacing={2}>
|
||||||
|
<Typography variant="h6" color="textSecondary">
|
||||||
|
This Week Statistics
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="h3">$7,650</Typography>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
<MonthlyBarChart />
|
||||||
|
</MainCard>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<PlotComponent title={'Network'} data={[metrics["cosmos.system.netTx"], metrics["cosmos.system.netRx"]]}/>
|
||||||
|
|
||||||
<Grid item xs={12} md={5} lg={4}>
|
<Grid item xs={12} md={5} lg={4}>
|
||||||
<Grid container alignItems="center" justifyContent="space-between">
|
<Grid container alignItems="center" justifyContent="space-between">
|
||||||
|
@ -209,6 +231,7 @@ const DashboardDefault = () => {
|
||||||
<OrdersTable />
|
<OrdersTable />
|
||||||
</MainCard>
|
</MainCard>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Grid item xs={12} md={5} lg={4}>
|
<Grid item xs={12} md={5} lg={4}>
|
||||||
<Grid container alignItems="center" justifyContent="space-between">
|
<Grid container alignItems="center" justifyContent="space-between">
|
||||||
<Grid item>
|
<Grid item>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "cosmos-server",
|
"name": "cosmos-server",
|
||||||
"version": "0.12.0-unstable4",
|
"version": "0.12.0-unstable5",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "test-server.js",
|
"main": "test-server.js",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
|
@ -67,7 +67,7 @@
|
||||||
"start": "env COSMOS_CONFIG_FOLDER=/mnt/e/work/Cosmos-Server/zz_test_config/ CONFIG_FILE=./config_dev.json EZ=UTC ACME_STAGING=true build/cosmos",
|
"start": "env COSMOS_CONFIG_FOLDER=/mnt/e/work/Cosmos-Server/zz_test_config/ CONFIG_FILE=./config_dev.json EZ=UTC ACME_STAGING=true build/cosmos",
|
||||||
"build": "sh build.sh",
|
"build": "sh build.sh",
|
||||||
"dev": "npm run build && npm run start",
|
"dev": "npm run build && npm run start",
|
||||||
"dockerdevbuild": "sh build.sh && docker build -f dockerfile.local --tag cosmos-dev .",
|
"dockerdevbuild": "docker build -f dockerfile.local --tag cosmos-dev .",
|
||||||
"dockerdevrun": "docker stop cosmos-dev; docker rm cosmos-dev; docker run --cap-add NET_ADMIN -d -p 7200:443 -p 80:80 -p 53:53 -p 443:443 -p 4242:4242 -e DOCKER_HOST=tcp://host.docker.internal:2375 -e COSMOS_MONGODB=$MONGODB -e COSMOS_LOG_LEVEL=DEBUG -v /:/mnt/host --restart=unless-stopped -h cosmos-dev --name cosmos-dev cosmos-dev",
|
"dockerdevrun": "docker stop cosmos-dev; docker rm cosmos-dev; docker run --cap-add NET_ADMIN -d -p 7200:443 -p 80:80 -p 53:53 -p 443:443 -p 4242:4242 -e DOCKER_HOST=tcp://host.docker.internal:2375 -e COSMOS_MONGODB=$MONGODB -e COSMOS_LOG_LEVEL=DEBUG -v /:/mnt/host --restart=unless-stopped -h cosmos-dev --name cosmos-dev cosmos-dev",
|
||||||
"dockerdev": "npm run client-build && npm run dockerdevbuild && npm run dockerdevrun",
|
"dockerdev": "npm run client-build && npm run dockerdevbuild && npm run dockerdevrun",
|
||||||
"demo": "vite build --base=/cosmos-ui/ --mode demo",
|
"demo": "vite build --base=/cosmos-ui/ --mode demo",
|
||||||
|
|
|
@ -31,7 +31,7 @@ type DataDefDB struct {
|
||||||
AggloType string
|
AggloType string
|
||||||
}
|
}
|
||||||
|
|
||||||
func AggloMetrics() {
|
func AggloMetrics() []DataDefDB {
|
||||||
lock <- true
|
lock <- true
|
||||||
defer func() { <-lock }()
|
defer func() { <-lock }()
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ func AggloMetrics() {
|
||||||
c, errCo := utils.GetCollection(utils.GetRootAppId(), "metrics")
|
c, errCo := utils.GetCollection(utils.GetRootAppId(), "metrics")
|
||||||
if errCo != nil {
|
if errCo != nil {
|
||||||
utils.Error("Metrics - Database Connect", errCo)
|
utils.Error("Metrics - Database Connect", errCo)
|
||||||
return
|
return []DataDefDB{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// get all metrics from database
|
// get all metrics from database
|
||||||
|
@ -50,13 +50,13 @@ func AggloMetrics() {
|
||||||
cursor, err := c.Find(nil, map[string]interface{}{})
|
cursor, err := c.Find(nil, map[string]interface{}{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Error("Metrics: Error fetching metrics", err)
|
utils.Error("Metrics: Error fetching metrics", err)
|
||||||
return
|
return []DataDefDB{}
|
||||||
}
|
}
|
||||||
defer cursor.Close(nil)
|
defer cursor.Close(nil)
|
||||||
|
|
||||||
if err = cursor.All(nil, &metrics); err != nil {
|
if err = cursor.All(nil, &metrics); err != nil {
|
||||||
utils.Error("Metrics: Error decoding metrics", err)
|
utils.Error("Metrics: Error decoding metrics", err)
|
||||||
return
|
return []DataDefDB{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// populate aggregation pools
|
// populate aggregation pools
|
||||||
|
@ -153,8 +153,18 @@ func AggloMetrics() {
|
||||||
metrics[metInd] = metric
|
metrics[metInd] = metric
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return metrics
|
||||||
|
}
|
||||||
|
|
||||||
|
func CommitAggl(metrics []DataDefDB) {
|
||||||
utils.Log("Metrics: Agglomeration done. Saving to DB")
|
utils.Log("Metrics: Agglomeration done. Saving to DB")
|
||||||
|
|
||||||
|
c, errCo := utils.GetCollection(utils.GetRootAppId(), "metrics")
|
||||||
|
if errCo != nil {
|
||||||
|
utils.Error("Metrics - Database Connect", errCo)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// save metrics
|
// save metrics
|
||||||
for _, metric := range metrics {
|
for _, metric := range metrics {
|
||||||
options := options.Update().SetUpsert(true)
|
options := options.Update().SetUpsert(true)
|
||||||
|
@ -166,12 +176,18 @@ func AggloMetrics() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
utils.Log("Metrics: Agglomeration saved to DB")
|
||||||
|
}
|
||||||
|
|
||||||
|
func AggloAndCommitMetrics() {
|
||||||
|
CommitAggl(AggloMetrics())
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitAggl() {
|
func InitAggl() {
|
||||||
go func() {
|
go func() {
|
||||||
s := gocron.NewScheduler()
|
s := gocron.NewScheduler()
|
||||||
s.Every(1).Hour().From(gocron.NextTick()).Do(AggloMetrics)
|
s.Every(1).Hour().From(gocron.NextTick()).Do(AggloAndCommitMetrics)
|
||||||
// s.Every(3).Minute().From(gocron.NextTick()).Do(AggloMetrics)
|
// s.Every(3).Minute().From(gocron.NextTick()).Do(AggloMetrics)
|
||||||
|
|
||||||
s.Start()
|
s.Start()
|
||||||
|
|
|
@ -13,29 +13,9 @@ func API_GetMetrics(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(req.Method == "GET") {
|
if(req.Method == "GET") {
|
||||||
c, errCo := utils.GetCollection(utils.GetRootAppId(), "metrics")
|
|
||||||
if errCo != nil {
|
|
||||||
utils.Error("Metrics - Database Connect", errCo)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// get all metrics from database
|
|
||||||
var metrics []DataDefDB
|
|
||||||
cursor, err := c.Find(nil, map[string]interface{}{})
|
|
||||||
if err != nil {
|
|
||||||
utils.Error("Metrics: Error fetching metrics", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer cursor.Close(nil)
|
|
||||||
|
|
||||||
if err = cursor.All(nil, &metrics); err != nil {
|
|
||||||
utils.Error("Metrics: Error decoding metrics", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
json.NewEncoder(w).Encode(map[string]interface{}{
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||||
"status": "OK",
|
"status": "OK",
|
||||||
"data": metrics,
|
"data": AggloMetrics(),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
utils.Error("SettingGet: Method not allowed" + req.Method, nil)
|
utils.Error("SettingGet: Method not allowed" + req.Method, nil)
|
||||||
|
|
|
@ -124,7 +124,7 @@ func GetSystemMetrics() {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, part := range parts {
|
for _, part := range parts {
|
||||||
if strings.HasPrefix(part.Mountpoint, "/dev") || strings.HasPrefix(part.Mountpoint, "/mnt") {
|
if strings.HasPrefix(part.Mountpoint, "/dev") || (strings.HasPrefix(part.Mountpoint, "/mnt") && !strings.HasPrefix(part.Mountpoint, "/mnt/host")) {
|
||||||
realMount := part.Mountpoint
|
realMount := part.Mountpoint
|
||||||
|
|
||||||
if os.Getenv("HOSTANME") != "" {
|
if os.Getenv("HOSTANME") != "" {
|
||||||
|
|
Loading…
Reference in a new issue