github.com/imannamdari/v2ray-core/v5@v5.0.5/main/commands/all/api/stats.go (about) 1 package api 2 3 import ( 4 "fmt" 5 "os" 6 "sort" 7 "strings" 8 "time" 9 10 statsService "github.com/imannamdari/v2ray-core/v5/app/stats/command" 11 "github.com/imannamdari/v2ray-core/v5/common/units" 12 "github.com/imannamdari/v2ray-core/v5/main/commands/base" 13 ) 14 15 var cmdStats = &base.Command{ 16 CustomFlags: true, 17 UsageLine: "{{.Exec}} api stats [--server=127.0.0.1:8080] [pattern]...", 18 Short: "query statistics", 19 Long: ` 20 Query statistics from V2Ray. 21 22 > Make sure you have "StatsService" set in "config.api.services" 23 of server config. 24 25 Arguments: 26 27 -regexp 28 The patterns are using regexp. 29 30 -reset 31 Reset counters to 0 after fetching their values. 32 33 -runtime 34 Get runtime statistics. 35 36 -json 37 Use json output. 38 39 -s, -server <server:port> 40 The API server address. Default 127.0.0.1:8080 41 42 -t, -timeout <seconds> 43 Timeout seconds to call API. Default 3 44 45 Example: 46 47 {{.Exec}} {{.LongName}} -runtime 48 {{.Exec}} {{.LongName}} node1 49 {{.Exec}} {{.LongName}} -json node1 node2 50 {{.Exec}} {{.LongName}} -regexp 'node1.+downlink' 51 `, 52 Run: executeStats, 53 } 54 55 func executeStats(cmd *base.Command, args []string) { 56 setSharedFlags(cmd) 57 var ( 58 runtime bool 59 regexp bool 60 reset bool 61 ) 62 cmd.Flag.BoolVar(&runtime, "runtime", false, "") 63 cmd.Flag.BoolVar(®exp, "regexp", false, "") 64 cmd.Flag.BoolVar(&reset, "reset", false, "") 65 cmd.Flag.Parse(args) 66 unnamed := cmd.Flag.Args() 67 if runtime { 68 getRuntimeStats(apiJSON) 69 return 70 } 71 getStats(unnamed, regexp, reset, apiJSON) 72 } 73 74 func getRuntimeStats(jsonOutput bool) { 75 conn, ctx, close := dialAPIServer() 76 defer close() 77 78 client := statsService.NewStatsServiceClient(conn) 79 r := &statsService.SysStatsRequest{} 80 resp, err := client.GetSysStats(ctx, r) 81 if err != nil { 82 base.Fatalf("failed to get sys stats: %s", err) 83 } 84 if jsonOutput { 85 showJSONResponse(resp) 86 return 87 } 88 showRuntimeStats(resp) 89 } 90 91 func showRuntimeStats(s *statsService.SysStatsResponse) { 92 formats := []string{"%-22s", "%-10s"} 93 rows := [][]string{ 94 {"Up time", (time.Duration(s.Uptime) * time.Second).String()}, 95 {"Memory obtained", units.ByteSize(s.Sys).String()}, 96 {"Number of goroutines", fmt.Sprintf("%d", s.NumGoroutine)}, 97 {"Heap allocated", units.ByteSize(s.Alloc).String()}, 98 {"Live objects", fmt.Sprintf("%d", s.LiveObjects)}, 99 {"Heap allocated total", units.ByteSize(s.TotalAlloc).String()}, 100 {"Heap allocate count", fmt.Sprintf("%d", s.Mallocs)}, 101 {"Heap free count", fmt.Sprintf("%d", s.Frees)}, 102 {"Number of GC", fmt.Sprintf("%d", s.NumGC)}, 103 {"Time of GC pause", (time.Duration(s.PauseTotalNs) * time.Nanosecond).String()}, 104 } 105 sb := new(strings.Builder) 106 writeRow(sb, 0, 0, 107 []string{"Item", "Value"}, 108 formats, 109 ) 110 for i, r := range rows { 111 writeRow(sb, 0, i+1, r, formats) 112 } 113 os.Stdout.WriteString(sb.String()) 114 } 115 116 func getStats(patterns []string, regexp, reset, jsonOutput bool) { 117 conn, ctx, close := dialAPIServer() 118 defer close() 119 120 client := statsService.NewStatsServiceClient(conn) 121 r := &statsService.QueryStatsRequest{ 122 Patterns: patterns, 123 Regexp: regexp, 124 Reset_: reset, 125 } 126 resp, err := client.QueryStats(ctx, r) 127 if err != nil { 128 base.Fatalf("failed to query stats: %s", err) 129 } 130 if jsonOutput { 131 showJSONResponse(resp) 132 return 133 } 134 sort.Slice(resp.Stat, func(i, j int) bool { 135 return resp.Stat[i].Name < resp.Stat[j].Name 136 }) 137 showStats(resp.Stat) 138 } 139 140 func showStats(stats []*statsService.Stat) { 141 if len(stats) == 0 { 142 return 143 } 144 formats := []string{"%-12s", "%s"} 145 sum := int64(0) 146 sb := new(strings.Builder) 147 idx := 0 148 writeRow(sb, 0, 0, 149 []string{"Value", "Name"}, 150 formats, 151 ) 152 for _, stat := range stats { 153 // if stat.Value == 0 { 154 // continue 155 // } 156 idx++ 157 sum += stat.Value 158 writeRow( 159 sb, 0, idx, 160 []string{units.ByteSize(stat.Value).String(), stat.Name}, 161 formats, 162 ) 163 } 164 sb.WriteString( 165 fmt.Sprintf("\nTotal: %s\n", units.ByteSize(sum)), 166 ) 167 os.Stdout.WriteString(sb.String()) 168 }