vitess.io/vitess@v0.16.2/go/vt/vttablet/tabletserver/debugenv.go (about) 1 /* 2 Copyright 2020 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package tabletserver 18 19 import ( 20 "encoding/json" 21 "fmt" 22 "html" 23 "net/http" 24 "strconv" 25 "text/template" 26 "time" 27 28 "vitess.io/vitess/go/acl" 29 "vitess.io/vitess/go/vt/log" 30 ) 31 32 var ( 33 debugEnvHeader = []byte(` 34 <thead><tr> 35 <th>Variable Name</th> 36 <th>Value</th> 37 <th>Action</th> 38 </tr></thead> 39 `) 40 debugEnvRow = template.Must(template.New("debugenv").Parse(` 41 <tr><form method="POST"> 42 <td>{{.Name}}</td> 43 <td> 44 <input type="hidden" name="varname" value="{{.Name}}"></input> 45 <input type="text" name="value" value="{{.Value}}"></input> 46 </td> 47 <td><input type="submit" name="Action" value="Modify"></input></td> 48 </form></tr> 49 `)) 50 ) 51 52 type envValue struct { 53 Name string 54 Value string 55 } 56 57 // this cannot be an anonymous function within debugEnvHandler because those kinds 58 // of functions cannot (currently) have type params. 59 func addVar[T any](vars []envValue, name string, f func() T) []envValue { 60 return append(vars, envValue{ 61 Name: name, 62 Value: fmt.Sprintf("%v", f()), 63 }) 64 } 65 66 func debugEnvHandler(tsv *TabletServer, w http.ResponseWriter, r *http.Request) { 67 if err := acl.CheckAccessHTTP(r, acl.ADMIN); err != nil { 68 acl.SendError(w, err) 69 return 70 } 71 72 var msg string 73 if r.Method == "POST" { 74 varname := r.FormValue("varname") 75 value := r.FormValue("value") 76 setIntVal := func(f func(int)) { 77 ival, err := strconv.Atoi(value) 78 if err != nil { 79 msg = fmt.Sprintf("Failed setting value for %v: %v", varname, err) 80 return 81 } 82 f(ival) 83 msg = fmt.Sprintf("Setting %v to: %v", varname, value) 84 } 85 setInt64Val := func(f func(int64)) { 86 ival, err := strconv.ParseInt(value, 10, 64) 87 if err != nil { 88 msg = fmt.Sprintf("Failed setting value for %v: %v", varname, err) 89 return 90 } 91 f(ival) 92 msg = fmt.Sprintf("Setting %v to: %v", varname, value) 93 } 94 setDurationVal := func(f func(time.Duration)) { 95 durationVal, err := time.ParseDuration(value) 96 if err != nil { 97 msg = fmt.Sprintf("Failed setting value for %v: %v", varname, err) 98 return 99 } 100 f(durationVal) 101 msg = fmt.Sprintf("Setting %v to: %v", varname, value) 102 } 103 setFloat64Val := func(f func(float64)) { 104 fval, err := strconv.ParseFloat(value, 64) 105 if err != nil { 106 msg = fmt.Sprintf("Failed setting value for %v: %v", varname, err) 107 return 108 } 109 f(fval) 110 msg = fmt.Sprintf("Setting %v to: %v", varname, value) 111 } 112 switch varname { 113 case "PoolSize": 114 setIntVal(tsv.SetPoolSize) 115 case "StreamPoolSize": 116 setIntVal(tsv.SetStreamPoolSize) 117 case "TxPoolSize": 118 setIntVal(tsv.SetTxPoolSize) 119 case "QueryCacheCapacity": 120 setIntVal(tsv.SetQueryPlanCacheCap) 121 case "MaxResultSize": 122 setIntVal(tsv.SetMaxResultSize) 123 case "WarnResultSize": 124 setIntVal(tsv.SetWarnResultSize) 125 case "RowStreamerMaxInnoDBTrxHistLen": 126 setInt64Val(func(val int64) { tsv.Config().RowStreamer.MaxInnoDBTrxHistLen = val }) 127 case "RowStreamerMaxMySQLReplLagSecs": 128 setInt64Val(func(val int64) { tsv.Config().RowStreamer.MaxMySQLReplLagSecs = val }) 129 case "UnhealthyThreshold": 130 setDurationVal(tsv.Config().Healthcheck.UnhealthyThresholdSeconds.Set) 131 setDurationVal(tsv.hs.SetUnhealthyThreshold) 132 setDurationVal(tsv.sm.SetUnhealthyThreshold) 133 case "ThrottleMetricThreshold": 134 setFloat64Val(tsv.SetThrottleMetricThreshold) 135 case "Consolidator": 136 tsv.SetConsolidatorMode(value) 137 msg = fmt.Sprintf("Setting %v to: %v", varname, value) 138 } 139 } 140 141 var vars []envValue 142 vars = addVar(vars, "PoolSize", tsv.PoolSize) 143 vars = addVar(vars, "StreamPoolSize", tsv.StreamPoolSize) 144 vars = addVar(vars, "TxPoolSize", tsv.TxPoolSize) 145 vars = addVar(vars, "QueryCacheCapacity", tsv.QueryPlanCacheCap) 146 vars = addVar(vars, "MaxResultSize", tsv.MaxResultSize) 147 vars = addVar(vars, "WarnResultSize", tsv.WarnResultSize) 148 vars = addVar(vars, "RowStreamerMaxInnoDBTrxHistLen", func() int64 { return tsv.Config().RowStreamer.MaxInnoDBTrxHistLen }) 149 vars = addVar(vars, "RowStreamerMaxMySQLReplLagSecs", func() int64 { return tsv.Config().RowStreamer.MaxMySQLReplLagSecs }) 150 vars = addVar(vars, "UnhealthyThreshold", tsv.Config().Healthcheck.UnhealthyThresholdSeconds.Get) 151 vars = addVar(vars, "ThrottleMetricThreshold", tsv.ThrottleMetricThreshold) 152 vars = append(vars, envValue{ 153 Name: "Consolidator", 154 Value: tsv.ConsolidatorMode(), 155 }) 156 157 format := r.FormValue("format") 158 if format == "json" { 159 mvars := make(map[string]string) 160 for _, v := range vars { 161 mvars[v.Name] = v.Value 162 } 163 w.Header().Set("Content-Type", "application/json") 164 _ = json.NewEncoder(w).Encode(mvars) 165 return 166 } 167 168 // gridTable is reused from twopcz.go. 169 w.Write(gridTable) 170 w.Write([]byte("<h3>Internal Variables</h3>\n")) 171 if msg != "" { 172 fmt.Fprintf(w, "<b>%s</b><br /><br />\n", html.EscapeString(msg)) 173 } 174 w.Write(startTable) 175 w.Write(debugEnvHeader) 176 for _, v := range vars { 177 if err := debugEnvRow.Execute(w, v); err != nil { 178 log.Errorf("debugenv: couldn't execute template: %v", err) 179 } 180 } 181 w.Write(endTable) 182 }