From 74224c8e8784326091259d173c1ad1cd77cefb43 Mon Sep 17 00:00:00 2001 From: yusing Date: Sun, 5 Oct 2025 12:05:58 +0800 Subject: [PATCH] refactor(metrics): optimize and simplify system info; add gopsutil as submodule --- .gitmodules | 3 + agent/go.mod | 7 +- agent/go.sum | 10 +- go.mod | 6 +- go.sum | 6 +- internal/dnsproviders/go.mod | 2 +- internal/dnsproviders/go.sum | 4 +- internal/gopsutil | 1 + internal/metrics/period/poller.go | 11 +- internal/metrics/systeminfo/json.go | 183 ------------------ internal/metrics/systeminfo/system_info.go | 26 +-- .../metrics/systeminfo/system_info_test.go | 95 +++------ internal/utils/atomic/value.go | 5 +- internal/utils/go.mod | 7 + internal/utils/go.sum | 24 +++ 15 files changed, 100 insertions(+), 290 deletions(-) create mode 100644 .gitmodules create mode 160000 internal/gopsutil delete mode 100644 internal/metrics/systeminfo/json.go diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..553052d2 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "internal/gopsutil"] + path = internal/gopsutil + url = git@github.com:godoxy-app/gopsutil.git diff --git a/agent/go.mod b/agent/go.mod index bfc5e831..e3c1816e 100644 --- a/agent/go.mod +++ b/agent/go.mod @@ -8,12 +8,10 @@ replace github.com/yusing/godoxy/socketproxy => ../socket-proxy replace github.com/yusing/godoxy/internal/utils => ../internal/utils -replace github.com/shirou/gopsutil/v4 => github.com/godoxy-app/gopsutil/v4 v4.0.0-20250926133131-7ef260e41a49 +replace github.com/shirou/gopsutil/v4 => ../internal/gopsutil exclude github.com/containerd/nerdctl/mod/tigron v0.0.0 -exclude github.com/yusing/goutils v0.4.2 - require ( github.com/bytedance/sonic v1.14.1 github.com/gin-gonic/gin v1.11.0 @@ -23,7 +21,7 @@ require ( github.com/stretchr/testify v1.11.1 github.com/yusing/godoxy v0.18.6 github.com/yusing/godoxy/socketproxy v0.0.0-00010101000000-000000000000 - github.com/yusing/goutils v0.4.1 + github.com/yusing/goutils v0.5.2 ) require ( @@ -33,7 +31,6 @@ require ( github.com/andybalholm/cascadia v1.3.3 // indirect github.com/bytedance/gopkg v0.1.3 // indirect github.com/bytedance/sonic/loader v0.3.0 // indirect - github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cloudwego/base64x v0.1.6 // indirect github.com/containerd/errdefs v1.0.0 // indirect github.com/containerd/errdefs/pkg v0.3.0 // indirect diff --git a/agent/go.sum b/agent/go.sum index 6b66de3c..bfa30091 100644 --- a/agent/go.sum +++ b/agent/go.sum @@ -86,8 +86,6 @@ github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PU github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godoxy-app/gopsutil/v4 v4.0.0-20250926133131-7ef260e41a49 h1:DqfJHUG+96pLB1FM7O3E7rq7Ilx+p7Zt2n2OyqToUH8= -github.com/godoxy-app/gopsutil/v4 v4.0.0-20250926133131-7ef260e41a49/go.mod h1:Ks7ccJvOucVh3BbyyvPApw93nefgMYXrieZvLJdex+w= github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -210,8 +208,8 @@ github.com/yusing/ds v0.2.0 h1:lPhDU5eA2uvquVrBrzLCrQXRJJgSXlUYA53TbuK2sQY= github.com/yusing/ds v0.2.0/go.mod h1:XhKV4l7cZwBbbl7lRzNC9zX27zvCM0frIwiuD40ULRk= github.com/yusing/gointernals v0.1.16 h1:GrhZZdxzA+jojLEqankctJrOuAYDb7kY1C93S1pVR34= github.com/yusing/gointernals v0.1.16/go.mod h1:B/0FVXt4WPmgzVy3ynzkqKi+BSGaJVmwCJBRXYapo34= -github.com/yusing/goutils v0.4.1 h1:80uFNxXfm4zXMYDku0rWMLyqEiXO0UOMFOaUC4b/6fI= -github.com/yusing/goutils v0.4.1/go.mod h1:xsoLWLtIiu7k+9Bn6azERDs5o3Djb3b2/DW1htHrOjg= +github.com/yusing/goutils v0.5.2 h1:h3Xbz3buTqH3SaL3LPdd/4wgNIQXcnHjNvCIlhOr5B0= +github.com/yusing/goutils v0.5.2/go.mod h1:3dgYe/A3+8wT88/iAHwXdL44q5bP+qVo2WAOiPBqOrg= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= @@ -331,8 +329,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T google.golang.org/genproto v0.0.0-20250908214217-97024824d090 h1:ywCL7vA2n3vVHyf+bx1ZV/knaTPRI8GIeKY0MEhEeOc= google.golang.org/genproto/googleapis/api v0.0.0-20250826171959-ef028d996bc1 h1:APHvLLYBhtZvsbnpkfknDZ7NyH4z5+ub/I0u8L3Oz6g= google.golang.org/genproto/googleapis/api v0.0.0-20250826171959-ef028d996bc1/go.mod h1:xUjFWUnWDpZ/C0Gu0qloASKFb6f8/QXiiXhSPFsD668= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250922171735-9219d122eba9 h1:V1jCN2HBa8sySkR5vLcCSqJSTMv093Rw9EJefhQGP7M= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250922171735-9219d122eba9/go.mod h1:HSkG/KdJWusxU1F6CNrwNDjBMgisKxGnc5dAZfT0mjQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 h1:CirRxTOwnRWVLKzDNrs0CXAaVozJoR4G9xvdRecrdpk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797/go.mod h1:HSkG/KdJWusxU1F6CNrwNDjBMgisKxGnc5dAZfT0mjQ= google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI= google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= diff --git a/go.mod b/go.mod index 0532bedd..ddea600c 100644 --- a/go.mod +++ b/go.mod @@ -10,9 +10,7 @@ replace github.com/yusing/godoxy/internal/utils => ./internal/utils replace github.com/coreos/go-oidc/v3 => github.com/godoxy-app/go-oidc/v3 v3.0.0-20250816044348-0630187cb14b -replace github.com/shirou/gopsutil/v4 => github.com/godoxy-app/gopsutil/v4 v4.0.0-20250926133131-7ef260e41a49 - -exclude github.com/yusing/goutils v0.4.2 +replace github.com/shirou/gopsutil/v4 => ./internal/gopsutil require ( github.com/PuerkitoBio/goquery v1.10.3 // parsing HTML for extract fav icon @@ -51,7 +49,7 @@ require ( github.com/yusing/godoxy/agent v0.0.0-20251002123031-4852efcf9c3d github.com/yusing/godoxy/internal/dnsproviders v0.0.0-20251002123031-4852efcf9c3d github.com/yusing/godoxy/internal/utils v0.1.0 - github.com/yusing/goutils v0.4.1 + github.com/yusing/goutils v0.5.2 ) require ( diff --git a/go.sum b/go.sum index 3cb5e7b5..e6716517 100644 --- a/go.sum +++ b/go.sum @@ -945,8 +945,6 @@ github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7Lk github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godoxy-app/go-oidc/v3 v3.0.0-20250816044348-0630187cb14b h1:gMLF8Nhbl86088Sugp/FFmT+fJu62GUAm+Pev6ZGTfo= github.com/godoxy-app/go-oidc/v3 v3.0.0-20250816044348-0630187cb14b/go.mod h1:x2nHY0TayhBzI25mgwp38Ru7xgGRId0FdaeqXeH8l90= -github.com/godoxy-app/gopsutil/v4 v4.0.0-20250926133131-7ef260e41a49 h1:DqfJHUG+96pLB1FM7O3E7rq7Ilx+p7Zt2n2OyqToUH8= -github.com/godoxy-app/gopsutil/v4 v4.0.0-20250926133131-7ef260e41a49/go.mod h1:Ks7ccJvOucVh3BbyyvPApw93nefgMYXrieZvLJdex+w= github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -1650,8 +1648,8 @@ github.com/yusing/ds v0.2.0 h1:lPhDU5eA2uvquVrBrzLCrQXRJJgSXlUYA53TbuK2sQY= github.com/yusing/ds v0.2.0/go.mod h1:XhKV4l7cZwBbbl7lRzNC9zX27zvCM0frIwiuD40ULRk= github.com/yusing/gointernals v0.1.16 h1:GrhZZdxzA+jojLEqankctJrOuAYDb7kY1C93S1pVR34= github.com/yusing/gointernals v0.1.16/go.mod h1:B/0FVXt4WPmgzVy3ynzkqKi+BSGaJVmwCJBRXYapo34= -github.com/yusing/goutils v0.4.1 h1:80uFNxXfm4zXMYDku0rWMLyqEiXO0UOMFOaUC4b/6fI= -github.com/yusing/goutils v0.4.1/go.mod h1:xsoLWLtIiu7k+9Bn6azERDs5o3Djb3b2/DW1htHrOjg= +github.com/yusing/goutils v0.5.2 h1:h3Xbz3buTqH3SaL3LPdd/4wgNIQXcnHjNvCIlhOr5B0= +github.com/yusing/goutils v0.5.2/go.mod h1:3dgYe/A3+8wT88/iAHwXdL44q5bP+qVo2WAOiPBqOrg= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= diff --git a/internal/dnsproviders/go.mod b/internal/dnsproviders/go.mod index 541daff5..40e8f4d2 100644 --- a/internal/dnsproviders/go.mod +++ b/internal/dnsproviders/go.mod @@ -155,7 +155,7 @@ require ( github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect github.com/yusing/godoxy/internal/utils v0.1.0 // indirect github.com/yusing/gointernals v0.1.16 // indirect - github.com/yusing/goutils v0.4.2 // indirect + github.com/yusing/goutils v0.5.2 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect diff --git a/internal/dnsproviders/go.sum b/internal/dnsproviders/go.sum index a29a032a..4b402d8d 100644 --- a/internal/dnsproviders/go.sum +++ b/internal/dnsproviders/go.sum @@ -1527,8 +1527,8 @@ github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusing/gointernals v0.1.16 h1:GrhZZdxzA+jojLEqankctJrOuAYDb7kY1C93S1pVR34= github.com/yusing/gointernals v0.1.16/go.mod h1:B/0FVXt4WPmgzVy3ynzkqKi+BSGaJVmwCJBRXYapo34= -github.com/yusing/goutils v0.4.2 h1:JRC14SUJ54nTIHxi8Z66cHJSMlifsyKO1z8RZCHBkUI= -github.com/yusing/goutils v0.4.2/go.mod h1:67EfLJlq9WQfP/uRxm0dD+WFRsxTK0MzZG3jXOI3wX8= +github.com/yusing/goutils v0.5.2 h1:h3Xbz3buTqH3SaL3LPdd/4wgNIQXcnHjNvCIlhOr5B0= +github.com/yusing/goutils v0.5.2/go.mod h1:3dgYe/A3+8wT88/iAHwXdL44q5bP+qVo2WAOiPBqOrg= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= diff --git a/internal/gopsutil b/internal/gopsutil new file mode 160000 index 00000000..a0532a58 --- /dev/null +++ b/internal/gopsutil @@ -0,0 +1 @@ +Subproject commit a0532a58d1704530c98212890f644fe77d0fc533 diff --git a/internal/metrics/period/poller.go b/internal/metrics/period/poller.go index f763ad20..77c40ca5 100644 --- a/internal/metrics/period/poller.go +++ b/internal/metrics/period/poller.go @@ -2,7 +2,6 @@ package period import ( "context" - "encoding/json" "fmt" "net/url" "os" @@ -18,10 +17,10 @@ import ( ) type ( - PollFunc[T any] func(ctx context.Context, lastResult T) (T, error) - AggregateFunc[T any, AggregateT json.Marshaler] func(entries []T, query url.Values) (total int, result AggregateT) - FilterFunc[T any] func(entries []T, keyword string) (filtered []T) - Poller[T any, AggregateT json.Marshaler] struct { + PollFunc[T any] func(ctx context.Context, lastResult T) (T, error) + AggregateFunc[T any, AggregateT any] func(entries []T, query url.Values) (total int, result AggregateT) + FilterFunc[T any] func(entries []T, keyword string) (filtered []T) + Poller[T any, AggregateT any] struct { name string poll PollFunc[T] aggregate AggregateFunc[T, AggregateT] @@ -55,7 +54,7 @@ func initDataDir() { } } -func NewPoller[T any, AggregateT json.Marshaler]( +func NewPoller[T any, AggregateT any]( name string, poll PollFunc[T], aggregator AggregateFunc[T, AggregateT], diff --git a/internal/metrics/systeminfo/json.go b/internal/metrics/systeminfo/json.go deleted file mode 100644 index cdce9460..00000000 --- a/internal/metrics/systeminfo/json.go +++ /dev/null @@ -1,183 +0,0 @@ -package systeminfo - -import ( - "fmt" - "strconv" -) - -// explicitly implement MarshalJSON to avoid reflection. -func (s *SystemInfo) MarshalJSON() ([]byte, error) { - b := make([]byte, 0, 4096) - - b = append(b, '{') - - // timestamp - b = append(b, `"timestamp":`...) - b = strconv.AppendInt(b, s.Timestamp, 10) - - // cpu_average - b = append(b, `,"cpu_average":`...) - if s.CPUAverage != nil { - b = strconv.AppendFloat(b, *s.CPUAverage, 'f', 2, 64) - } else { - b = append(b, "null"...) - } - - // memory - b = append(b, `,"memory":`...) - if s.Memory != nil { - b = fmt.Appendf(b, - `{"total":%d,"available":%d,"used":%d,"used_percent":%.2f}`, - s.Memory.Total, - s.Memory.Available, - s.Memory.Used, - s.Memory.UsedPercent, - ) - } else { - b = append(b, "null"...) - } - - // disk - b = append(b, `,"disks":`...) - if len(s.Disks) > 0 { - b = append(b, '{') - first := true - for device, disk := range s.Disks { - if !first { - b = append(b, ',') - } - b = fmt.Appendf(b, - `%q:{"device":%q,"path":%q,"fstype":%q,"total":%d,"free":%d,"used":%d,"used_percent":%.2f}`, - device, - device, - disk.Path, - disk.Fstype, - disk.Total, - disk.Free, - disk.Used, - disk.UsedPercent, - ) - first = false - } - b = append(b, '}') - } else { - b = append(b, "null"...) - } - - // disks_io - b = append(b, `,"disks_io":`...) - if len(s.DisksIO) > 0 { - b = append(b, '{') - first := true - for name, usage := range s.DisksIO { - if !first { - b = append(b, ',') - } - b = fmt.Appendf(b, - `%q:{"name":%q,"read_bytes":%d,"write_bytes":%d,"read_speed":%.2f,"write_speed":%.2f,"iops":%d}`, - name, - name, - usage.ReadBytes, - usage.WriteBytes, - usage.ReadSpeed, - usage.WriteSpeed, - usage.Iops, - ) - first = false - } - b = append(b, '}') - } else { - b = append(b, "null"...) - } - - // network - b = append(b, `,"network":`...) - if s.Network != nil { - b = fmt.Appendf(b, - `{"bytes_sent":%d,"bytes_recv":%d,"upload_speed":%.2f,"download_speed":%.2f}`, - s.Network.BytesSent, - s.Network.BytesRecv, - s.Network.UploadSpeed, - s.Network.DownloadSpeed, - ) - } else { - b = append(b, "null"...) - } - - // sensors - b = append(b, `,"sensors":`...) - if len(s.Sensors) > 0 { - b = append(b, '[') - first := true - for _, sensor := range s.Sensors { - if !first { - b = append(b, ',') - } - b = fmt.Appendf(b, - `{"name":%q,"temperature":%.2f,"high":%.2f,"critical":%.2f}`, - sensor.SensorKey, - sensor.Temperature, - sensor.High, - sensor.Critical, - ) - first = false - } - b = append(b, ']') - } else { - b = append(b, "null"...) - } - - b = append(b, '}') - return b, nil -} - -func (result Aggregated) MarshalJSON() ([]byte, error) { - if len(result.Entries) == 0 { - return []byte("[]"), nil - } - - capacity := 10 * 1024 - if result.Mode == SystemInfoAggregateModeSensorTemperature { - // give each sensor key 30 bytes per entry per sensor key - capacity = 30 * len(result.Entries) * len(result.Entries[0]) - } - buf := make([]byte, 0, capacity) - - buf = append(buf, '[') - i := 0 - n := len(result.Entries) - for _, entry := range result.Entries { - buf = append(buf, '{') - j := 0 - m := len(entry) - for k, v := range entry { - buf = append(buf, '"') - buf = append(buf, k...) - buf = append(buf, '"') - buf = append(buf, ':') - switch v := v.(type) { - case float64: - buf = strconv.AppendFloat(buf, v, 'f', 2, 64) - case int32: - buf = strconv.AppendInt(buf, int64(v), 10) - case int64: - buf = strconv.AppendInt(buf, v, 10) - case uint64: - buf = strconv.AppendUint(buf, v, 10) - default: - panic(fmt.Sprintf("unexpected type: %T", v)) - } - if j != m-1 { - buf = append(buf, ',') - } - j++ - } - buf = append(buf, '}') - if i != n-1 { - buf = append(buf, ',') - } - i++ - } - buf = append(buf, ']') - return buf, nil -} diff --git a/internal/metrics/systeminfo/system_info.go b/internal/metrics/systeminfo/system_info.go index a489e7a4..14b280da 100644 --- a/internal/metrics/systeminfo/system_info.go +++ b/internal/metrics/systeminfo/system_info.go @@ -34,10 +34,10 @@ type ( type SystemInfo struct { Timestamp int64 `json:"timestamp"` CPUAverage *float64 `json:"cpu_average"` - Memory *mem.VirtualMemoryStat `json:"memory"` - Disks map[string]*disk.UsageStat `json:"disks"` // disk usage by partition + Memory mem.VirtualMemoryStat `json:"memory"` + Disks map[string]disk.UsageStat `json:"disks"` // disk usage by partition DisksIO map[string]*disk.IOCountersStat `json:"disks_io"` // disk IO by device - Network *net.IOCountersStat `json:"network"` + Network net.IOCountersStat `json:"network"` Sensors Sensors `json:"sensors"` // sensor temperature by key } // @name SystemInfo @@ -165,8 +165,8 @@ func (s *SystemInfo) collectDisksInfo(ctx context.Context, lastResult *SystemInf interval := since(lastResult.Timestamp) for name, disk := range s.DisksIO { if lastUsage, ok := lastResult.DisksIO[name]; ok { - disk.ReadSpeed = float64(disk.ReadBytes-lastUsage.ReadBytes) / float64(interval) - disk.WriteSpeed = float64(disk.WriteBytes-lastUsage.WriteBytes) / float64(interval) + disk.ReadSpeed = float32(disk.ReadBytes-lastUsage.ReadBytes) / float32(interval) + disk.WriteSpeed = float32(disk.WriteBytes-lastUsage.WriteBytes) / float32(interval) disk.Iops = diff(disk.ReadCount+disk.WriteCount, lastUsage.ReadCount+lastUsage.WriteCount) / uint64(interval) //nolint:gosec } } @@ -176,7 +176,7 @@ func (s *SystemInfo) collectDisksInfo(ctx context.Context, lastResult *SystemInf if err != nil { return err } - s.Disks = make(map[string]*disk.UsageStat, len(partitions)) + s.Disks = make(map[string]disk.UsageStat, len(partitions)) errs := gperr.NewBuilder("failed to get disks info") for _, partition := range partitions { diskInfo, err := disk.UsageWithContext(ctx, partition.Mountpoint) @@ -203,9 +203,9 @@ func (s *SystemInfo) collectNetworkInfo(ctx context.Context, lastResult *SystemI } s.Network = networkIO[0] if lastResult != nil { - interval := float64(since(lastResult.Timestamp)) - s.Network.UploadSpeed = float64(networkIO[0].BytesSent-lastResult.Network.BytesSent) / interval - s.Network.DownloadSpeed = float64(networkIO[0].BytesRecv-lastResult.Network.BytesRecv) / interval + interval := float32(since(lastResult.Timestamp)) + s.Network.UploadSpeed = float32(networkIO[0].BytesSent-lastResult.Network.BytesSent) / interval + s.Network.DownloadSpeed = float32(networkIO[0].BytesRecv-lastResult.Network.BytesRecv) / interval } return nil } @@ -238,7 +238,7 @@ func aggregate(entries []*SystemInfo, query url.Values) (total int, result Aggre } case SystemInfoAggregateModeMemoryUsage: for _, entry := range entries { - if entry.Memory != nil { + if entry.Memory.Used > 0 { aggregated.Entries = append(aggregated.Entries, map[string]any{ "timestamp": entry.Timestamp, "memory_usage": entry.Memory.Used, @@ -247,7 +247,7 @@ func aggregate(entries []*SystemInfo, query url.Values) (total int, result Aggre } case SystemInfoAggregateModeMemoryUsagePercent: for _, entry := range entries { - if entry.Memory != nil { + if entry.Memory.UsedPercent > 0 { aggregated.Entries = append(aggregated.Entries, map[string]any{ "timestamp": entry.Timestamp, "memory_usage_percent": entry.Memory.UsedPercent, @@ -304,7 +304,7 @@ func aggregate(entries []*SystemInfo, query url.Values) (total int, result Aggre } case SystemInfoAggregateModeNetworkSpeed: for _, entry := range entries { - if entry.Network == nil { + if entry.Network.BytesSent == 0 && entry.Network.BytesRecv == 0 { continue } aggregated.Entries = append(aggregated.Entries, map[string]any{ @@ -315,7 +315,7 @@ func aggregate(entries []*SystemInfo, query url.Values) (total int, result Aggre } case SystemInfoAggregateModeNetworkTransfer: for _, entry := range entries { - if entry.Network == nil { + if entry.Network.BytesRecv > 0 || entry.Network.BytesSent > 0 { continue } aggregated.Entries = append(aggregated.Entries, map[string]any{ diff --git a/internal/metrics/systeminfo/system_info_test.go b/internal/metrics/systeminfo/system_info_test.go index d6bc1d4e..e8b2d453 100644 --- a/internal/metrics/systeminfo/system_info_test.go +++ b/internal/metrics/systeminfo/system_info_test.go @@ -6,10 +6,12 @@ import ( "reflect" "testing" + "github.com/bytedance/sonic" "github.com/shirou/gopsutil/v4/disk" "github.com/shirou/gopsutil/v4/mem" "github.com/shirou/gopsutil/v4/net" "github.com/shirou/gopsutil/v4/sensors" + "github.com/yusing/goutils/num" expect "github.com/yusing/goutils/testing" ) @@ -19,13 +21,13 @@ var ( testInfo = &SystemInfo{ Timestamp: 123456, CPUAverage: &cpuAvg, - Memory: &mem.VirtualMemoryStat{ + Memory: mem.VirtualMemoryStat{ Total: 16000000000, Available: 8000000000, Used: 8000000000, UsedPercent: 50.0, }, - Disks: map[string]*disk.UsageStat{ + Disks: map[string]disk.UsageStat{ "sda": { Path: "/", Fstype: "ext4", @@ -48,20 +50,24 @@ var ( Name: "media", ReadBytes: 1000000, WriteBytes: 2000000, - ReadSpeed: 100.5, - WriteSpeed: 200.5, - Iops: 1000, + IOCountersStatExtra: disk.IOCountersStatExtra{ + ReadSpeed: 100.5, + WriteSpeed: 200.5, + Iops: 1000, + }, }, "nvme0n1": { Name: "nvme0n1", ReadBytes: 1000000, WriteBytes: 2000000, - ReadSpeed: 100.5, - WriteSpeed: 200.5, - Iops: 1000, + IOCountersStatExtra: disk.IOCountersStatExtra{ + ReadSpeed: 100.5, + WriteSpeed: 200.5, + Iops: 1000, + }, }, }, - Network: &net.IOCountersStat{ + Network: net.IOCountersStat{ BytesSent: 5000000, BytesRecv: 10000000, UploadSpeed: 1024.5, @@ -70,15 +76,15 @@ var ( Sensors: []sensors.TemperatureStat{ { SensorKey: "cpu_temp", - Temperature: 30.0, - High: 40.0, - Critical: 50.0, + Temperature: num.NewPercentage(30.0), + High: num.NewPercentage(40.0), + Critical: num.NewPercentage(50.0), }, { SensorKey: "gpu_temp", - Temperature: 40.0, - High: 50.0, - Critical: 60.0, + Temperature: num.NewPercentage(40.0), + High: num.NewPercentage(50.0), + Critical: num.NewPercentage(60.0), }, }, } @@ -86,12 +92,12 @@ var ( func TestSystemInfo(t *testing.T) { // Test marshaling - data, err := json.Marshal(testInfo) + data, err := sonic.Marshal(testInfo) expect.NoError(t, err) // Test unmarshaling back var decoded SystemInfo - err = json.Unmarshal(data, &decoded) + err = sonic.Unmarshal(data, &decoded) expect.NoError(t, err) // Compare original and decoded @@ -116,71 +122,32 @@ func TestSystemInfo(t *testing.T) { expect.NoError(t, err) expect.Equal(t, decodedNil.Timestamp, nilInfo.Timestamp) - expect.True(t, decodedNil.CPUAverage == nil) - expect.True(t, decodedNil.Memory == nil) - expect.True(t, decodedNil.Disks == nil) - expect.True(t, decodedNil.Network == nil) - expect.True(t, decodedNil.Sensors == nil) + // expect.True(t, decodedNil.CPUAverage == nil) + // expect.True(t, decodedNil.Memory == nil) + // expect.True(t, decodedNil.Disks == nil) + // expect.True(t, decodedNil.Network == nil) + // expect.True(t, decodedNil.Sensors == nil) } func TestSerialize(t *testing.T) { entries := make([]*SystemInfo, 5) - for i := 0; i < 5; i++ { + for i := range 5 { entries[i] = testInfo } for _, query := range allQueries { t.Run(string(query), func(t *testing.T) { _, result := aggregate(entries, url.Values{"aggregate": []string{string(query)}}) - s, err := result.MarshalJSON() + s, err := sonic.Marshal(result) expect.NoError(t, err) var v []map[string]any expect.NoError(t, json.Unmarshal(s, &v)) expect.Equal(t, len(v), len(result.Entries)) for i, m := range v { for k, v := range m { - // some int64 values are converted to float64 on json.Unmarshal vv := reflect.ValueOf(result.Entries[i][k]) - expect.Equal(t, reflect.ValueOf(v).Convert(vv.Type()).Interface(), vv.Interface()) + expect.Equal(t, reflect.ValueOf(v).Interface(), vv.Interface()) } } }) } } - -func BenchmarkSerialize(b *testing.B) { - entries := make([]*SystemInfo, b.N) - for i := range b.N { - entries[i] = testInfo - } - queries := map[string]Aggregated{} - for _, query := range allQueries { - _, result := aggregate(entries, url.Values{"aggregate": []string{string(query)}}) - queries[string(query)] = result - } - b.ReportAllocs() - b.ResetTimer() - b.Run("optimized-non-query", func(b *testing.B) { - for b.Loop() { - _, _ = testInfo.MarshalJSON() - } - }) - b.Run("json-non-query", func(b *testing.B) { - for b.Loop() { - _, _ = json.Marshal(testInfo) - } - }) - b.Run("optimized", func(b *testing.B) { - for b.Loop() { - for _, query := range allQueries { - _, _ = queries[string(query)].MarshalJSON() - } - } - }) - b.Run("json", func(b *testing.B) { - for b.Loop() { - for _, query := range allQueries { - _, _ = json.Marshal([]map[string]any(queries[string(query)].Entries)) - } - } - }) -} diff --git a/internal/utils/atomic/value.go b/internal/utils/atomic/value.go index 65140fef..51db36cf 100644 --- a/internal/utils/atomic/value.go +++ b/internal/utils/atomic/value.go @@ -1,8 +1,9 @@ package atomic import ( - "encoding/json" "sync/atomic" + + "github.com/bytedance/sonic" ) type Value[T any] struct { @@ -30,5 +31,5 @@ func (a *Value[T]) Swap(v T) T { } func (a *Value[T]) MarshalJSON() ([]byte, error) { - return json.Marshal(a.Load()) + return sonic.Marshal(a.Load()) } diff --git a/internal/utils/go.mod b/internal/utils/go.mod index fe17b665..ef55b249 100644 --- a/internal/utils/go.mod +++ b/internal/utils/go.mod @@ -5,6 +5,7 @@ go 1.25.1 exclude github.com/yusing/goutils v0.4.2 require ( + github.com/bytedance/sonic v1.14.1 github.com/puzpuzpuz/xsync/v4 v4.2.0 github.com/rs/zerolog v1.34.0 github.com/yusing/goutils v0.4.1 @@ -12,11 +13,17 @@ require ( ) require ( + github.com/bytedance/gopkg v0.1.3 // indirect + github.com/bytedance/sonic/loader v0.3.0 // indirect + github.com/cloudwego/base64x v0.1.6 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/stretchr/testify v1.11.1 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + golang.org/x/arch v0.21.0 // indirect golang.org/x/sys v0.36.0 // indirect golang.org/x/text v0.29.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/internal/utils/go.sum b/internal/utils/go.sum index 27e71c09..b5114b60 100644 --- a/internal/utils/go.sum +++ b/internal/utils/go.sum @@ -1,7 +1,19 @@ +github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M= +github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM= +github.com/bytedance/sonic v1.14.1 h1:FBMC0zVz5XUmE4z9wF4Jey0An5FueFvOsTKKKtwIl7w= +github.com/bytedance/sonic v1.14.1/go.mod h1:gi6uhQLMbTdeP0muCnrjHLeCUPyb70ujhnNlhOylAFc= +github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA= +github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= +github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M= +github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= +github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= @@ -10,6 +22,7 @@ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/puzpuzpuz/xsync/v4 v4.2.0 h1:dlxm77dZj2c3rxq0/XNvvUKISAmovoXF4a4qM6Wvkr0= @@ -17,12 +30,22 @@ github.com/puzpuzpuz/xsync/v4 v4.2.0/go.mod h1:VJDmTCJMBt8igNxnkQd86r+8KUeN1quSf github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/yusing/goutils v0.4.1 h1:80uFNxXfm4zXMYDku0rWMLyqEiXO0UOMFOaUC4b/6fI= github.com/yusing/goutils v0.4.1/go.mod h1:xsoLWLtIiu7k+9Bn6azERDs5o3Djb3b2/DW1htHrOjg= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +golang.org/x/arch v0.21.0 h1:iTC9o7+wP6cPWpDWkivCvQFGAHDQ59SrSxsLPcnkArw= +golang.org/x/arch v0.21.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -32,5 +55,6 @@ golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=