mirror of
https://github.com/safing/portmaster
synced 2025-04-20 02:49:10 +00:00
* Move portbase into monorepo * Add new simple module mgr * [WIP] Switch to new simple module mgr * Add StateMgr and more worker variants * [WIP] Switch more modules * [WIP] Switch more modules * [WIP] swtich more modules * [WIP] switch all SPN modules * [WIP] switch all service modules * [WIP] Convert all workers to the new module system * [WIP] add new task system to module manager * [WIP] Add second take for scheduling workers * [WIP] Add FIXME for bugs in new scheduler * [WIP] Add minor improvements to scheduler * [WIP] Add new worker scheduler * [WIP] Fix more bug related to new module system * [WIP] Fix start handing of the new module system * [WIP] Improve startup process * [WIP] Fix minor issues * [WIP] Fix missing subsystem in settings * [WIP] Initialize managers in constructor * [WIP] Move module event initialization to constrictors * [WIP] Fix setting for enabling and disabling the SPN module * [WIP] Move API registeration into module construction * [WIP] Update states mgr for all modules * [WIP] Add CmdLine operation support * Add state helper methods to module group and instance * Add notification and module status handling to status package * Fix starting issues * Remove pilot widget and update security lock to new status data * Remove debug logs * Improve http server shutdown * Add workaround for cleanly shutting down firewall+netquery * Improve logging * Add syncing states with notifications for new module system * Improve starting, stopping, shutdown; resolve FIXMEs/TODOs * [WIP] Fix most unit tests * Review new module system and fix minor issues * Push shutdown and restart events again via API * Set sleep mode via interface * Update example/template module * [WIP] Fix spn/cabin unit test * Remove deprecated UI elements * Make log output more similar for the logging transition phase * Switch spn hub and observer cmds to new module system * Fix log sources * Make worker mgr less error prone * Fix tests and minor issues * Fix observation hub * Improve shutdown and restart handling * Split up big connection.go source file * Move varint and dsd packages to structures repo * Improve expansion test * Fix linter warnings * Fix interception module on windows * Fix linter errors --------- Co-authored-by: Vladimir Stoilov <vladimir@safing.io>
263 lines
6.6 KiB
Go
263 lines
6.6 KiB
Go
package metrics
|
|
|
|
import (
|
|
"runtime"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/shirou/gopsutil/disk"
|
|
"github.com/shirou/gopsutil/load"
|
|
"github.com/shirou/gopsutil/mem"
|
|
|
|
"github.com/safing/portmaster/base/api"
|
|
"github.com/safing/portmaster/base/dataroot"
|
|
"github.com/safing/portmaster/base/log"
|
|
)
|
|
|
|
const hostStatTTL = 1 * time.Second
|
|
|
|
func registerHostMetrics() (err error) {
|
|
// Register load average metrics.
|
|
_, err = NewGauge("host/load/avg/1", nil, getFloat64HostStat(LoadAvg1), &Options{Name: "Host Load Avg 1min", Permission: api.PermitUser})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = NewGauge("host/load/avg/5", nil, getFloat64HostStat(LoadAvg5), &Options{Name: "Host Load Avg 5min", Permission: api.PermitUser})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = NewGauge("host/load/avg/15", nil, getFloat64HostStat(LoadAvg15), &Options{Name: "Host Load Avg 15min", Permission: api.PermitUser})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Register memory usage metrics.
|
|
_, err = NewGauge("host/mem/total", nil, getUint64HostStat(MemTotal), &Options{Name: "Host Memory Total", Permission: api.PermitUser})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = NewGauge("host/mem/used", nil, getUint64HostStat(MemUsed), &Options{Name: "Host Memory Used", Permission: api.PermitUser})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = NewGauge("host/mem/available", nil, getUint64HostStat(MemAvailable), &Options{Name: "Host Memory Available", Permission: api.PermitUser})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = NewGauge("host/mem/used/percent", nil, getFloat64HostStat(MemUsedPercent), &Options{Name: "Host Memory Used in Percent", Permission: api.PermitUser})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Register disk usage metrics.
|
|
_, err = NewGauge("host/disk/total", nil, getUint64HostStat(DiskTotal), &Options{Name: "Host Disk Total", Permission: api.PermitUser})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = NewGauge("host/disk/used", nil, getUint64HostStat(DiskUsed), &Options{Name: "Host Disk Used", Permission: api.PermitUser})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = NewGauge("host/disk/free", nil, getUint64HostStat(DiskFree), &Options{Name: "Host Disk Free", Permission: api.PermitUser})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = NewGauge("host/disk/used/percent", nil, getFloat64HostStat(DiskUsedPercent), &Options{Name: "Host Disk Used in Percent", Permission: api.PermitUser})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func getUint64HostStat(getStat func() (uint64, bool)) func() float64 {
|
|
return func() float64 {
|
|
val, _ := getStat()
|
|
return float64(val)
|
|
}
|
|
}
|
|
|
|
func getFloat64HostStat(getStat func() (float64, bool)) func() float64 {
|
|
return func() float64 {
|
|
val, _ := getStat()
|
|
return val
|
|
}
|
|
}
|
|
|
|
var (
|
|
loadAvg *load.AvgStat
|
|
loadAvgExpires time.Time
|
|
loadAvgLock sync.Mutex
|
|
)
|
|
|
|
func getLoadAvg() *load.AvgStat {
|
|
loadAvgLock.Lock()
|
|
defer loadAvgLock.Unlock()
|
|
|
|
// Return cache if still valid.
|
|
if time.Now().Before(loadAvgExpires) {
|
|
return loadAvg
|
|
}
|
|
|
|
// Refresh.
|
|
var err error
|
|
loadAvg, err = load.Avg()
|
|
if err != nil {
|
|
log.Warningf("metrics: failed to get load avg: %s", err)
|
|
loadAvg = nil
|
|
}
|
|
loadAvgExpires = time.Now().Add(hostStatTTL)
|
|
|
|
return loadAvg
|
|
}
|
|
|
|
// LoadAvg1 returns the 1-minute average system load.
|
|
func LoadAvg1() (loadAvg float64, ok bool) {
|
|
if stat := getLoadAvg(); stat != nil {
|
|
return stat.Load1 / float64(runtime.NumCPU()), true
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
// LoadAvg5 returns the 5-minute average system load.
|
|
func LoadAvg5() (loadAvg float64, ok bool) {
|
|
if stat := getLoadAvg(); stat != nil {
|
|
return stat.Load5 / float64(runtime.NumCPU()), true
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
// LoadAvg15 returns the 15-minute average system load.
|
|
func LoadAvg15() (loadAvg float64, ok bool) {
|
|
if stat := getLoadAvg(); stat != nil {
|
|
return stat.Load15 / float64(runtime.NumCPU()), true
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
var (
|
|
memStat *mem.VirtualMemoryStat
|
|
memStatExpires time.Time
|
|
memStatLock sync.Mutex
|
|
)
|
|
|
|
func getMemStat() *mem.VirtualMemoryStat {
|
|
memStatLock.Lock()
|
|
defer memStatLock.Unlock()
|
|
|
|
// Return cache if still valid.
|
|
if time.Now().Before(memStatExpires) {
|
|
return memStat
|
|
}
|
|
|
|
// Refresh.
|
|
var err error
|
|
memStat, err = mem.VirtualMemory()
|
|
if err != nil {
|
|
log.Warningf("metrics: failed to get load avg: %s", err)
|
|
memStat = nil
|
|
}
|
|
memStatExpires = time.Now().Add(hostStatTTL)
|
|
|
|
return memStat
|
|
}
|
|
|
|
// MemTotal returns the total system memory.
|
|
func MemTotal() (total uint64, ok bool) {
|
|
if stat := getMemStat(); stat != nil {
|
|
return stat.Total, true
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
// MemUsed returns the used system memory.
|
|
func MemUsed() (used uint64, ok bool) {
|
|
if stat := getMemStat(); stat != nil {
|
|
return stat.Used, true
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
// MemAvailable returns the available system memory.
|
|
func MemAvailable() (available uint64, ok bool) {
|
|
if stat := getMemStat(); stat != nil {
|
|
return stat.Available, true
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
// MemUsedPercent returns the percent of used system memory.
|
|
func MemUsedPercent() (usedPercent float64, ok bool) {
|
|
if stat := getMemStat(); stat != nil {
|
|
return stat.UsedPercent, true
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
var (
|
|
diskStat *disk.UsageStat
|
|
diskStatExpires time.Time
|
|
diskStatLock sync.Mutex
|
|
)
|
|
|
|
func getDiskStat() *disk.UsageStat {
|
|
diskStatLock.Lock()
|
|
defer diskStatLock.Unlock()
|
|
|
|
// Return cache if still valid.
|
|
if time.Now().Before(diskStatExpires) {
|
|
return diskStat
|
|
}
|
|
|
|
// Check if we have a data root.
|
|
dataRoot := dataroot.Root()
|
|
if dataRoot == nil {
|
|
log.Warning("metrics: cannot get disk stats without data root")
|
|
diskStat = nil
|
|
diskStatExpires = time.Now().Add(hostStatTTL)
|
|
return diskStat
|
|
}
|
|
|
|
// Refresh.
|
|
var err error
|
|
diskStat, err = disk.Usage(dataRoot.Path)
|
|
if err != nil {
|
|
log.Warningf("metrics: failed to get load avg: %s", err)
|
|
diskStat = nil
|
|
}
|
|
diskStatExpires = time.Now().Add(hostStatTTL)
|
|
|
|
return diskStat
|
|
}
|
|
|
|
// DiskTotal returns the total disk space (from the program's data root).
|
|
func DiskTotal() (total uint64, ok bool) {
|
|
if stat := getDiskStat(); stat != nil {
|
|
return stat.Total, true
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
// DiskUsed returns the used disk space (from the program's data root).
|
|
func DiskUsed() (used uint64, ok bool) {
|
|
if stat := getDiskStat(); stat != nil {
|
|
return stat.Used, true
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
// DiskFree returns the available disk space (from the program's data root).
|
|
func DiskFree() (free uint64, ok bool) {
|
|
if stat := getDiskStat(); stat != nil {
|
|
return stat.Free, true
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
// DiskUsedPercent returns the percent of used disk space (from the program's data root).
|
|
func DiskUsedPercent() (usedPercent float64, ok bool) {
|
|
if stat := getDiskStat(); stat != nil {
|
|
return stat.UsedPercent, true
|
|
}
|
|
return 0, false
|
|
}
|