github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/metrics/metrics.go (about)

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