From b00cd259b6fd56e43d1b00360835063527ff3817 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mert=20=C5=9Ei=C5=9Fmano=C4=9Flu?= Date: Thu, 19 Dec 2024 16:44:30 +0300 Subject: [PATCH 1/5] ci: add lint.yml - use: 'golangci/golangci-lint-action' --- .github/workflows/lint.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .github/workflows/lint.yml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..7399ce0 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,19 @@ +name: lint + +on: + pull_request: + branches: + - main + - develop + +jobs: + release: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Golangci-lint + uses: golangci/golangci-lint-action@v6.1.1 From 7a2fbd97f996b91a50ffed58130fca779453e561 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mert=20=C5=9Ei=C5=9Fmano=C4=9Flu?= Date: Thu, 19 Dec 2024 16:46:00 +0300 Subject: [PATCH 2/5] ci: change job name to lint --- .github/workflows/lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 7399ce0..c5224bb 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -7,7 +7,7 @@ on: - develop jobs: - release: + lint: runs-on: ubuntu-latest steps: - name: Checkout From acddb720cc9256992f8704f518bfe5e826b6cddd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mert=20=C5=9Ei=C5=9Fmano=C4=9Flu?= Date: Thu, 19 Dec 2024 17:33:50 +0300 Subject: [PATCH 3/5] fix: remove websocket handler --- cmd/capture/main.go | 17 ++++---- go.mod | 1 - go.sum | 2 - internal/handler/websocket.go | 79 ----------------------------------- 4 files changed, 7 insertions(+), 92 deletions(-) delete mode 100644 internal/handler/websocket.go diff --git a/cmd/capture/main.go b/cmd/capture/main.go index 46a7477..7a1c0f9 100644 --- a/cmd/capture/main.go +++ b/cmd/capture/main.go @@ -23,7 +23,7 @@ var appConfig = config.NewConfig( func main() { r := gin.Default() apiV1 := r.Group("/api/v1") - apiV1.Use(middleware.AuthRequired(appConfig.ApiSecret)) + apiV1.Use(middleware.AuthRequired(appConfig.APISecret)) // Health Check apiV1.GET("/health", handler.Health) @@ -35,12 +35,10 @@ func main() { apiV1.GET("/metrics/disk", handler.MetricsDisk) apiV1.GET("/metrics/host", handler.MetricsHost) - // WebSocket Connection - apiV1.GET("/ws/metrics", handler.WebSocket) - server := &http.Server{ - Addr: ":" + appConfig.Port, - Handler: r.Handler(), + Addr: ":" + appConfig.Port, + Handler: r.Handler(), + ReadHeaderTimeout: 5 * time.Second, } // Graceful shutdown @@ -57,10 +55,9 @@ func main() { if err := server.Shutdown(ctx); err != nil { log.Fatal("server shutdown:", err) } - select { - case <-ctx.Done(): - log.Println("timeout of 5 seconds.") - } + <-ctx.Done() + log.Println("timeout of 5 seconds.") + log.Println("server exiting") } diff --git a/go.mod b/go.mod index ec0393b..e46c395 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ go 1.23.1 require ( github.com/gin-gonic/gin v1.10.0 - github.com/gorilla/websocket v1.5.3 github.com/shirou/gopsutil/v4 v4.24.9 github.com/stretchr/testify v1.9.0 ) diff --git a/go.sum b/go.sum index 66aae07..4425366 100644 --- a/go.sum +++ b/go.sum @@ -34,8 +34,6 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= -github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= diff --git a/internal/handler/websocket.go b/internal/handler/websocket.go deleted file mode 100644 index 09679ff..0000000 --- a/internal/handler/websocket.go +++ /dev/null @@ -1,79 +0,0 @@ -package handler - -import ( - "encoding/json" - "log" - "net/http" - "time" - - "github.com/bluewave-labs/capture/internal/metric" - "github.com/gin-gonic/gin" - "github.com/gorilla/websocket" -) - -var interval = 5 * time.Second - -var upgrader = websocket.Upgrader{ - ReadBufferSize: 1024, - WriteBufferSize: 1024, - CheckOrigin: func(r *http.Request) bool { - // TODO: Make allowedOrigins Configurable. ENV var?, config? - allowedOrigins := []string{"*"} - - if allowedOrigins[0] == "*" { - return true // Accept connections from everywhere - } - - return false // Decline connections - }, -} - -func WebSocket(c *gin.Context) { - conn, err := upgrader.Upgrade(c.Writer, c.Request, nil) - if err != nil { - log.Printf("[FAIL] | Failed to set websocket upgrade: %v", err) - return - } - - defer conn.Close() - done := make(chan struct{}) // Channel to signal when the client disconnects - - // Goroutine to handle incoming messages and detect disconnection - go func() { - for { - _, _, err := conn.ReadMessage() // ReadMessage blocks until there's a message or an error - if err != nil { - log.Println("Client disconnected:", err) - close(done) // Signal that the client has disconnected - return - } - } - }() - - // Streaming messages to the client - for { - metrics, metricsErr := metric.GetAllSystemMetrics() - if metricsErr != nil { - log.Printf("[FAIL] | Failed to get system metrics: %v", metricsErr) - c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get system metrics"}) - return - } - data, dataErr := json.Marshal(metrics) - if dataErr != nil { - log.Printf("[FAIL] | Failed to marshal system metrics: %v", dataErr) - c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to marshal system metrics"}) - return - } - select { - case <-done: // If client disconnects, exit the loop - log.Println("Stopped streaming due to client disconnect") - return - default: - if err := conn.WriteMessage(websocket.TextMessage, data); err != nil { - log.Println("Write error:", err) - return - } - time.Sleep(interval) // Simulate real-time data generation - } - } -} From bce26b2f194e43b43e955ebf5dd966db5b808530 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mert=20=C5=9Ei=C5=9Fmano=C4=9Flu?= Date: Thu, 19 Dec 2024 17:34:53 +0300 Subject: [PATCH 4/5] fix(lint): Solve all linter warnings and errors --- internal/config/config.go | 6 +++--- internal/handler/metrics.go | 5 ++--- internal/metric/cpu.go | 8 ++++---- internal/metric/disk.go | 2 +- internal/metric/metric.go | 12 ++++++------ internal/metric/metric_math.go | 4 ++-- internal/sysfs/cpu.go | 8 ++++---- internal/sysfs/exec.go | 2 +- 8 files changed, 23 insertions(+), 24 deletions(-) diff --git a/internal/config/config.go b/internal/config/config.go index 5531120..3ba0e9d 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -4,7 +4,7 @@ import "log" type Config struct { Port string - ApiSecret string + APISecret string } var defaultPort = "59232" @@ -22,13 +22,13 @@ func NewConfig(port string, apiSecret string) *Config { return &Config{ Port: port, - ApiSecret: apiSecret, + APISecret: apiSecret, } } func Default() *Config { return &Config{ Port: defaultPort, - ApiSecret: "", + APISecret: "", } } diff --git a/internal/handler/metrics.go b/internal/handler/metrics.go index 99b9165..198dcab 100644 --- a/internal/handler/metrics.go +++ b/internal/handler/metrics.go @@ -10,11 +10,10 @@ func handleMetricResponse(c *gin.Context, metrics metric.Metric, errs []metric.C if len(errs) > 0 { statusCode = 207 } - c.JSON(statusCode, metric.ApiResponse{ + c.JSON(statusCode, metric.APIResponse{ Data: metrics, Errors: errs, }) - return } func Metrics(c *gin.Context) { @@ -23,7 +22,7 @@ func Metrics(c *gin.Context) { } func MetricsCPU(c *gin.Context) { - cpuMetrics, metricsErrs := metric.CollectCpuMetrics() + cpuMetrics, metricsErrs := metric.CollectCPUMetrics() handleMetricResponse(c, cpuMetrics, metricsErrs) } diff --git a/internal/metric/cpu.go b/internal/metric/cpu.go index 02bcb36..3aaabf0 100644 --- a/internal/metric/cpu.go +++ b/internal/metric/cpu.go @@ -7,7 +7,7 @@ import ( "github.com/shirou/gopsutil/v4/cpu" ) -func CollectCpuMetrics() (*CpuData, []CustomErr) { +func CollectCPUMetrics() (*CPUData, []CustomErr) { // Collect CPU Core Counts cpuPhysicalCoreCount, cpuPhysicalErr := cpu.Counts(false) cpuLogicalCoreCount, cpuLogicalErr := cpu.Counts(true) @@ -60,7 +60,7 @@ func CollectCpuMetrics() (*CpuData, []CustomErr) { } // Collect CPU Temperature from sysfs - cpuTemp, cpuTempErr := sysfs.CpuTemperature() + cpuTemp, cpuTempErr := sysfs.CPUTemperature() if cpuTempErr != nil { cpuErrors = append(cpuErrors, CustomErr{ @@ -70,7 +70,7 @@ func CollectCpuMetrics() (*CpuData, []CustomErr) { cpuTemp = nil } - cpuCurrentFrequency, cpuCurFreqErr := sysfs.CpuCurrentFrequency() + cpuCurrentFrequency, cpuCurFreqErr := sysfs.CPUCurrentFrequency() if cpuCurFreqErr != nil { cpuErrors = append(cpuErrors, CustomErr{ Metric: []string{"cpu.current_frequency"}, @@ -79,7 +79,7 @@ func CollectCpuMetrics() (*CpuData, []CustomErr) { cpuCurrentFrequency = 0 } - return &CpuData{ + return &CPUData{ PhysicalCore: cpuPhysicalCoreCount, LogicalCore: cpuLogicalCoreCount, Frequency: cpuFrequency, diff --git a/internal/metric/disk.go b/internal/metric/disk.go index e658970..7886048 100644 --- a/internal/metric/disk.go +++ b/internal/metric/disk.go @@ -20,7 +20,7 @@ func CollectDiskMetrics() (MetricsSlice, []CustomErr) { } var diskErrors []CustomErr var metricsSlice MetricsSlice - var checkedSlice []string // To keep track of checked partitions + var checkedSlice = make([]string, 0, 10) // To keep track of checked partitions // Set all flag to "false" to get only necessary partitions // Avoiding unnecessary partitions like /run/user/1000, /run/credentials diff --git a/internal/metric/metric.go b/internal/metric/metric.go index 1e9c062..98663cc 100644 --- a/internal/metric/metric.go +++ b/internal/metric/metric.go @@ -8,13 +8,13 @@ type Metric interface { isMetric() } -type ApiResponse struct { +type APIResponse struct { Data Metric `json:"data"` Errors []CustomErr `json:"errors"` } type AllMetrics struct { - Cpu CpuData `json:"cpu"` + CPU CPUData `json:"cpu"` Memory MemoryData `json:"memory"` Disk MetricsSlice `json:"disk"` Host HostData `json:"host"` @@ -27,7 +27,7 @@ type CustomErr struct { Error string `json:"err"` } -type CpuData struct { +type CPUData struct { PhysicalCore int `json:"physical_core"` // Physical cores LogicalCore int `json:"logical_core"` // Logical cores aka Threads Frequency float64 `json:"frequency"` // Frequency in mHz @@ -37,7 +37,7 @@ type CpuData struct { UsagePercent float64 `json:"usage_percent"` // Usage percentage //* Total - Idle / Total } -func (c CpuData) isMetric() {} +func (c CPUData) isMetric() {} type MemoryData struct { TotalBytes uint64 `json:"total_bytes"` // Total space in bytes @@ -68,7 +68,7 @@ type HostData struct { func (h HostData) isMetric() {} func GetAllSystemMetrics() (AllMetrics, []CustomErr) { - cpu, cpuErr := CollectCpuMetrics() + cpu, cpuErr := CollectCPUMetrics() memory, memErr := CollectMemoryMetrics() disk, diskErr := CollectDiskMetrics() host, hostErr := GetHostInformation() @@ -92,7 +92,7 @@ func GetAllSystemMetrics() (AllMetrics, []CustomErr) { } return AllMetrics{ - Cpu: *cpu, + CPU: *cpu, Memory: *memory, Disk: disk, Host: *host, diff --git a/internal/metric/metric_math.go b/internal/metric/metric_math.go index 9324248..a0d42bb 100644 --- a/internal/metric/metric_math.go +++ b/internal/metric/metric_math.go @@ -20,8 +20,8 @@ func RoundFloat(val float64, precision uint) float64 { return prc } -func RandomIntPtr(max int64) *int { - n, err := rand.Int(rand.Reader, big.NewInt(max)) +func RandomIntPtr(maximum int64) *int { + n, err := rand.Int(rand.Reader, big.NewInt(maximum)) if err != nil { panic(err) // handle error appropriately in production } diff --git a/internal/sysfs/cpu.go b/internal/sysfs/cpu.go index 4daac36..067782e 100644 --- a/internal/sysfs/cpu.go +++ b/internal/sysfs/cpu.go @@ -22,7 +22,7 @@ func readTempFile(path string) (float32, error) { return float32(temp) / 1000, nil } -func readCpuFreqFile(path string) (int, error) { +func readCPUFreqFile(path string) (int, error) { data, err := os.ReadFile(path) if err != nil { return 0, err @@ -36,7 +36,7 @@ func readCpuFreqFile(path string) (int, error) { return freq, nil } -func CpuTemperature() ([]float32, error) { +func CPUTemperature() ([]float32, error) { // Look in all these folders for core temp corePaths := []string{ "/sys/devices/platform/coretemp.0/hwmon/hwmon*/temp*_input", @@ -74,8 +74,8 @@ func CpuTemperature() ([]float32, error) { return temps, nil } -func CpuCurrentFrequency() (int, error) { - frequency, cpuFrequencyError := readCpuFreqFile("/sys/devices/system/cpu/cpufreq/policy0/scaling_cur_freq") +func CPUCurrentFrequency() (int, error) { + frequency, cpuFrequencyError := readCPUFreqFile("/sys/devices/system/cpu/cpufreq/policy0/scaling_cur_freq") if cpuFrequencyError != nil { return 0, cpuFrequencyError diff --git a/internal/sysfs/exec.go b/internal/sysfs/exec.go index 9c63701..15b6421 100644 --- a/internal/sysfs/exec.go +++ b/internal/sysfs/exec.go @@ -8,7 +8,7 @@ import ( func ShellExec(c string) (string, error) { if strings.Contains(c, "&&") || strings.Contains(c, "||") || strings.Contains(c, ";") { - return "", errors.New("It's forbidden to execute consecutive commands") + return "", errors.New("it's forbidden to execute consecutive commands") } cmd := exec.Command("bash", "-c", c) From ba2ab5f6a0184967d88b7fcf5176ff4e561de1fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mert=20=C5=9Ei=C5=9Fmano=C4=9Flu?= Date: Thu, 19 Dec 2024 20:45:11 +0300 Subject: [PATCH 5/5] chore: Remove unimplemented 'ReadSpeedBytes' and 'WriteSpeedBytes' fields from the DiskData struct --- internal/metric/disk.go | 20 ++++++++------------ internal/metric/metric.go | 10 ++++------ 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/internal/metric/disk.go b/internal/metric/disk.go index 7886048..b48d100 100644 --- a/internal/metric/disk.go +++ b/internal/metric/disk.go @@ -10,12 +10,10 @@ import ( func CollectDiskMetrics() (MetricsSlice, []CustomErr) { defaultDiskData := []*DiskData{ { - Device: "unknown", - ReadSpeedBytes: nil, - WriteSpeedBytes: nil, - TotalBytes: nil, - FreeBytes: nil, - UsagePercent: nil, + Device: "unknown", + TotalBytes: nil, + FreeBytes: nil, + UsagePercent: nil, }, } var diskErrors []CustomErr @@ -52,12 +50,10 @@ func CollectDiskMetrics() (MetricsSlice, []CustomErr) { checkedSlice = append(checkedSlice, p.Device) metricsSlice = append(metricsSlice, &DiskData{ - Device: p.Device, - ReadSpeedBytes: nil, // TODO: Implement - WriteSpeedBytes: nil, // TODO: Implement - TotalBytes: &diskUsage.Total, - FreeBytes: &diskUsage.Free, - UsagePercent: RoundFloatPtr(diskUsage.UsedPercent/100, 4), + Device: p.Device, + TotalBytes: &diskUsage.Total, + FreeBytes: &diskUsage.Free, + UsagePercent: RoundFloatPtr(diskUsage.UsedPercent/100, 4), }) } diff --git a/internal/metric/metric.go b/internal/metric/metric.go index 98663cc..f3d79d1 100644 --- a/internal/metric/metric.go +++ b/internal/metric/metric.go @@ -49,12 +49,10 @@ type MemoryData struct { func (m MemoryData) isMetric() {} type DiskData struct { - Device string `json:"device"` // Device - ReadSpeedBytes *uint64 `json:"read_speed_bytes"` // TODO: Implement - WriteSpeedBytes *uint64 `json:"write_speed_bytes"` // TODO: Implement - TotalBytes *uint64 `json:"total_bytes"` // Total space of device in bytes - FreeBytes *uint64 `json:"free_bytes"` // Free space of device in bytes - UsagePercent *float64 `json:"usage_percent"` // Usage Percent of device + Device string `json:"device"` // Device + TotalBytes *uint64 `json:"total_bytes"` // Total space of device in bytes + FreeBytes *uint64 `json:"free_bytes"` // Free space of device in bytes + UsagePercent *float64 `json:"usage_percent"` // Usage Percent of device } func (d DiskData) isMetric() {}