Skip to content
Merged
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
44 changes: 27 additions & 17 deletions common/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
)

// GetCPULoad calculates the CPU load for the service, system, and total.
func GetCPULoad() (serviceCPU, systemCPU, totalCPU string) {
func GetCPULoad() (serviceCPU, systemCPU, totalCPU string, serviceCPUF, systemCPUF, totalCPUF float64) {

proc := GetProcessObject() // Getting process details
serviceCPUF, err := proc.CPUPercent() // Measure CPU percent for the current process
Expand All @@ -26,62 +26,72 @@ func GetCPULoad() (serviceCPU, systemCPU, totalCPU string) {
cpuPercents, err := cpu.Percent(time.Second, false) // Get total system CPU percentage
if err != nil {
log.Printf("[MoniGo] Error fetching CPU load for the system: %v\n", err)
return serviceCPU, "0%", "0%"
return serviceCPU, "0%", "0%", serviceCPUF, 0, 0
}
if len(cpuPercents) > 0 {
systemCPU = ParseFloat64ToString(cpuPercents[0]-serviceCPUF) + "%" // System CPU usage percentage
systemCPUF = cpuPercents[0] - serviceCPUF
if systemCPUF < 0 {
systemCPUF = 0
}
systemCPU = ParseFloat64ToString(systemCPUF) + "%" // System CPU usage percentage
totalCPUF = cpuPercents[0]
}

totalCPU = ParseFloat64ToString(serviceCPUF+cpuPercents[0]) + "%" // Total CPU usage percentage
return serviceCPU, systemCPU, totalCPU
totalCPU = ParseFloat64ToString(totalCPUF) + "%" // Total CPU usage percentage
return serviceCPU, systemCPU, totalCPU, serviceCPUF, systemCPUF, totalCPUF
}

// GetMemoryLoad calculates the memory load for the service, system, and total.
func GetMemoryLoad() (serviceMem, systemMem, totalMem string) {
func GetMemoryLoad() (serviceMem, systemMem, totalMem string, serviceMemF, systemMemF, totalMemF float64) {
// Get system memory statistics
vmStat, err := mem.VirtualMemory()
if err != nil {
log.Printf("[MoniGo] Error fetching memory load for the system: %v\n", err)
return "0%", "0%", "0%"
return "0%", "0%", "0%", 0, 0, 0
}
systemMem = ParseFloat64ToString(vmStat.UsedPercent) + "%" // Calculate system memory as a percentage of total memory
totalMem = ParseFloat64ToString(ParseUint64ToFloat64(vmStat.Total)) // Total memory in bytes Total amount of RAM on this system
systemMemF = vmStat.UsedPercent
systemMem = ParseFloat64ToString(systemMemF) + "%" // Calculate system memory as a percentage of total memory
totalMemF = float64(vmStat.Total)
totalMem = ParseFloat64ToString(totalMemF) // Total memory in bytes Total amount of RAM on this system

proc := GetProcessObject()
memInfo, err := proc.MemoryInfo()
if err != nil {
log.Printf("[MoniGo] Error fetching memory load for the service: %v\n", err)
return "0%", systemMem, totalMem
return "0%", systemMem, totalMem, 0, systemMemF, totalMemF
}

serviceMem = ParseFloat64ToString(float64(memInfo.RSS)/float64(vmStat.Total)*100) + "%" // Calculate service memory as a percentage of total memory
serviceMemF = (float64(memInfo.RSS) / float64(vmStat.Total)) * 100
serviceMem = ParseFloat64ToString(serviceMemF) + "%" // Calculate service memory as a percentage of total memory

return serviceMem, systemMem, totalMem
return serviceMem, systemMem, totalMem, serviceMemF, systemMemF, totalMemF
}

// GetDiskLoad calculates the disk load for the service, system, and total.
func GetDiskLoad() (serviceDisk, systemDisk, totalDisk string) {
func GetDiskLoad() (serviceDisk, systemDisk, totalDisk string, systemDiskF, totalDiskF float64) {
// For disk, "Service" usage handles read/write bytes or handle count, but normally "Load" implies storage usage.
// However, gathering "Disk Usage by Process" is complex and often requires root or specific tracking.
// For now, we will track System Disk Usage (Root Partition).

diskUsage, err := disk.Usage("/")
if err != nil {
log.Printf("[MoniGo] Error fetching disk usage: %v\n", err) // Changed from Panic to Printf as agreed in plan
return "0%", "0%", "0%"
return "0%", "0%", "0%", 0, 0
}

// ServiceDiskLoad is complex to calculate per process without cgroups/root.
// We will mistakenly leave it as 0% or maybe revisit if we can get FD count as proxy?
// For now, let's just return System Disk Usage.

systemDisk = ParseFloat64ToString(diskUsage.UsedPercent) + "%"
totalDisk = ParseFloat64ToString(float64(diskUsage.Total)) // Total disk size in bytes
systemDiskF = diskUsage.UsedPercent
systemDisk = ParseFloat64ToString(systemDiskF) + "%"
totalDiskF = float64(diskUsage.Total)
totalDisk = ParseFloat64ToString(totalDiskF) // Total disk size in bytes

// ServiceDiskLoad: Not easily available.
serviceDisk = "0%"

return serviceDisk, systemDisk, totalDisk
return serviceDisk, systemDisk, totalDisk, systemDiskF, totalDiskF
}

// GetProcessDetails returns the process ID and process object.
Expand Down
74 changes: 44 additions & 30 deletions core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ func GetServiceStats() models.ServiceStats {
stats.HeapAllocBySystem = common.BytesToUnit(memStats.HeapSys)
stats.TotalAllocByService = common.BytesToUnit(memStats.TotalAlloc)
stats.TotalMemoryByOS = common.BytesToUnit(memStats.Sys)
stats.HeapAllocByServiceRaw = memStats.HeapAlloc
stats.HeapAllocBySystemRaw = memStats.HeapSys
stats.TotalAllocByServiceRaw = memStats.TotalAlloc
stats.TotalMemoryByOSRaw = memStats.Sys
}()

// Goroutine to fetch network I/O statistics
Expand Down Expand Up @@ -108,35 +112,39 @@ func GetCoreStatistics() models.CoreStatistics {
func GetLoadStatistics() models.LoadStatistics {

// Fetch CPU load statistics
serviceCPULoad, systemCPULoad, totalCPULoad := common.GetCPULoad()
serviceCPULoad, systemCPULoad, totalCPULoad, serviceCPUF, systemCPUF, _ := common.GetCPULoad()

// Fetch memory load statistics
serviceMemLoad, systemMemLoad, totalMemAvailable := common.GetMemoryLoad()
serviceMemLoad, systemMemLoad, totalMemAvailable, serviceMemF, systemMemF, _ := common.GetMemoryLoad()

// Fetch disk load statistics
serviceDisk, systemDisk, totalDisk := common.GetDiskLoad()
serviceDisk, systemDisk, totalDisk, systemDiskF, totalDiskF := common.GetDiskLoad()

overallLoadF, overallLoadStr := CalculateOverallLoad(serviceCPUF, serviceMemF)

return models.LoadStatistics{
ServiceCPULoad: serviceCPULoad,
SystemCPULoad: systemCPULoad,
TotalCPULoad: totalCPULoad,
ServiceMemLoad: serviceMemLoad,
SystemMemLoad: systemMemLoad,
TotalMemLoad: common.ConvertToReadableUnit(totalMemAvailable),
OverallLoadOfService: CalculateOverallLoad(serviceCPULoad, serviceMemLoad),
ServiceDiskLoad: serviceDisk,
SystemDiskLoad: systemDisk,
TotalDiskLoad: totalDisk,
ServiceCPULoad: serviceCPULoad,
SystemCPULoad: systemCPULoad,
TotalCPULoad: totalCPULoad,
ServiceMemLoad: serviceMemLoad,
SystemMemLoad: systemMemLoad,
TotalMemLoad: totalMemAvailable,
OverallLoadOfService: overallLoadStr,
ServiceDiskLoad: serviceDisk,
SystemDiskLoad: systemDisk,
TotalDiskLoad: totalDisk,
ServiceCPULoadRaw: serviceCPUF,
SystemCPULoadRaw: systemCPUF,
ServiceMemLoadRaw: serviceMemF,
SystemMemLoadRaw: systemMemF,
OverallLoadOfServiceRaw: overallLoadF,
SystemDiskLoadRaw: systemDiskF,
TotalDiskLoadRaw: totalDiskF,
}
}

// Function to calculate overall load
func CalculateOverallLoad(serviceCPU, serviceMem string) string {

// string to float64 conversion
serviceCPUF := common.ParseStringToFloat64(serviceCPU)
serviceMemF := common.ParseStringToFloat64(serviceMem)

func CalculateOverallLoad(serviceCPUF, serviceMemF float64) (float64, string) {
cpuWeight := 0.5 // Weight for CPU load
memWeight := 0.5 // Weight for memory usage

Expand All @@ -146,7 +154,7 @@ func CalculateOverallLoad(serviceCPU, serviceMem string) string {
overallLoad = 100
}

return common.ParseFloat64ToString(overallLoad) + "%"
return overallLoad, common.ParseFloat64ToString(overallLoad) + "%"
}

// GetCPUStatistics retrieves the CPU statistics.
Expand Down Expand Up @@ -205,16 +213,22 @@ func GetMemoryStatistics() models.MemoryStatistics {

m := ReadMemStats() // Get the memory statistics for the service
return models.MemoryStatistics{
TotalSystemMemory: common.BytesToUnit(memInfo.Total),
MemoryUsedBySystem: common.BytesToUnit(memInfo.Used),
AvailableMemory: common.BytesToUnit(memInfo.Available),
TotalSwapMemory: common.BytesToUnit(swapInfo.Total),
FreeSwapMemory: common.BytesToUnit(swapInfo.Free),
MemoryUsedByService: common.BytesToUnit(m.Alloc), // Example metric
StackMemoryUsage: common.BytesToUnit(m.StackInuse),
GCPauseDuration: fmt.Sprintf("%.2f ms", float64(m.PauseTotalNs)/float64(time.Millisecond)), // Convert nanoseconds to milliseconds
MemStatsRecords: ConstructMemStats(m),
RawMemStatsRecords: ConstructRawMemStats(m),
TotalSystemMemory: common.BytesToUnit(memInfo.Total),
MemoryUsedBySystem: common.BytesToUnit(memInfo.Used),
AvailableMemory: common.BytesToUnit(memInfo.Available),
TotalSwapMemory: common.BytesToUnit(swapInfo.Total),
FreeSwapMemory: common.BytesToUnit(swapInfo.Free),
MemoryUsedByService: common.BytesToUnit(m.Alloc), // Example metric
StackMemoryUsage: common.BytesToUnit(m.StackInuse),
GCPauseDuration: fmt.Sprintf("%.2f ms", float64(m.PauseTotalNs)/float64(time.Millisecond)), // Convert nanoseconds to milliseconds
MemStatsRecords: ConstructMemStats(m),
RawMemStatsRecords: ConstructRawMemStats(m),
TotalSystemMemoryRaw: float64(memInfo.Total),
MemoryUsedBySystemRaw: float64(memInfo.Used),
MemoryUsedByServiceRaw: float64(m.Alloc),
AvailableMemoryRaw: float64(memInfo.Available),
GCPauseDurationRaw: float64(m.PauseTotalNs) / float64(time.Millisecond),
StackMemoryUsageRaw: float64(m.StackInuse),
}
}

Expand Down
36 changes: 32 additions & 4 deletions core/function-metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,16 +258,44 @@ func executeFunctionWithProfiling(name string, fn func()) {

// ViewFunctionMetrics generates the function metrics
func ViewFunctionMetrics(name, reportType string, metrics *models.FunctionMetrics) models.FunctionTraceDetails {
// Check if 'go' command is available
_, err := exec.LookPath("go")
if err != nil {
log.Printf("[MoniGo] Warning: 'go' command not found in PATH. pprof reports will be unavailable.")
return models.FunctionTraceDetails{
FunctionName: name,
CoreProfile: models.Profiles{
CPU: "Error: 'go' command not found. pprof reports require the Go SDK.",
Mem: "Error: 'go' command not found. pprof reports require the Go SDK.",
},
FunctionCodeTrace: "Error: 'go' command not found.",
}
}

// Function to execute the pprof command and return the output or log an error
executePprof := func(profileFilePath, reportType string) string {
if profileFilePath == "" {
return "Error: Profile file path is empty"
}
cmd := exec.Command("go", "tool", "pprof", "-"+reportType, profileFilePath)
output, _ := cmd.Output()
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Sprintf("Error executing pprof: %v\nOutput: %s", err, string(output))
}
return string(output)
}

// Generating the function code stack trace for CPU profile
codeStackView := exec.Command("go", "tool", "pprof", "-list", name, metrics.CPUProfileFilePath)
codeStack, _ := codeStackView.Output()
var codeStack string
if metrics.CPUProfileFilePath != "" {
codeStackView := exec.Command("go", "tool", "pprof", "-list", name, metrics.CPUProfileFilePath)
output, err := codeStackView.CombinedOutput()
if err != nil {
codeStack = fmt.Sprintf("Error generating code trace: %v\nOutput: %s", err, string(output))
} else {
codeStack = string(output)
}
}

// Return the function trace details
return models.FunctionTraceDetails{
Expand All @@ -276,6 +304,6 @@ func ViewFunctionMetrics(name, reportType string, metrics *models.FunctionMetric
CPU: executePprof(metrics.CPUProfileFilePath, reportType),
Mem: executePprof(metrics.MemProfileFilePath, reportType),
},
FunctionCodeTrace: string(codeStack),
FunctionCodeTrace: codeStack,
}
}
9 changes: 9 additions & 0 deletions example/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ require github.com/iyashjayesh/monigo v0.0.2

require (
github.com/andybalholm/brotli v1.2.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/clipperhouse/stringish v0.1.1 // indirect
github.com/clipperhouse/uax29/v2 v2.3.0 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
Expand All @@ -15,14 +17,21 @@ require (
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.19 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nakabonne/tstorage v0.3.6 // indirect
github.com/prometheus/client_golang v1.23.2 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.66.1 // indirect
github.com/prometheus/procfs v0.16.1 // indirect
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
github.com/tklauser/go-sysconf v0.3.16 // indirect
github.com/tklauser/numcpus v0.11.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.68.0 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
golang.org/x/sys v0.39.0 // indirect
google.golang.org/protobuf v1.36.8 // indirect
)

replace github.com/iyashjayesh/monigo => ../
Loading