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