github.com/dominant-strategies/go-quai@v0.28.2/metrics/metrics.go (about) 1 // Go port of Coda Hale's Metrics library 2 // 3 // <https://github.com/rcrowley/go-metrics> 4 // 5 // Coda Hale's original work: <https://github.com/codahale/metrics> 6 package metrics 7 8 import ( 9 "os" 10 "runtime" 11 "strings" 12 "time" 13 14 "github.com/dominant-strategies/go-quai/log" 15 ) 16 17 // Enabled is checked by the constructor functions for all of the 18 // standard metrics. If it is true, the metric returned is a stub. 19 // 20 // This global kill-switch helps quantify the observer effect and makes 21 // for less cluttered pprof profiles. 22 var Enabled = false 23 24 // EnabledExpensive is a soft-flag meant for external packages to check if costly 25 // metrics gathering is allowed or not. The goal is to separate standard metrics 26 // for health monitoring and debug metrics that might impact runtime performance. 27 var EnabledExpensive = false 28 29 // enablerFlags is the CLI flag names to use to enable metrics collections. 30 var enablerFlags = []string{"metrics"} 31 32 // expensiveEnablerFlags is the CLI flag names to use to enable metrics collections. 33 var expensiveEnablerFlags = []string{"metrics.expensive"} 34 35 // Init enables or disables the metrics system. Since we need this to run before 36 // any other code gets to create meters and timers, we'll actually do an ugly hack 37 // and peek into the command line args for the metrics flag. 38 func init() { 39 for _, arg := range os.Args { 40 flag := strings.TrimLeft(arg, "-") 41 42 for _, enabler := range enablerFlags { 43 if !Enabled && flag == enabler { 44 log.Info("Enabling metrics collection") 45 Enabled = true 46 } 47 } 48 for _, enabler := range expensiveEnablerFlags { 49 if !EnabledExpensive && flag == enabler { 50 log.Info("Enabling expensive metrics collection") 51 EnabledExpensive = true 52 } 53 } 54 } 55 } 56 57 // CollectProcessMetrics periodically collects various metrics about the running 58 // process. 59 func CollectProcessMetrics(refresh time.Duration) { 60 // Short circuit if the metrics system is disabled 61 if !Enabled { 62 return 63 } 64 refreshFreq := int64(refresh / time.Second) 65 66 // Create the various data collectors 67 cpuStats := make([]*CPUStats, 2) 68 memstats := make([]*runtime.MemStats, 2) 69 diskstats := make([]*DiskStats, 2) 70 for i := 0; i < len(memstats); i++ { 71 cpuStats[i] = new(CPUStats) 72 memstats[i] = new(runtime.MemStats) 73 diskstats[i] = new(DiskStats) 74 } 75 // Define the various metrics to collect 76 var ( 77 cpuSysLoad = GetOrRegisterGauge("system/cpu/sysload", DefaultRegistry) 78 cpuSysWait = GetOrRegisterGauge("system/cpu/syswait", DefaultRegistry) 79 cpuProcLoad = GetOrRegisterGauge("system/cpu/procload", DefaultRegistry) 80 cpuThreads = GetOrRegisterGauge("system/cpu/threads", DefaultRegistry) 81 cpuGoroutines = GetOrRegisterGauge("system/cpu/goroutines", DefaultRegistry) 82 83 memPauses = GetOrRegisterMeter("system/memory/pauses", DefaultRegistry) 84 memAllocs = GetOrRegisterMeter("system/memory/allocs", DefaultRegistry) 85 memFrees = GetOrRegisterMeter("system/memory/frees", DefaultRegistry) 86 memHeld = GetOrRegisterGauge("system/memory/held", DefaultRegistry) 87 memUsed = GetOrRegisterGauge("system/memory/used", DefaultRegistry) 88 89 diskReads = GetOrRegisterMeter("system/disk/readcount", DefaultRegistry) 90 diskReadBytes = GetOrRegisterMeter("system/disk/readdata", DefaultRegistry) 91 diskReadBytesCounter = GetOrRegisterCounter("system/disk/readbytes", DefaultRegistry) 92 diskWrites = GetOrRegisterMeter("system/disk/writecount", DefaultRegistry) 93 diskWriteBytes = GetOrRegisterMeter("system/disk/writedata", DefaultRegistry) 94 diskWriteBytesCounter = GetOrRegisterCounter("system/disk/writebytes", DefaultRegistry) 95 ) 96 // Iterate loading the different stats and updating the meters 97 for i := 1; ; i++ { 98 location1 := i % 2 99 location2 := (i - 1) % 2 100 101 ReadCPUStats(cpuStats[location1]) 102 cpuSysLoad.Update((cpuStats[location1].GlobalTime - cpuStats[location2].GlobalTime) / refreshFreq) 103 cpuSysWait.Update((cpuStats[location1].GlobalWait - cpuStats[location2].GlobalWait) / refreshFreq) 104 cpuProcLoad.Update((cpuStats[location1].LocalTime - cpuStats[location2].LocalTime) / refreshFreq) 105 cpuThreads.Update(int64(threadCreateProfile.Count())) 106 cpuGoroutines.Update(int64(runtime.NumGoroutine())) 107 108 runtime.ReadMemStats(memstats[location1]) 109 memPauses.Mark(int64(memstats[location1].PauseTotalNs - memstats[location2].PauseTotalNs)) 110 memAllocs.Mark(int64(memstats[location1].Mallocs - memstats[location2].Mallocs)) 111 memFrees.Mark(int64(memstats[location1].Frees - memstats[location2].Frees)) 112 memHeld.Update(int64(memstats[location1].HeapSys - memstats[location1].HeapReleased)) 113 memUsed.Update(int64(memstats[location1].Alloc)) 114 115 if ReadDiskStats(diskstats[location1]) == nil { 116 diskReads.Mark(diskstats[location1].ReadCount - diskstats[location2].ReadCount) 117 diskReadBytes.Mark(diskstats[location1].ReadBytes - diskstats[location2].ReadBytes) 118 diskWrites.Mark(diskstats[location1].WriteCount - diskstats[location2].WriteCount) 119 diskWriteBytes.Mark(diskstats[location1].WriteBytes - diskstats[location2].WriteBytes) 120 121 diskReadBytesCounter.Inc(diskstats[location1].ReadBytes - diskstats[location2].ReadBytes) 122 diskWriteBytesCounter.Inc(diskstats[location1].WriteBytes - diskstats[location2].WriteBytes) 123 } 124 time.Sleep(refresh) 125 } 126 }