gitlab.com/Raven-IO/raven-delve@v1.22.4/service/api/command.go (about) 1 package api 2 3 import ( 4 "errors" 5 "fmt" 6 "strconv" 7 "strings" 8 ) 9 10 type PrintGoroutinesFlags uint8 11 12 const ( 13 PrintGoroutinesStack PrintGoroutinesFlags = 1 << iota 14 PrintGoroutinesLabels 15 PrintGoroutinesExec 16 ) 17 18 type FormatGoroutineLoc int 19 20 const ( 21 FglRuntimeCurrent = FormatGoroutineLoc(iota) 22 FglUserCurrent 23 FglGo 24 FglStart 25 ) 26 27 const ( 28 maxGroupMembers = 5 29 maxGoroutineGroups = 50 30 ) 31 32 // The number of goroutines we're going to request on each RPC call 33 const goroutineBatchSize = 10000 34 35 func ParseGoroutineArgs(argstr string) ([]ListGoroutinesFilter, GoroutineGroupingOptions, FormatGoroutineLoc, PrintGoroutinesFlags, int, int, string, error) { 36 args := strings.Split(argstr, " ") 37 var filters []ListGoroutinesFilter 38 var group GoroutineGroupingOptions 39 var fgl = FglUserCurrent 40 var flags PrintGoroutinesFlags 41 var depth = 10 42 var batchSize = goroutineBatchSize 43 var cmd string 44 45 group.MaxGroupMembers = maxGroupMembers 46 group.MaxGroups = maxGoroutineGroups 47 48 for i := 0; i < len(args); i++ { 49 arg := args[i] 50 switch arg { 51 case "-u": 52 fgl = FglUserCurrent 53 case "-r": 54 fgl = FglRuntimeCurrent 55 case "-g": 56 fgl = FglGo 57 case "-s": 58 fgl = FglStart 59 case "-l": 60 flags |= PrintGoroutinesLabels 61 case "-t": 62 flags |= PrintGoroutinesStack 63 // optional depth argument 64 if i+1 < len(args) && len(args[i+1]) > 0 { 65 n, err := strconv.Atoi(args[i+1]) 66 if err == nil { 67 depth = n 68 i++ 69 } 70 } 71 72 case "-w", "-with": 73 filter, err := readGoroutinesFilter(args, &i) 74 if err != nil { 75 return nil, GoroutineGroupingOptions{}, 0, 0, 0, 0, "", fmt.Errorf("wrong argument: '%s'", arg) 76 } 77 filters = append(filters, *filter) 78 79 case "-wo", "-without": 80 filter, err := readGoroutinesFilter(args, &i) 81 if err != nil { 82 return nil, GoroutineGroupingOptions{}, 0, 0, 0, 0, "", fmt.Errorf("wrong argument: '%s'", arg) 83 } 84 filter.Negated = true 85 filters = append(filters, *filter) 86 87 case "-group": 88 var err error 89 group.GroupBy, err = readGoroutinesFilterKind(args, i+1) 90 if err != nil { 91 return nil, GoroutineGroupingOptions{}, 0, 0, 0, 0, "", fmt.Errorf("wrong argument: '%s'", arg) 92 } 93 i++ 94 if group.GroupBy == GoroutineLabel { 95 if i+1 >= len(args) { 96 return nil, GoroutineGroupingOptions{}, 0, 0, 0, 0, "", fmt.Errorf("wrong argument: '%s'", arg) 97 } 98 group.GroupByKey = args[i+1] 99 i++ 100 } 101 batchSize = 0 // grouping only works well if run on all goroutines 102 103 case "-chan": 104 i++ 105 if i >= len(args) { 106 return nil, GoroutineGroupingOptions{}, 0, 0, 0, 0, "", errors.New("not enough arguments after -chan") 107 } 108 filters = append(filters, ListGoroutinesFilter{Kind: GoroutineWaitingOnChannel, Arg: args[i]}) 109 110 case "-exec": 111 flags |= PrintGoroutinesExec 112 cmd = strings.Join(args[i+1:], " ") 113 i = len(args) 114 115 case "": 116 // nothing to do 117 default: 118 return nil, GoroutineGroupingOptions{}, 0, 0, 0, 0, "", fmt.Errorf("wrong argument: '%s'", arg) 119 } 120 } 121 return filters, group, fgl, flags, depth, batchSize, cmd, nil 122 } 123 124 func readGoroutinesFilterKind(args []string, i int) (GoroutineField, error) { 125 if i >= len(args) { 126 return GoroutineFieldNone, fmt.Errorf("%s must be followed by an argument", args[i-1]) 127 } 128 129 switch args[i] { 130 case "curloc": 131 return GoroutineCurrentLoc, nil 132 case "userloc": 133 return GoroutineUserLoc, nil 134 case "goloc": 135 return GoroutineGoLoc, nil 136 case "startloc": 137 return GoroutineStartLoc, nil 138 case "label": 139 return GoroutineLabel, nil 140 case "running": 141 return GoroutineRunning, nil 142 case "user": 143 return GoroutineUser, nil 144 default: 145 return GoroutineFieldNone, fmt.Errorf("unrecognized argument to %s %s", args[i-1], args[i]) 146 } 147 } 148 149 func readGoroutinesFilter(args []string, pi *int) (*ListGoroutinesFilter, error) { 150 r := new(ListGoroutinesFilter) 151 var err error 152 r.Kind, err = readGoroutinesFilterKind(args, *pi+1) 153 if err != nil { 154 return nil, err 155 } 156 *pi++ 157 switch r.Kind { 158 case GoroutineRunning, GoroutineUser: 159 return r, nil 160 } 161 if *pi+1 >= len(args) { 162 return nil, fmt.Errorf("%s %s needs to be followed by an expression", args[*pi-1], args[*pi]) 163 } 164 r.Arg = args[*pi+1] 165 *pi++ 166 167 return r, nil 168 }