Skip to content

Commit 8901696

Browse files
committed
Merge remote-tracking branch 'upstream/main' into cluster-watch-range
Signed-off-by: Manan Gupta <manan@planetscale.com>
2 parents 22446ab + d1aa2f4 commit 8901696

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+564
-521
lines changed

changelog/22.0/22.0.0/summary.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
- **[Update default MySQL version to 8.0.40](#mysql-8-0-40)**
1717
- **[Update lite images to Debian Bookworm](#debian-bookworm)**
1818
- **[KeyRanges in `--clusters_to_watch` in VTOrc](#key-range-vtorc)**
19+
- **[Support for Filtering Query logs on Error](#query-logs)**
1920
- **[Minor Changes](#minor-changes)**
2021
- **[VTTablet Flags](#flags-vttablet)**
2122
- **[Topology read concurrency behaviour changes](#topo-read-concurrency-changes)**
@@ -26,7 +27,7 @@
2627

2728
These are the RPC changes made in this release -
2829

29-
1. `GetTransactionInfo` RPC has been added to both `VtctldServer`, and `TabletManagerClient` interface. These RPCs are used to fecilitate the users in reading the state of an unresolved distributed transaction. This can be useful in debugging what went wrong and how to fix the problem.
30+
1. `GetTransactionInfo` RPC has been added to both `VtctldServer`, and `TabletManagerClient` interface. These RPCs are used to facilitate the users in reading the state of an unresolved distributed transaction. This can be useful in debugging what went wrong and how to fix the problem.
3031

3132
### <a id="deprecations-and-deletions"/>Deprecations and Deletions</a>
3233

@@ -138,6 +139,10 @@ VTOrc now supports specifying KeyRanges in the `--clusters_to_watch` flag. This
138139
For example, if a VTOrc is configured to watch `ks/-80`, then it would watch all the shards that fall under the KeyRange `-80`. If a reshard is run and, `-80` is split into new shards `-40`, and `40-80`, the VTOrc instance will automatically start watching the new shard without needing a restart.
139140
The users can still continue to specify exact key ranges too, and the new feature is backward compatible.
140141

142+
### <a id="query-logs"/>Support for Filtering Query logs on Error</a>
143+
144+
The `querylog-mode` setting can be configured to `error` to log only queries that result in errors. This option is supported in both VTGate and VTTablet.
145+
141146
## <a id="minor-changes"/>Minor Changes</a>
142147

143148
#### <a id="flags-vttablet"/>VTTablet Flags</a>

go/flags/endtoend/vtcombo.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ Flags:
272272
--querylog-buffer-size int Maximum number of buffered query logs before throttling log output (default 10)
273273
--querylog-filter-tag string string that must be present in the query for it to be logged; if using a value as the tag, you need to disable query normalization
274274
--querylog-format string format for query logs ("text" or "json") (default "text")
275+
--querylog-mode string Mode for logging queries. "error" will only log queries that return an error. Otherwise all queries will be logged. (default "all")
275276
--querylog-row-threshold uint Number of rows a query has to return or affect before being logged; not useful for streaming queries. 0 means all queries will be logged.
276277
--querylog-sample-rate float Sample rate for logging queries. Value must be between 0.0 (no logging) and 1.0 (all queries)
277278
--queryserver-config-acl-exempt-acl string an acl that exempt from table acl checking (this acl is free to access any vitess tables).

go/flags/endtoend/vtgate.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ Flags:
177177
--querylog-buffer-size int Maximum number of buffered query logs before throttling log output (default 10)
178178
--querylog-filter-tag string string that must be present in the query for it to be logged; if using a value as the tag, you need to disable query normalization
179179
--querylog-format string format for query logs ("text" or "json") (default "text")
180+
--querylog-mode string Mode for logging queries. "error" will only log queries that return an error. Otherwise all queries will be logged. (default "all")
180181
--querylog-row-threshold uint Number of rows a query has to return or affect before being logged; not useful for streaming queries. 0 means all queries will be logged.
181182
--querylog-sample-rate float Sample rate for logging queries. Value must be between 0.0 (no logging) and 1.0 (all queries)
182183
--redact-debug-ui-queries redact full queries and bind variables from debug UI

go/flags/endtoend/vttablet.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ Flags:
264264
--query-log-stream-handler string URL handler for streaming queries log (default "/debug/querylog")
265265
--querylog-filter-tag string string that must be present in the query for it to be logged; if using a value as the tag, you need to disable query normalization
266266
--querylog-format string format for query logs ("text" or "json") (default "text")
267+
--querylog-mode string Mode for logging queries. "error" will only log queries that return an error. Otherwise all queries will be logged. (default "all")
267268
--querylog-row-threshold uint Number of rows a query has to return or affect before being logged; not useful for streaming queries. 0 means all queries will be logged.
268269
--querylog-sample-rate float Sample rate for logging queries. Value must be between 0.0 (no logging) and 1.0 (all queries)
269270
--queryserver-config-acl-exempt-acl string an acl that exempt from table acl checking (this acl is free to access any vitess tables).

go/mysql/binlog_dump.go

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -72,21 +72,19 @@ func (c *Conn) parseComBinlogDumpGTID(data []byte) (logFile string, logPos uint6
7272
return logFile, logPos, position, readPacketErr
7373
}
7474

75-
if flags2&BinlogDumpNonBlock != 0 {
76-
return logFile, logPos, position, io.EOF
75+
dataSize, pos, ok := readUint32(data, pos)
76+
if !ok {
77+
return logFile, logPos, position, readPacketErr
7778
}
78-
if flags2&BinlogThroughGTID != 0 {
79-
dataSize, pos, ok := readUint32(data, pos)
80-
if !ok {
81-
return logFile, logPos, position, readPacketErr
82-
}
83-
if gtid := string(data[pos : pos+int(dataSize)]); gtid != "" {
84-
position, err = replication.DecodePosition(gtid)
85-
if err != nil {
86-
return logFile, logPos, position, err
87-
}
79+
if gtid := string(data[pos : pos+int(dataSize)]); gtid != "" {
80+
position, err = replication.DecodePosition(gtid)
81+
if err != nil {
82+
return logFile, logPos, position, err
8883
}
8984
}
85+
if flags2&BinlogDumpNonBlock != 0 {
86+
return logFile, logPos, position, io.EOF
87+
}
9088

9189
return logFile, logPos, position, nil
9290
}

go/mysql/flavor_mysql.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,14 @@ func (mysqlFlavor) sendBinlogDumpCommand(c *Conn, serverID uint32, binlogFilenam
219219

220220
// Build the command.
221221
sidBlock := gtidSet.SIDBlock()
222-
return c.WriteComBinlogDumpGTID(serverID, binlogFilename, 4, 0, sidBlock)
222+
var flags2 uint16
223+
if binlogFilename != "" {
224+
flags2 |= BinlogThroughPosition
225+
}
226+
if len(sidBlock) > 0 {
227+
flags2 |= BinlogThroughGTID
228+
}
229+
return c.WriteComBinlogDumpGTID(serverID, binlogFilename, 4, flags2, sidBlock)
223230
}
224231

225232
// setReplicationPositionCommands is part of the Flavor interface.

go/mysql/replication/mysql56_gtid_set_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -854,3 +854,18 @@ func TestMysql56GTIDSet_RemoveUUID(t *testing.T) {
854854
})
855855
}
856856
}
857+
858+
func TestSIDs(t *testing.T) {
859+
var set Mysql56GTIDSet // nil
860+
sids := set.SIDs()
861+
assert.NotNil(t, sids)
862+
assert.Empty(t, sids)
863+
864+
gtid := "8bc65cca-3fe4-11ed-bbfb-091034d48b3e:1:4-24"
865+
gtidSet, err := ParseMysql56GTIDSet(gtid)
866+
require.NoError(t, err)
867+
sids = gtidSet.SIDs()
868+
assert.NotNil(t, sids)
869+
require.Len(t, sids, 1)
870+
assert.Equal(t, "8bc65cca-3fe4-11ed-bbfb-091034d48b3e", sids[0].String())
871+
}

go/mysql/replication_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,9 @@ func TestComBinlogDumpGTID(t *testing.T) {
9090

9191
t.Run("WriteComBinlogDumpGTID", func(t *testing.T) {
9292
// Write ComBinlogDumpGTID packet, read it, compare.
93-
err := cConn.WriteComBinlogDumpGTID(0x01020304, "moofarm", 0x05060708090a0b0c, 0x0d0e, []byte{0xfa, 0xfb})
93+
var flags uint16 = 0x0d0e
94+
assert.Equal(t, flags, flags|BinlogThroughGTID)
95+
err := cConn.WriteComBinlogDumpGTID(0x01020304, "moofarm", 0x05060708090a0b0c, flags, []byte{0xfa, 0xfb})
9496
assert.NoError(t, err)
9597
data, err := sConn.ReadPacket()
9698
require.NoError(t, err, "sConn.ReadPacket - ComBinlogDumpGTID failed: %v", err)

go/streamlog/streamlog.go

Lines changed: 48 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ package streamlog
2020
import (
2121
"fmt"
2222
"io"
23-
rand "math/rand/v2"
23+
"math/rand/v2"
2424
"net/http"
2525
"net/url"
2626
"os"
@@ -47,40 +47,42 @@ var (
4747
[]string{"Log", "Subscriber"})
4848
)
4949

50-
var (
51-
redactDebugUIQueries bool
52-
queryLogFilterTag string
53-
queryLogRowThreshold uint64
54-
queryLogFormat = "text"
55-
queryLogSampleRate float64
56-
)
50+
const (
51+
// QueryLogFormatText is the format specifier for text querylog output
52+
QueryLogFormatText = "text"
5753

58-
func GetRedactDebugUIQueries() bool {
59-
return redactDebugUIQueries
60-
}
54+
// QueryLogFormatJSON is the format specifier for json querylog output
55+
QueryLogFormatJSON = "json"
6156

62-
func SetRedactDebugUIQueries(newRedactDebugUIQueries bool) {
63-
redactDebugUIQueries = newRedactDebugUIQueries
64-
}
57+
// QueryLogModeAll is the mode specifier for logging all queries
58+
QueryLogModeAll = "all"
6559

66-
func SetQueryLogFilterTag(newQueryLogFilterTag string) {
67-
queryLogFilterTag = newQueryLogFilterTag
68-
}
60+
// QueryLogModeError is the mode specifier for logging only queries that return an error
61+
QueryLogModeError = "error"
62+
)
6963

70-
func SetQueryLogRowThreshold(newQueryLogRowThreshold uint64) {
71-
queryLogRowThreshold = newQueryLogRowThreshold
64+
type QueryLogConfig struct {
65+
RedactDebugUIQueries bool
66+
FilterTag string
67+
Format string
68+
Mode string
69+
RowThreshold uint64
70+
sampleRate float64
7271
}
7372

74-
func SetQueryLogSampleRate(sampleRate float64) {
75-
queryLogSampleRate = sampleRate
73+
var queryLogConfigInstance = QueryLogConfig{
74+
Format: QueryLogFormatText,
75+
Mode: QueryLogModeAll,
7676
}
7777

78-
func GetQueryLogFormat() string {
79-
return queryLogFormat
78+
func GetQueryLogConfig() QueryLogConfig {
79+
return queryLogConfigInstance
8080
}
8181

82-
func SetQueryLogFormat(newQueryLogFormat string) {
83-
queryLogFormat = newQueryLogFormat
82+
func NewQueryLogConfigForTest() QueryLogConfig {
83+
return QueryLogConfig{
84+
Format: QueryLogFormatText,
85+
}
8486
}
8587

8688
func init() {
@@ -91,28 +93,23 @@ func init() {
9193

9294
func registerStreamLogFlags(fs *pflag.FlagSet) {
9395
// RedactDebugUIQueries controls whether full queries and bind variables are suppressed from debug UIs.
94-
fs.BoolVar(&redactDebugUIQueries, "redact-debug-ui-queries", redactDebugUIQueries, "redact full queries and bind variables from debug UI")
96+
fs.BoolVar(&queryLogConfigInstance.RedactDebugUIQueries, "redact-debug-ui-queries", queryLogConfigInstance.RedactDebugUIQueries, "redact full queries and bind variables from debug UI")
9597

9698
// QueryLogFormat controls the format of the query log (either text or json)
97-
fs.StringVar(&queryLogFormat, "querylog-format", queryLogFormat, "format for query logs (\"text\" or \"json\")")
99+
fs.StringVar(&queryLogConfigInstance.Format, "querylog-format", queryLogConfigInstance.Format, "format for query logs (\"text\" or \"json\")")
98100

99101
// QueryLogFilterTag contains an optional string that must be present in the query for it to be logged
100-
fs.StringVar(&queryLogFilterTag, "querylog-filter-tag", queryLogFilterTag, "string that must be present in the query for it to be logged; if using a value as the tag, you need to disable query normalization")
102+
fs.StringVar(&queryLogConfigInstance.FilterTag, "querylog-filter-tag", queryLogConfigInstance.FilterTag, "string that must be present in the query for it to be logged; if using a value as the tag, you need to disable query normalization")
101103

102104
// QueryLogRowThreshold only log queries returning or affecting this many rows
103-
fs.Uint64Var(&queryLogRowThreshold, "querylog-row-threshold", queryLogRowThreshold, "Number of rows a query has to return or affect before being logged; not useful for streaming queries. 0 means all queries will be logged.")
105+
fs.Uint64Var(&queryLogConfigInstance.RowThreshold, "querylog-row-threshold", queryLogConfigInstance.RowThreshold, "Number of rows a query has to return or affect before being logged; not useful for streaming queries. 0 means all queries will be logged.")
104106

105107
// QueryLogSampleRate causes a sample of queries to be logged
106-
fs.Float64Var(&queryLogSampleRate, "querylog-sample-rate", queryLogSampleRate, "Sample rate for logging queries. Value must be between 0.0 (no logging) and 1.0 (all queries)")
107-
}
108-
109-
const (
110-
// QueryLogFormatText is the format specifier for text querylog output
111-
QueryLogFormatText = "text"
108+
fs.Float64Var(&queryLogConfigInstance.sampleRate, "querylog-sample-rate", queryLogConfigInstance.sampleRate, "Sample rate for logging queries. Value must be between 0.0 (no logging) and 1.0 (all queries)")
112109

113-
// QueryLogFormatJSON is the format specifier for json querylog output
114-
QueryLogFormatJSON = "json"
115-
)
110+
// QueryLogMode controls the mode for logging queries (all or error)
111+
fs.StringVar(&queryLogConfigInstance.Mode, "querylog-mode", queryLogConfigInstance.Mode, `Mode for logging queries. "error" will only log queries that return an error. Otherwise all queries will be logged.`)
112+
}
116113

117114
// StreamLogger is a non-blocking broadcaster of messages.
118115
// Subscribers can use channels or HTTP.
@@ -257,27 +254,30 @@ func GetFormatter[T any](logger *StreamLogger[T]) LogFormatter {
257254
}
258255
}
259256

260-
// shouldSampleQuery returns true if a query should be sampled based on queryLogSampleRate
261-
func shouldSampleQuery() bool {
262-
if queryLogSampleRate <= 0 {
257+
// shouldSampleQuery returns true if a query should be sampled based on sampleRate
258+
func (qlConfig QueryLogConfig) shouldSampleQuery() bool {
259+
if qlConfig.sampleRate <= 0 {
263260
return false
264-
} else if queryLogSampleRate >= 1 {
261+
} else if qlConfig.sampleRate >= 1 {
265262
return true
266263
}
267-
return rand.Float64() <= queryLogSampleRate
264+
return rand.Float64() <= qlConfig.sampleRate
268265
}
269266

270267
// ShouldEmitLog returns whether the log with the given SQL query
271268
// should be emitted or filtered
272-
func ShouldEmitLog(sql string, rowsAffected, rowsReturned uint64) bool {
273-
if shouldSampleQuery() {
269+
func (qlConfig QueryLogConfig) ShouldEmitLog(sql string, rowsAffected, rowsReturned uint64, hasError bool) bool {
270+
if qlConfig.shouldSampleQuery() {
274271
return true
275272
}
276-
if queryLogRowThreshold > max(rowsAffected, rowsReturned) && queryLogFilterTag == "" {
273+
if qlConfig.RowThreshold > max(rowsAffected, rowsReturned) && qlConfig.FilterTag == "" {
277274
return false
278275
}
279-
if queryLogFilterTag != "" {
280-
return strings.Contains(sql, queryLogFilterTag)
276+
if qlConfig.FilterTag != "" {
277+
return strings.Contains(sql, qlConfig.FilterTag)
278+
}
279+
if qlConfig.Mode == QueryLogModeError {
280+
return hasError
281281
}
282282
return true
283283
}

go/streamlog/streamlog_test.go

Lines changed: 29 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -266,40 +266,29 @@ func TestFile(t *testing.T) {
266266
}
267267

268268
func TestShouldSampleQuery(t *testing.T) {
269-
queryLogSampleRate = -1
270-
assert.False(t, shouldSampleQuery())
269+
qlConfig := QueryLogConfig{sampleRate: -1}
270+
assert.False(t, qlConfig.shouldSampleQuery())
271271

272-
queryLogSampleRate = 0
273-
assert.False(t, shouldSampleQuery())
272+
qlConfig.sampleRate = 0
273+
assert.False(t, qlConfig.shouldSampleQuery())
274274

275-
// for test coverage, can't test a random result
276-
queryLogSampleRate = 0.5
277-
shouldSampleQuery()
275+
qlConfig.sampleRate = 1.0
276+
assert.True(t, qlConfig.shouldSampleQuery())
278277

279-
queryLogSampleRate = 1.0
280-
assert.True(t, shouldSampleQuery())
281-
282-
queryLogSampleRate = 100.0
283-
assert.True(t, shouldSampleQuery())
278+
qlConfig.sampleRate = 100.0
279+
assert.True(t, qlConfig.shouldSampleQuery())
284280
}
285281

286282
func TestShouldEmitLog(t *testing.T) {
287-
origQueryLogFilterTag := queryLogFilterTag
288-
origQueryLogRowThreshold := queryLogRowThreshold
289-
origQueryLogSampleRate := queryLogSampleRate
290-
defer func() {
291-
SetQueryLogFilterTag(origQueryLogFilterTag)
292-
SetQueryLogRowThreshold(origQueryLogRowThreshold)
293-
SetQueryLogSampleRate(origQueryLogSampleRate)
294-
}()
295-
296283
tests := []struct {
297284
sql string
298285
qLogFilterTag string
299286
qLogRowThreshold uint64
300287
qLogSampleRate float64
288+
qLogMode string
301289
rowsAffected uint64
302290
rowsReturned uint64
291+
errored bool
303292
ok bool
304293
}{
305294
{
@@ -356,43 +345,33 @@ func TestShouldEmitLog(t *testing.T) {
356345
rowsReturned: 17,
357346
ok: true,
358347
},
348+
{
349+
sql: "log only error - no error",
350+
qLogMode: "error",
351+
errored: false,
352+
ok: false,
353+
},
354+
{
355+
sql: "log only error - errored",
356+
qLogMode: "error",
357+
errored: true,
358+
ok: true,
359+
},
359360
}
360361

361362
for _, tt := range tests {
362363
t.Run(tt.sql, func(t *testing.T) {
363-
SetQueryLogFilterTag(tt.qLogFilterTag)
364-
SetQueryLogRowThreshold(tt.qLogRowThreshold)
365-
SetQueryLogSampleRate(tt.qLogSampleRate)
366-
367-
require.Equal(t, tt.ok, ShouldEmitLog(tt.sql, tt.rowsAffected, tt.rowsReturned))
364+
qlConfig := QueryLogConfig{
365+
FilterTag: tt.qLogFilterTag,
366+
RowThreshold: tt.qLogRowThreshold,
367+
sampleRate: tt.qLogSampleRate,
368+
Mode: tt.qLogMode,
369+
}
370+
require.Equal(t, tt.ok, qlConfig.ShouldEmitLog(tt.sql, tt.rowsAffected, tt.rowsReturned, tt.errored))
368371
})
369372
}
370373
}
371374

372-
func BenchmarkShouldEmitLog(b *testing.B) {
373-
b.Run("default", func(b *testing.B) {
374-
SetQueryLogSampleRate(0.0)
375-
for i := 0; i < b.N; i++ {
376-
ShouldEmitLog("select * from test where user='someone'", 0, 123)
377-
}
378-
})
379-
b.Run("filter_tag", func(b *testing.B) {
380-
SetQueryLogSampleRate(0.0)
381-
SetQueryLogFilterTag("LOG_QUERY")
382-
defer SetQueryLogFilterTag("")
383-
for i := 0; i < b.N; i++ {
384-
ShouldEmitLog("select /* LOG_QUERY=1 */ * from test where user='someone'", 0, 123)
385-
}
386-
})
387-
b.Run("50%_sample_rate", func(b *testing.B) {
388-
SetQueryLogSampleRate(0.5)
389-
defer SetQueryLogSampleRate(0.0)
390-
for i := 0; i < b.N; i++ {
391-
ShouldEmitLog("select * from test where user='someone'", 0, 123)
392-
}
393-
})
394-
}
395-
396375
func TestGetFormatter(t *testing.T) {
397376
tests := []struct {
398377
name string

0 commit comments

Comments
 (0)