vitess.io/vitess@v0.16.2/go/vt/vttablet/tabletserver/querylogz_test.go (about) 1 /* 2 Copyright 2019 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 "io" 21 "net/http" 22 "net/http/httptest" 23 "regexp" 24 "strings" 25 "testing" 26 "time" 27 28 "context" 29 30 "vitess.io/vitess/go/streamlog" 31 "vitess.io/vitess/go/vt/callerid" 32 "vitess.io/vitess/go/vt/vttablet/tabletserver/planbuilder" 33 "vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv" 34 ) 35 36 func TestQuerylogzHandlerInvalidLogStats(t *testing.T) { 37 req, _ := http.NewRequest("GET", "/querylogz?timeout=10&limit=1", nil) 38 response := httptest.NewRecorder() 39 ch := make(chan any, 1) 40 ch <- "test msg" 41 querylogzHandler(ch, response, req) 42 close(ch) 43 if !strings.Contains(response.Body.String(), "error") { 44 t.Fatalf("should show an error page for an non LogStats") 45 } 46 } 47 48 func TestQuerylogzHandler(t *testing.T) { 49 req, _ := http.NewRequest("GET", "/querylogz?timeout=10&limit=1", nil) 50 logStats := tabletenv.NewLogStats(context.Background(), "Execute") 51 logStats.PlanType = planbuilder.PlanSelect.String() 52 logStats.OriginalSQL = "select name from test_table limit 1000" 53 logStats.RowsAffected = 1000 54 logStats.NumberOfQueries = 1 55 logStats.StartTime, _ = time.Parse("Jan 2 15:04:05", "Nov 29 13:33:09") 56 logStats.MysqlResponseTime = 1 * time.Millisecond 57 logStats.WaitingForConnection = 10 * time.Nanosecond 58 logStats.TransactionID = 131 59 logStats.ReservedID = 313 60 logStats.Ctx = callerid.NewContext( 61 context.Background(), 62 callerid.NewEffectiveCallerID("effective-caller", "component", "subcomponent"), 63 callerid.NewImmediateCallerID("immediate-caller"), 64 ) 65 66 // fast query 67 fastQueryPattern := []string{ 68 `<tr class="low">`, 69 `<td>Execute</td>`, 70 `<td></td>`, 71 `<td>effective-caller</td>`, 72 `<td>immediate-caller</td>`, 73 `<td>Nov 29 13:33:09.000000</td>`, 74 `<td>Nov 29 13:33:09.001000</td>`, 75 `<td>0.001</td>`, 76 `<td>0.001</td>`, 77 `<td>1e-08</td>`, 78 `<td>Select</td>`, 79 `<td>select name from test_table limit 1000</td>`, 80 `<td>1</td>`, 81 `<td>none</td>`, 82 `<td>1000</td>`, 83 `<td>0</td>`, 84 `<td>131</td>`, 85 `<td>313</td>`, 86 `<td></td>`, 87 } 88 logStats.EndTime = logStats.StartTime.Add(1 * time.Millisecond) 89 response := httptest.NewRecorder() 90 ch := make(chan any, 1) 91 ch <- logStats 92 querylogzHandler(ch, response, req) 93 close(ch) 94 body, _ := io.ReadAll(response.Body) 95 checkQuerylogzHasStats(t, fastQueryPattern, logStats, body) 96 97 // medium query 98 mediumQueryPattern := []string{ 99 `<tr class="medium">`, 100 `<td>Execute</td>`, 101 `<td></td>`, 102 `<td>effective-caller</td>`, 103 `<td>immediate-caller</td>`, 104 `<td>Nov 29 13:33:09.000000</td>`, 105 `<td>Nov 29 13:33:09.020000</td>`, 106 `<td>0.02</td>`, 107 `<td>0.001</td>`, 108 `<td>1e-08</td>`, 109 `<td>Select</td>`, 110 `<td>select name from test_table limit 1000</td>`, 111 `<td>1</td>`, 112 `<td>none</td>`, 113 `<td>1000</td>`, 114 `<td>0</td>`, 115 `<td>131</td>`, 116 `<td>313</td>`, 117 `<td></td>`, 118 } 119 logStats.EndTime = logStats.StartTime.Add(20 * time.Millisecond) 120 response = httptest.NewRecorder() 121 ch = make(chan any, 1) 122 ch <- logStats 123 querylogzHandler(ch, response, req) 124 close(ch) 125 body, _ = io.ReadAll(response.Body) 126 checkQuerylogzHasStats(t, mediumQueryPattern, logStats, body) 127 128 // slow query 129 slowQueryPattern := []string{ 130 `<tr class="high">`, 131 `<td>Execute</td>`, 132 `<td></td>`, 133 `<td>effective-caller</td>`, 134 `<td>immediate-caller</td>`, 135 `<td>Nov 29 13:33:09.000000</td>`, 136 `<td>Nov 29 13:33:09.500000</td>`, 137 `<td>0.5</td>`, 138 `<td>0.001</td>`, 139 `<td>1e-08</td>`, 140 `<td>Select</td>`, 141 `<td>select name from test_table limit 1000</td>`, 142 `<td>1</td>`, 143 `<td>none</td>`, 144 `<td>1000</td>`, 145 `<td>0</td>`, 146 `<td>131</td>`, 147 `<td>313</td>`, 148 `<td></td>`, 149 } 150 logStats.EndTime = logStats.StartTime.Add(500 * time.Millisecond) 151 ch = make(chan any, 1) 152 ch <- logStats 153 querylogzHandler(ch, response, req) 154 close(ch) 155 body, _ = io.ReadAll(response.Body) 156 checkQuerylogzHasStats(t, slowQueryPattern, logStats, body) 157 158 // ensure querylogz is not affected by the filter tag 159 streamlog.SetQueryLogFilterTag("XXX_SKIP_ME") 160 defer func() { streamlog.SetQueryLogFilterTag("") }() 161 ch = make(chan any, 1) 162 ch <- logStats 163 querylogzHandler(ch, response, req) 164 close(ch) 165 body, _ = io.ReadAll(response.Body) 166 checkQuerylogzHasStats(t, slowQueryPattern, logStats, body) 167 } 168 169 func checkQuerylogzHasStats(t *testing.T, pattern []string, logStats *tabletenv.LogStats, page []byte) { 170 t.Helper() 171 matcher := regexp.MustCompile(strings.Join(pattern, `\s*`)) 172 if !matcher.Match(page) { 173 t.Fatalf("querylogz page does not contain stats: %v, pattern: %v, page: %s", logStats, pattern, string(page)) 174 } 175 }