mirror of
https://github.com/crocofied/CoreControl.git
synced 2025-12-17 23:47:13 +00:00
Finish úptime display
This commit is contained in:
parent
a84a985645
commit
00a628031e
124
agent/main.go
124
agent/main.go
@ -7,6 +7,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@ -36,6 +37,7 @@ type Server struct {
|
|||||||
CpuUsage sql.NullFloat64
|
CpuUsage sql.NullFloat64
|
||||||
RamUsage sql.NullFloat64
|
RamUsage sql.NullFloat64
|
||||||
DiskUsage sql.NullFloat64
|
DiskUsage sql.NullFloat64
|
||||||
|
Uptime sql.NullString
|
||||||
}
|
}
|
||||||
|
|
||||||
type CPUResponse struct {
|
type CPUResponse struct {
|
||||||
@ -61,6 +63,10 @@ type FSResponse []struct {
|
|||||||
Percent float64 `json:"percent"`
|
Percent float64 `json:"percent"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UptimeResponse struct {
|
||||||
|
Value string `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
type Notification struct {
|
type Notification struct {
|
||||||
ID int
|
ID int
|
||||||
Enabled bool
|
Enabled bool
|
||||||
@ -403,25 +409,26 @@ func checkAndUpdateServerStatus(db *sql.DB, client *http.Client, servers []Serve
|
|||||||
baseURL := strings.TrimSuffix(server.MonitoringURL.String, "/")
|
baseURL := strings.TrimSuffix(server.MonitoringURL.String, "/")
|
||||||
var cpuUsage, ramUsage, diskUsage float64
|
var cpuUsage, ramUsage, diskUsage float64
|
||||||
var online = true
|
var online = true
|
||||||
|
var uptimeStr string
|
||||||
|
|
||||||
// Get CPU usage
|
// Get CPU usage
|
||||||
cpuResp, err := client.Get(fmt.Sprintf("%s/api/4/cpu", baseURL))
|
cpuResp, err := client.Get(fmt.Sprintf("%s/api/4/cpu", baseURL))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("%s CPU request failed: %v\n", logPrefix, err)
|
fmt.Printf("%s CPU request failed: %v\n", logPrefix, err)
|
||||||
updateServerStatus(db, server.ID, false, 0, 0, 0)
|
updateServerStatus(db, server.ID, false, 0, 0, 0, "")
|
||||||
online = false
|
online = false
|
||||||
} else {
|
} else {
|
||||||
defer cpuResp.Body.Close()
|
defer cpuResp.Body.Close()
|
||||||
|
|
||||||
if cpuResp.StatusCode != http.StatusOK {
|
if cpuResp.StatusCode != http.StatusOK {
|
||||||
fmt.Printf("%s Bad CPU status code: %d\n", logPrefix, cpuResp.StatusCode)
|
fmt.Printf("%s Bad CPU status code: %d\n", logPrefix, cpuResp.StatusCode)
|
||||||
updateServerStatus(db, server.ID, false, 0, 0, 0)
|
updateServerStatus(db, server.ID, false, 0, 0, 0, "")
|
||||||
online = false
|
online = false
|
||||||
} else {
|
} else {
|
||||||
var cpuData CPUResponse
|
var cpuData CPUResponse
|
||||||
if err := json.NewDecoder(cpuResp.Body).Decode(&cpuData); err != nil {
|
if err := json.NewDecoder(cpuResp.Body).Decode(&cpuData); err != nil {
|
||||||
fmt.Printf("%s Failed to parse CPU JSON: %v\n", logPrefix, err)
|
fmt.Printf("%s Failed to parse CPU JSON: %v\n", logPrefix, err)
|
||||||
updateServerStatus(db, server.ID, false, 0, 0, 0)
|
updateServerStatus(db, server.ID, false, 0, 0, 0, "")
|
||||||
online = false
|
online = false
|
||||||
} else {
|
} else {
|
||||||
cpuUsage = cpuData.Total
|
cpuUsage = cpuData.Total
|
||||||
@ -429,25 +436,59 @@ func checkAndUpdateServerStatus(db *sql.DB, client *http.Client, servers []Serve
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get uptime if server is online
|
||||||
|
if online {
|
||||||
|
uptimeResp, err := client.Get(fmt.Sprintf("%s/api/4/uptime", baseURL))
|
||||||
|
if err == nil && uptimeResp.StatusCode == http.StatusOK {
|
||||||
|
defer uptimeResp.Body.Close()
|
||||||
|
|
||||||
|
// Read the response body as a string first
|
||||||
|
uptimeBytes, err := io.ReadAll(uptimeResp.Body)
|
||||||
|
if err == nil {
|
||||||
|
uptimeStr = strings.Trim(string(uptimeBytes), "\"")
|
||||||
|
|
||||||
|
// Try to parse as JSON object first, then fallback to direct string if that fails
|
||||||
|
var uptimeData UptimeResponse
|
||||||
|
if jsonErr := json.Unmarshal(uptimeBytes, &uptimeData); jsonErr == nil && uptimeData.Value != "" {
|
||||||
|
uptimeStr = formatUptime(uptimeData.Value)
|
||||||
|
} else {
|
||||||
|
// Use the string directly
|
||||||
|
uptimeStr = formatUptime(uptimeStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%s Uptime: %s (formatted: %s)\n", logPrefix, string(uptimeBytes), uptimeStr)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("%s Failed to read uptime response: %v\n", logPrefix, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("%s Uptime request failed: %v\n", logPrefix, err)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("%s Bad uptime status code: %d\n", logPrefix, uptimeResp.StatusCode)
|
||||||
|
uptimeResp.Body.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if online {
|
if online {
|
||||||
// Get Memory usage
|
// Get Memory usage
|
||||||
memResp, err := client.Get(fmt.Sprintf("%s/api/4/mem", baseURL))
|
memResp, err := client.Get(fmt.Sprintf("%s/api/4/mem", baseURL))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("%s Memory request failed: %v\n", logPrefix, err)
|
fmt.Printf("%s Memory request failed: %v\n", logPrefix, err)
|
||||||
updateServerStatus(db, server.ID, false, 0, 0, 0)
|
updateServerStatus(db, server.ID, false, 0, 0, 0, "")
|
||||||
online = false
|
online = false
|
||||||
} else {
|
} else {
|
||||||
defer memResp.Body.Close()
|
defer memResp.Body.Close()
|
||||||
|
|
||||||
if memResp.StatusCode != http.StatusOK {
|
if memResp.StatusCode != http.StatusOK {
|
||||||
fmt.Printf("%s Bad memory status code: %d\n", logPrefix, memResp.StatusCode)
|
fmt.Printf("%s Bad memory status code: %d\n", logPrefix, memResp.StatusCode)
|
||||||
updateServerStatus(db, server.ID, false, 0, 0, 0)
|
updateServerStatus(db, server.ID, false, 0, 0, 0, "")
|
||||||
online = false
|
online = false
|
||||||
} else {
|
} else {
|
||||||
var memData MemoryResponse
|
var memData MemoryResponse
|
||||||
if err := json.NewDecoder(memResp.Body).Decode(&memData); err != nil {
|
if err := json.NewDecoder(memResp.Body).Decode(&memData); err != nil {
|
||||||
fmt.Printf("%s Failed to parse memory JSON: %v\n", logPrefix, err)
|
fmt.Printf("%s Failed to parse memory JSON: %v\n", logPrefix, err)
|
||||||
updateServerStatus(db, server.ID, false, 0, 0, 0)
|
updateServerStatus(db, server.ID, false, 0, 0, 0, "")
|
||||||
online = false
|
online = false
|
||||||
} else {
|
} else {
|
||||||
ramUsage = memData.Percent
|
ramUsage = memData.Percent
|
||||||
@ -461,20 +502,20 @@ func checkAndUpdateServerStatus(db *sql.DB, client *http.Client, servers []Serve
|
|||||||
fsResp, err := client.Get(fmt.Sprintf("%s/api/4/fs", baseURL))
|
fsResp, err := client.Get(fmt.Sprintf("%s/api/4/fs", baseURL))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("%s Filesystem request failed: %v\n", logPrefix, err)
|
fmt.Printf("%s Filesystem request failed: %v\n", logPrefix, err)
|
||||||
updateServerStatus(db, server.ID, false, 0, 0, 0)
|
updateServerStatus(db, server.ID, false, 0, 0, 0, "")
|
||||||
online = false
|
online = false
|
||||||
} else {
|
} else {
|
||||||
defer fsResp.Body.Close()
|
defer fsResp.Body.Close()
|
||||||
|
|
||||||
if fsResp.StatusCode != http.StatusOK {
|
if fsResp.StatusCode != http.StatusOK {
|
||||||
fmt.Printf("%s Bad filesystem status code: %d\n", logPrefix, fsResp.StatusCode)
|
fmt.Printf("%s Bad filesystem status code: %d\n", logPrefix, fsResp.StatusCode)
|
||||||
updateServerStatus(db, server.ID, false, 0, 0, 0)
|
updateServerStatus(db, server.ID, false, 0, 0, 0, "")
|
||||||
online = false
|
online = false
|
||||||
} else {
|
} else {
|
||||||
var fsData FSResponse
|
var fsData FSResponse
|
||||||
if err := json.NewDecoder(fsResp.Body).Decode(&fsData); err != nil {
|
if err := json.NewDecoder(fsResp.Body).Decode(&fsData); err != nil {
|
||||||
fmt.Printf("%s Failed to parse filesystem JSON: %v\n", logPrefix, err)
|
fmt.Printf("%s Failed to parse filesystem JSON: %v\n", logPrefix, err)
|
||||||
updateServerStatus(db, server.ID, false, 0, 0, 0)
|
updateServerStatus(db, server.ID, false, 0, 0, 0, "")
|
||||||
online = false
|
online = false
|
||||||
} else if len(fsData) > 0 {
|
} else if len(fsData) > 0 {
|
||||||
diskUsage = fsData[0].Percent
|
diskUsage = fsData[0].Percent
|
||||||
@ -498,7 +539,7 @@ func checkAndUpdateServerStatus(db *sql.DB, client *http.Client, servers []Serve
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update server status with metrics
|
// Update server status with metrics
|
||||||
updateServerStatus(db, server.ID, online, cpuUsage, ramUsage, diskUsage)
|
updateServerStatus(db, server.ID, online, cpuUsage, ramUsage, diskUsage, uptimeStr)
|
||||||
|
|
||||||
// Add entry to server history
|
// Add entry to server history
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
@ -513,19 +554,70 @@ func checkAndUpdateServerStatus(db *sql.DB, client *http.Client, servers []Serve
|
|||||||
fmt.Printf("%s Failed to insert history: %v\n", logPrefix, err)
|
fmt.Printf("%s Failed to insert history: %v\n", logPrefix, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("%s Updated - CPU: %.2f%%, RAM: %.2f%%, Disk: %.2f%%\n",
|
fmt.Printf("%s Updated - CPU: %.2f%%, RAM: %.2f%%, Disk: %.2f%%, Uptime: %s\n",
|
||||||
logPrefix, cpuUsage, ramUsage, diskUsage)
|
logPrefix, cpuUsage, ramUsage, diskUsage, uptimeStr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateServerStatus(db *sql.DB, serverID int, online bool, cpuUsage, ramUsage, diskUsage float64) {
|
func formatUptime(uptimeStr string) string {
|
||||||
|
// Example input: "3 days, 3:52:36"
|
||||||
|
// Target output: "28.6 13:52"
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
|
||||||
|
// Parse the uptime components
|
||||||
|
parts := strings.Split(uptimeStr, ", ")
|
||||||
|
|
||||||
|
var days int
|
||||||
|
var timeStr string
|
||||||
|
|
||||||
|
if len(parts) == 2 {
|
||||||
|
// Has days part and time part
|
||||||
|
_, err := fmt.Sscanf(parts[0], "%d days", &days)
|
||||||
|
if err != nil {
|
||||||
|
// Try singular "day"
|
||||||
|
_, err = fmt.Sscanf(parts[0], "%d day", &days)
|
||||||
|
if err != nil {
|
||||||
|
return uptimeStr // Return original if parsing fails
|
||||||
|
}
|
||||||
|
}
|
||||||
|
timeStr = parts[1]
|
||||||
|
} else if len(parts) == 1 {
|
||||||
|
// Only has time part (less than a day)
|
||||||
|
days = 0
|
||||||
|
timeStr = parts[0]
|
||||||
|
} else {
|
||||||
|
return uptimeStr // Return original if format is unexpected
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the time component (hours:minutes:seconds)
|
||||||
|
var hours, minutes, seconds int
|
||||||
|
_, err := fmt.Sscanf(timeStr, "%d:%d:%d", &hours, &minutes, &seconds)
|
||||||
|
if err != nil {
|
||||||
|
return uptimeStr // Return original if parsing fails
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the total duration
|
||||||
|
duration := time.Duration(days)*24*time.Hour +
|
||||||
|
time.Duration(hours)*time.Hour +
|
||||||
|
time.Duration(minutes)*time.Minute +
|
||||||
|
time.Duration(seconds)*time.Second
|
||||||
|
|
||||||
|
// Calculate the start time by subtracting the duration from now
|
||||||
|
startTime := now.Add(-duration)
|
||||||
|
|
||||||
|
// Format the result in the required format (day.month hour:minute)
|
||||||
|
return startTime.Format("2.1 15:04")
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateServerStatus(db *sql.DB, serverID int, online bool, cpuUsage, ramUsage, diskUsage float64, uptime string) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
_, err := db.ExecContext(ctx,
|
_, err := db.ExecContext(ctx,
|
||||||
`UPDATE server SET online = $1, "cpuUsage" = $2::float8, "ramUsage" = $3::float8, "diskUsage" = $4::float8
|
`UPDATE server SET online = $1, "cpuUsage" = $2::float8, "ramUsage" = $3::float8, "diskUsage" = $4::float8, "uptime" = $5
|
||||||
WHERE id = $5`,
|
WHERE id = $6`,
|
||||||
online, cpuUsage, ramUsage, diskUsage, serverID,
|
online, cpuUsage, ramUsage, diskUsage, uptime, serverID,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Failed to update server status (ID: %d): %v\n", serverID, err)
|
fmt.Printf("Failed to update server status (ID: %d): %v\n", serverID, err)
|
||||||
|
|||||||
@ -28,7 +28,7 @@ export async function GET() {
|
|||||||
cpuUsage: server.cpuUsage ? parseInt(server.cpuUsage) : 0,
|
cpuUsage: server.cpuUsage ? parseInt(server.cpuUsage) : 0,
|
||||||
ramUsage: server.ramUsage ? parseInt(server.ramUsage) : 0,
|
ramUsage: server.ramUsage ? parseInt(server.ramUsage) : 0,
|
||||||
diskUsage: server.diskUsage ? parseInt(server.diskUsage) : 0,
|
diskUsage: server.diskUsage ? parseInt(server.diskUsage) : 0,
|
||||||
uptime: server.uptime ? parseInt(server.uptime) : 0
|
uptime: server.uptime || ""
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return NextResponse.json(monitoringData)
|
return NextResponse.json(monitoringData)
|
||||||
|
|||||||
@ -99,7 +99,7 @@ interface Server {
|
|||||||
diskUsage: number;
|
diskUsage: number;
|
||||||
history?: ServerHistory;
|
history?: ServerHistory;
|
||||||
port: number;
|
port: number;
|
||||||
uptime: number;
|
uptime: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GetServersResponse {
|
interface GetServersResponse {
|
||||||
@ -1027,7 +1027,7 @@ export default function Dashboard() {
|
|||||||
<StatusIndicator isOnline={server.online} />
|
<StatusIndicator isOnline={server.online} />
|
||||||
{server.online && server.uptime && (
|
{server.online && server.uptime && (
|
||||||
<span className="text-xs text-muted-foreground mt-1">
|
<span className="text-xs text-muted-foreground mt-1">
|
||||||
{server.online ? `since ${server.uptime}` : 'offline'}
|
since {server.uptime}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -56,6 +56,7 @@ interface Server {
|
|||||||
diskUsage: number;
|
diskUsage: number;
|
||||||
history?: ServerHistory;
|
history?: ServerHistory;
|
||||||
port: number;
|
port: number;
|
||||||
|
uptime?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GetServersResponse {
|
interface GetServersResponse {
|
||||||
@ -439,8 +440,13 @@ export default function ServerDetail() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{server.monitoring && (
|
{server.monitoring && (
|
||||||
<div className="absolute top-0 right-4">
|
<div className="absolute top-0 right-4 flex flex-col items-end">
|
||||||
<StatusIndicator isOnline={server.online} />
|
<StatusIndicator isOnline={server.online} />
|
||||||
|
{server.online && server.uptime && (
|
||||||
|
<span className="text-xs text-muted-foreground mt-1 w-max text-right whitespace-nowrap">
|
||||||
|
since {server.uptime}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
@ -600,7 +606,14 @@ export default function ServerDetail() {
|
|||||||
</NextLink>
|
</NextLink>
|
||||||
</div>
|
</div>
|
||||||
{hostedVM.monitoring && (
|
{hostedVM.monitoring && (
|
||||||
<StatusIndicator isOnline={hostedVM.online} />
|
<div className="flex flex-col items-end">
|
||||||
|
<StatusIndicator isOnline={hostedVM.online} />
|
||||||
|
{hostedVM.online && hostedVM.uptime && (
|
||||||
|
<span className="text-xs text-muted-foreground mt-1 w-max text-right whitespace-nowrap">
|
||||||
|
since {hostedVM.uptime}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user