banyand/observability/metrics_system.go (106 lines of code) (raw):

// Licensed to Apache Software Foundation (ASF) under one or more contributor // license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright // ownership. Apache Software Foundation (ASF) licenses this file to you under // the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. package observability import ( "context" "strings" "sync" "github.com/shirou/gopsutil/v3/cpu" "github.com/shirou/gopsutil/v3/mem" "github.com/shirou/gopsutil/v3/net" "github.com/apache/skywalking-banyandb/pkg/logger" "github.com/apache/skywalking-banyandb/pkg/meter" ) var log = logger.GetLogger("observability", "metrics", "system") var ( cpuCount = 0 once4CpuCount sync.Once cpuCountsFunc = cpu.Counts cpuTimesFunc = cpu.Times ) var ( // RootScope is the root scope for all metrics. RootScope = meter.NewHierarchicalScope("banyandb", "_") systemScope = RootScope.SubScope("system") systemProvider = NewMeterProvider(systemScope) cpuStateGauge = systemProvider.Gauge("cpu_state", "kind") cpuNumGauge = systemProvider.Gauge("cpu_num") memorySateGauge = systemProvider.Gauge("memory_state", "kind") netStateGauge = systemProvider.Gauge("net_state", "kind", "name") ) func init() { MetricsCollector.Register("cpu", collectCPU) MetricsCollector.Register("memory", collectMemory) MetricsCollector.Register("net", collectNet) } func collectCPU() { once4CpuCount.Do(func() { if c, err := cpuCountsFunc(false); err != nil { log.Error().Err(err).Msg("cannot get cpu count") } else { cpuCount = c } }) cpuNumGauge.Set(float64(cpuCount)) s, err := cpuTimesFunc(false) if err != nil { log.Error().Err(err).Msg("cannot get cpu stat") } if len(s) == 0 { log.Error().Msg("cannot get cpu stat") } allStat := s[0] total := allStat.User + allStat.System + allStat.Idle + allStat.Nice + allStat.Iowait + allStat.Irq + allStat.Softirq + allStat.Steal + allStat.Guest + allStat.GuestNice cpuStateGauge.Set(allStat.User/total, "user") cpuStateGauge.Set(allStat.System/total, "system") cpuStateGauge.Set(allStat.Idle/total, "idle") cpuStateGauge.Set(allStat.Nice/total, "nice") cpuStateGauge.Set(allStat.Iowait/total, "iowait") cpuStateGauge.Set(allStat.Irq/total, "irq") cpuStateGauge.Set(allStat.Softirq/total, "softirq") cpuStateGauge.Set(allStat.Steal/total, "steal") } func collectMemory() { m, err := mem.VirtualMemory() if err != nil { log.Error().Err(err).Msg("cannot get memory stat") } memorySateGauge.Set(m.UsedPercent/100, "used_percent") memorySateGauge.Set(float64(m.Used)/float64(m.Total), "used") } func collectNet() { stats, err := getNetStat(context.Background()) if err != nil { log.Error().Err(err).Msg("cannot get net stat") } for _, stat := range stats { netStateGauge.Set(float64(stat.BytesRecv), "bytes_recv", stat.Name) netStateGauge.Set(float64(stat.BytesSent), "bytes_sent", stat.Name) netStateGauge.Set(float64(stat.PacketsRecv), "packets_recv", stat.Name) netStateGauge.Set(float64(stat.PacketsSent), "packets_sent", stat.Name) netStateGauge.Set(float64(stat.Errin), "errin", stat.Name) netStateGauge.Set(float64(stat.Errout), "errout", stat.Name) netStateGauge.Set(float64(stat.Dropin), "dropin", stat.Name) netStateGauge.Set(float64(stat.Dropout), "dropout", stat.Name) netStateGauge.Set(float64(stat.Fifoin), "fifoin", stat.Name) netStateGauge.Set(float64(stat.Fifoout), "fifoout", stat.Name) } } func getNetStat(ctx context.Context) ([]net.IOCountersStat, error) { stats, err := net.IOCountersWithContext(ctx, true) if err != nil { return nil, err } var availableStats []net.IOCountersStat for _, stat := range stats { switch { // OS X case strings.HasPrefix(stat.Name, "en"): // Linux case strings.HasPrefix(stat.Name, "eth"): default: continue } // ignore empty interface if stat.BytesRecv == 0 || stat.BytesSent == 0 { continue } availableStats = append(availableStats, stat) } return availableStats, nil }