6
6
package metrics
7
7
8
8
import (
9
+ "flag"
10
+ "io"
9
11
"os"
10
12
"runtime/metrics"
11
13
"runtime/pprof"
12
14
"strconv"
13
- "strings"
14
15
"syscall"
15
16
"time"
16
17
17
- "github.com/ethereum/go-ethereum/log "
18
+ "github.com/naoina/toml "
18
19
)
19
20
20
21
// Enabled is checked by the constructor functions for all of the
@@ -24,34 +25,58 @@ import (
24
25
// for less cluttered pprof profiles.
25
26
var Enabled = false
26
27
27
- // enablerFlags is the CLI flag names to use to enable metrics collections.
28
- var enablerFlags = []string {"metrics" }
29
-
30
- // enablerEnvVars is the env var names to use to enable metrics collections.
31
- var enablerEnvVars = []string {"GETH_METRICS" }
32
-
33
28
// init enables or disables the metrics system. Since we need this to run before
34
29
// any other code gets to create meters and timers, we'll actually do an ugly hack
35
30
// and peek into the command line args for the metrics flag.
36
31
func init () {
37
- for _ , enabler := range enablerEnvVars {
38
- if val , found := syscall .Getenv (enabler ); found && ! Enabled {
39
- if enable , _ := strconv .ParseBool (val ); enable { // ignore error, flag parser will choke on it later
40
- log .Info ("Enabling metrics collection" )
41
- Enabled = true
42
- }
32
+ if val , found := syscall .Getenv ("GETH_METRICS" ); found && ! Enabled {
33
+ if enable , _ := strconv .ParseBool (val ); enable { // ignore error, flag parser will choke on it later
34
+ Enabled = true
43
35
}
44
36
}
45
- for _ , arg := range os .Args {
46
- flag := strings .TrimLeft (arg , "-" )
47
37
48
- for _ , enabler := range enablerFlags {
49
- if ! Enabled && flag == enabler {
50
- log .Info ("Enabling metrics collection" )
51
- Enabled = true
52
- }
38
+ fs := flag .NewFlagSet ("" , flag .ContinueOnError )
39
+ fs .SetOutput (io .Discard )
40
+ fs .Bool ("metrics" , false , "" )
41
+ fs .String ("config" , "" , "" )
42
+
43
+ // The flag package will quit parsing immediately if it encounters a flag that
44
+ // it was not declared to it ahead of time. We could be fancy and try to look
45
+ // through the args and find the ones we care about, but then we'd need to
46
+ // handle the various ways that flags can be defined -- which was the point of
47
+ // using flags package in the first place! So instead, let's chop off the
48
+ // first element in the args list each time a parse fails. This way we will
49
+ // eventually parse every arg and get the ones we care about.
50
+ for i := range os .Args [1 :] {
51
+ if err := fs .Parse (os .Args [i + 1 :]); err == nil {
52
+ break
53
53
}
54
54
}
55
+
56
+ // Now visit the flags we defined which are present in the args and see if we
57
+ // should enable metrics.
58
+ fs .Visit (func (f * flag.Flag ) {
59
+ switch f .Name {
60
+ case "metrics" :
61
+ Enabled = true
62
+ case "config" :
63
+ data , err := os .ReadFile (f .Value .String ())
64
+ if err != nil {
65
+ return
66
+ }
67
+ var cfg map [string ]map [string ]any
68
+ if err := toml .Unmarshal (data , & cfg ); err != nil {
69
+ return
70
+ }
71
+ // A config file is definitely being used and was parsed correct. Let's
72
+ // try to peek inside and see if metrics are listed as enabled.
73
+ if m , ok := cfg ["Metrics" ]; ok {
74
+ if v , ok := m ["Enabled" ].(bool ); ok && v {
75
+ Enabled = true
76
+ }
77
+ }
78
+ }
79
+ })
55
80
}
56
81
57
82
var threadCreateProfile = pprof .Lookup ("threadcreate" )
0 commit comments