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  }