Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Feat: use db to store stats #6

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
logs
metrics
metrics
*.db
22 changes: 11 additions & 11 deletions cmd/sentinel/container-logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,12 @@ func attachContainer(cont types.Container, ctx context.Context, apiClient *clien
name = fmt.Sprintf("%s-pr-%s", name, cont.Labels["coolify.pullRequestId"])
}
}
logFileName := fmt.Sprintf("%s/%s.txt", logsDir, name)
streamLogs(ctx, apiClient, cont, logFileName)
// logFileName := fmt.Sprintf("%s/%s.txt", logsDir, name)
streamLogs(ctx, apiClient, cont)
}(cont)
}

func streamLogs(ctx context.Context, apiClient *client.Client, cont types.Container, logFileName string) {
func streamLogs(ctx context.Context, apiClient *client.Client, cont types.Container) {
out, err := apiClient.ContainerLogs(ctx, cont.ID, container.LogsOptions{
ShowStdout: true,
ShowStderr: true,
Expand All @@ -71,17 +71,17 @@ func streamLogs(ctx context.Context, apiClient *client.Client, cont types.Contai
}
defer out.Close()

logFile, err := os.OpenFile(logFileName, os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
fmt.Printf("Error opening log file %s: %s\n", logFileName, err)
return
}
defer logFile.Close()
// logFile, err := os.OpenFile(logFileName, os.O_WRONLY|os.O_CREATE, 0666)
// if err != nil {
// fmt.Printf("Error opening log file %s: %s\n", logFileName, err)
// return
// }
// defer logFile.Close()

seenLines := make(map[string]bool)
re := regexp.MustCompile(`\x1b\[[0-9;]*m`)
stdOutWriter := newRemovingWriter(logFile, seenLines, re)
stdErrWriter := newRemovingWriter(logFile, seenLines, re)
stdOutWriter := newRemovingWriter(os.Stdout, seenLines, re)
stdErrWriter := newRemovingWriter(os.Stderr, seenLines, re)

if _, err := stdcopy.StdCopy(stdOutWriter, stdErrWriter, out); err != nil {
fmt.Printf("Error saving logs for container %s: %s\n", cont.ID, err)
Expand Down
83 changes: 15 additions & 68 deletions cmd/sentinel/containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@ import (
"fmt"
"io"
"log"
"os"
"strconv"
"strings"
"time"

"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
Expand Down Expand Up @@ -81,11 +77,12 @@ func getOneContainer(containerID string, csv bool) (string, error) {
return string(jsonData), nil

}
func getOneContainerMetrics(containerID string, csv bool) (string, error) {

func getContainerMetrics(containerID string, csv bool) (*ContainerMetrics, error) {
ctx := context.Background()
apiClient, err := client.NewClientWithOpts()
if err != nil {
return "", err
return nil, err
}
apiClient.NegotiateAPIVersion(ctx)
defer apiClient.Close()
Expand All @@ -98,11 +95,11 @@ func getOneContainerMetrics(containerID string, csv bool) (string, error) {
}
container, err := apiClient.ContainerInspect(ctx, containerID)
if err != nil {
return "", err
return nil, err
}
stats, err := apiClient.ContainerStats(ctx, container.ID, false)
if err != nil {
return "", err
return nil, err
}
var v types.StatsJSON
dec := json.NewDecoder(stats.Body)
Expand All @@ -129,77 +126,27 @@ func getOneContainerMetrics(containerID string, csv bool) (string, error) {
MemoryAvailable: v.MemoryStats.Limit,
NetworkUsage: metrics.NetworkUsage,
}
jsonData, err := json.MarshalIndent(metrics, "", " ")
if err != nil {
return "", err
}
if csv {
return fmt.Sprintf("%s,%f,%d,%f\n", metrics.Time, metrics.CPUUsagePercentage, metrics.MemoryUsed, metrics.MemoryUsagePercentage), nil
}
return string(jsonData), nil

return &metrics, nil
}

func getHistoryContainerUsage(from string, to string, containerId string) (string, error) {
fileName := "container-" + containerId + ".csv"
containerFile := metricsDir + "/" + fileName
if from == "" && to == "" {
// return everything
file, err := os.ReadFile(containerFile)
if err != nil {
fmt.Println("Failed to read file:", err)
return "", err
}
return string(file), nil
}
if from == "" {
from = "1970-01-01T00:00:00Z"
}
if to == "" {
to = time.Now().UTC().Format(time.RFC3339)
}
fromTime, err := time.Parse(time.RFC3339, from)
if err != nil {
fmt.Println("Failed to parse from time:", err)
return "", err
}
toTime, err := time.Parse(time.RFC3339, to)
func getOneContainerMetrics(containerID string, csv bool) (string, error) {

metrics, err := getContainerMetrics(containerID, csv)
if err != nil {
fmt.Println("Failed to parse to time:", err)
return "", err
}

fromTimeUnix := fromTime.UnixMilli()
toTimeUnix := toTime.UnixMilli()
file, err := os.ReadFile(containerFile)
jsonData, err := json.MarshalIndent(metrics, "", " ")
if err != nil {
fmt.Println("Failed to read file:", err)
return "", err
}
lines := string(file)
var result string
lines = lines[strings.Index(lines, "\n")+1:]
for _, line := range strings.Split(lines, "\n") {
if line == "" {
continue
}
parts := strings.Split(line, ",")
if len(parts) != 4 {
fmt.Println("Invalid line:", line)
continue
}
time, err := strconv.ParseInt(parts[0], 10, 64)
if err != nil {
fmt.Println("Failed to parse time:", err)
continue
}
if time >= fromTimeUnix && time <= toTimeUnix {
result += line + "\n"
}
if csv {
return fmt.Sprintf("%s,%f,%d,%f\n", metrics.Time, metrics.CPUUsagePercentage, metrics.MemoryUsed, metrics.MemoryUsagePercentage), nil
}
result = containerMetricsCsvHeader + result
return result, nil

return string(jsonData), nil
}

func getAllContainers() (string, error) {
ctx := context.Background()
apiClient, err := client.NewClientWithOpts()
Expand Down
79 changes: 16 additions & 63 deletions cmd/sentinel/cpu.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ package main
import (
"encoding/json"
"fmt"
"os"
"strconv"
"strings"
"log"
"sentinel/pkg/db"
"time"

"github.com/shirou/gopsutil/cpu"
Expand All @@ -23,6 +22,20 @@ type CpuUsage struct {
Percent string `json:"percent"`
}

func CollectCpuUsage() {
queryTimeInUnixString := getUnixTimeInMilliUTC()

overallPercentage, err := cpu.Percent(0, false)
if err != nil {
log.Printf("%v", err)
}
cpuUsage := CpuUsage{
Time: queryTimeInUnixString,
Percent: fmt.Sprintf("%.2f", overallPercentage[0]),
}
db.Write("cpu", int(time.Now().Unix()), cpuUsage)
}

func getCpuUsage(csv bool) (string, error) {
usages := make([]CpuUsage, 0)
queryTimeInUnixString := getUnixTimeInMilliUTC()
Expand Down Expand Up @@ -53,63 +66,3 @@ func getCpuUsage(csv bool) (string, error) {
return string(jsonData), nil

}

func getHistoryCpuUsage(from string, to string) (string, error) {
if from == "" && to == "" {
// return everything
file, err := os.ReadFile(cpuMetricsFile)
if err != nil {
fmt.Println("Failed to read file:", err)
return "", err
}
return string(file), nil
}
if from == "" {
from = "1970-01-01T00:00:00Z"
}
if to == "" {
to = time.Now().UTC().Format(time.RFC3339)
}
fromTime, err := time.Parse(time.RFC3339, from)
if err != nil {
fmt.Println("Failed to parse from time:", err)
return "", err
}
toTime, err := time.Parse(time.RFC3339, to)
if err != nil {
fmt.Println("Failed to parse to time:", err)
return "", err
}

fromTimeUnix := fromTime.UnixMilli()
toTimeUnix := toTime.UnixMilli()
file, err := os.ReadFile(cpuMetricsFile)
if err != nil {
fmt.Println("Failed to read file:", err)
return "", err
}
lines := string(file)
var result string
lines = lines[strings.Index(lines, "\n")+1:]
for _, line := range strings.Split(lines, "\n") {
if line == "" {
continue
}
parts := strings.Split(line, ",")
if len(parts) != 2 {
fmt.Println("Invalid line:", line)
continue
}
time, err := strconv.ParseInt(parts[0], 10, 64)
if err != nil {
fmt.Println("Failed to parse time:", err)
continue
}
if time >= fromTimeUnix && time <= toTimeUnix {
result += line + "\n"
}
}
result = cpuCsvHeader + result
return result, nil

}
Loading