github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/metrics/metrics.go (about) 1 // Copyright 2015 The Spectrum Authors 2 // This file is part of the Spectrum library. 3 // 4 // The Spectrum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The Spectrum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the Spectrum library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Package metrics provides general system and process level metrics collection. 18 package metrics 19 20 import ( 21 "os" 22 "runtime" 23 "strings" 24 "time" 25 26 "github.com/SmartMeshFoundation/Spectrum/log" 27 "github.com/rcrowley/go-metrics" 28 "github.com/rcrowley/go-metrics/exp" 29 ) 30 31 // MetricsEnabledFlag is the CLI flag name to use to enable metrics collections. 32 const MetricsEnabledFlag = "metrics" 33 const DashboardEnabledFlag = "dashboard" 34 35 // Enabled is the flag specifying if metrics are enable or not. 36 var Enabled = false 37 38 // Init enables or disables the metrics system. Since we need this to run before 39 // any other code gets to create meters and timers, we'll actually do an ugly hack 40 // and peek into the command line args for the metrics flag. 41 func init() { 42 for _, arg := range os.Args { 43 if flag := strings.TrimLeft(arg, "-"); flag == MetricsEnabledFlag || flag == DashboardEnabledFlag { 44 log.Info("Enabling metrics collection") 45 Enabled = true 46 } 47 } 48 exp.Exp(metrics.DefaultRegistry) 49 } 50 51 // NewCounter create a new metrics Counter, either a real one of a NOP stub depending 52 // on the metrics flag. 53 func NewCounter(name string) metrics.Counter { 54 if !Enabled { 55 return new(metrics.NilCounter) 56 } 57 return metrics.GetOrRegisterCounter(name, metrics.DefaultRegistry) 58 } 59 60 // NewMeter create a new metrics Meter, either a real one of a NOP stub depending 61 // on the metrics flag. 62 func NewMeter(name string) metrics.Meter { 63 if !Enabled { 64 return new(metrics.NilMeter) 65 } 66 return metrics.GetOrRegisterMeter(name, metrics.DefaultRegistry) 67 } 68 69 // NewTimer create a new metrics Timer, either a real one of a NOP stub depending 70 // on the metrics flag. 71 func NewTimer(name string) metrics.Timer { 72 if !Enabled { 73 return new(metrics.NilTimer) 74 } 75 return metrics.GetOrRegisterTimer(name, metrics.DefaultRegistry) 76 } 77 78 // CollectProcessMetrics periodically collects various metrics about the running 79 // process. 80 func CollectProcessMetrics(refresh time.Duration) { 81 // Short circuit if the metrics system is disabled 82 if !Enabled { 83 return 84 } 85 // Create the various data collectors 86 memstats := make([]*runtime.MemStats, 2) 87 diskstats := make([]*DiskStats, 2) 88 for i := 0; i < len(memstats); i++ { 89 memstats[i] = new(runtime.MemStats) 90 diskstats[i] = new(DiskStats) 91 } 92 // Define the various metrics to collect 93 memAllocs := metrics.GetOrRegisterMeter("system/memory/allocs", metrics.DefaultRegistry) 94 memFrees := metrics.GetOrRegisterMeter("system/memory/frees", metrics.DefaultRegistry) 95 memInuse := metrics.GetOrRegisterMeter("system/memory/inuse", metrics.DefaultRegistry) 96 memPauses := metrics.GetOrRegisterMeter("system/memory/pauses", metrics.DefaultRegistry) 97 98 var diskReads, diskReadBytes, diskWrites, diskWriteBytes metrics.Meter 99 if err := ReadDiskStats(diskstats[0]); err == nil { 100 diskReads = metrics.GetOrRegisterMeter("system/disk/readcount", metrics.DefaultRegistry) 101 diskReadBytes = metrics.GetOrRegisterMeter("system/disk/readdata", metrics.DefaultRegistry) 102 diskWrites = metrics.GetOrRegisterMeter("system/disk/writecount", metrics.DefaultRegistry) 103 diskWriteBytes = metrics.GetOrRegisterMeter("system/disk/writedata", metrics.DefaultRegistry) 104 } else { 105 log.Debug("Failed to read disk metrics", "err", err) 106 } 107 // Iterate loading the different stats and updating the meters 108 for i := 1; ; i++ { 109 runtime.ReadMemStats(memstats[i%2]) 110 memAllocs.Mark(int64(memstats[i%2].Mallocs - memstats[(i-1)%2].Mallocs)) 111 memFrees.Mark(int64(memstats[i%2].Frees - memstats[(i-1)%2].Frees)) 112 memInuse.Mark(int64(memstats[i%2].Alloc - memstats[(i-1)%2].Alloc)) 113 memPauses.Mark(int64(memstats[i%2].PauseTotalNs - memstats[(i-1)%2].PauseTotalNs)) 114 115 if ReadDiskStats(diskstats[i%2]) == nil { 116 diskReads.Mark(diskstats[i%2].ReadCount - diskstats[(i-1)%2].ReadCount) 117 diskReadBytes.Mark(diskstats[i%2].ReadBytes - diskstats[(i-1)%2].ReadBytes) 118 diskWrites.Mark(diskstats[i%2].WriteCount - diskstats[(i-1)%2].WriteCount) 119 diskWriteBytes.Mark(diskstats[i%2].WriteBytes - diskstats[(i-1)%2].WriteBytes) 120 } 121 time.Sleep(refresh) 122 } 123 }