Skip to content

Commit 0f3027e

Browse files
Added TODOs and the parser function that populates event.CommentMetadata
1 parent cddb610 commit 0f3027e

File tree

3 files changed

+106
-12
lines changed

3 files changed

+106
-12
lines changed

event.go

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,19 @@ package slowlog
1212
// event is expected to define the query and Query_time metric. Other metrics
1313
// and metadata vary according to MySQL version, distro, and configuration.
1414
type Event struct {
15-
Offset uint64 // byte offset in file at which event starts
16-
Ts string // raw timestamp of event
17-
Admin bool // true if Query is admin command
18-
Query string // SQL query or admin command
19-
User string
20-
Host string
21-
Db string
22-
TimeMetrics map[string]float64 // *_time and *_wait metrics
23-
NumberMetrics map[string]uint64 // most metrics
24-
BoolMetrics map[string]bool // yes/no metrics
25-
RateType string // Percona Server rate limit type
26-
RateLimit uint // Percona Server rate limit value
15+
Offset uint64 // byte offset in file at which event starts
16+
Ts string // raw timestamp of event
17+
Admin bool // true if Query is admin command
18+
Query string // SQL query or admin command
19+
User string
20+
Host string
21+
Db string
22+
TimeMetrics map[string]float64 // *_time and *_wait metrics
23+
NumberMetrics map[string]uint64 // most metrics
24+
BoolMetrics map[string]bool // yes/no metrics
25+
RateType string // Percona Server rate limit type
26+
RateLimit uint // Percona Server rate limit value
27+
CommentMetadata map[string]string
2728
}
2829

2930
// NewEvent returns a new Event with initialized metric maps.

metrics.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ type Metrics struct {
1414
TimeMetrics map[string]*TimeStats `json:",omitempty"`
1515
NumberMetrics map[string]*NumberStats `json:",omitempty"`
1616
BoolMetrics map[string]*BoolStats `json:",omitempty"`
17+
// TODO(Yash): Add another metrics for metadata.
1718
}
1819

1920
// TimeStats are microsecond-based metrics like Query_time and Lock_time.
@@ -26,6 +27,8 @@ type TimeStats struct {
2627
P95 float64 `json:",omitempty"` // 95th percentile
2728
Max float64 `json:",omitempty"`
2829
outlierSum float64
30+
// TODO(Yash) timeTakeToTraceId as map. Move this to Metrics class or create another struct parallel to TImeMetrics, NumberMetrics, BoolMetrics
31+
// traceIdOfMaxSql
2932
}
3033

3134
// NumberStats are integer-based metrics like Rows_sent and Merge_passes.
@@ -72,6 +75,7 @@ func (m *Metrics) AddEvent(e Event, outlier bool) {
7275
stats.Sum += val
7376
}
7477
stats.vals = append(stats.vals, float64(val))
78+
// TODO(Yash): Add traceIdProto to the map defined in TimeMetrics
7579
}
7680

7781
for metric, val := range e.NumberMetrics {
@@ -133,6 +137,7 @@ func (m *Metrics) Finalize(rateLimit uint) {
133137

134138
// Update sum last because avg ^ needs the original value.
135139
s.Sum = (s.Sum * float64(rateLimit)) + s.outlierSum
140+
//TODO(Yash): Do timeTakenToTraceIdProto[s.Max] to know the traceId and populate traceIdOfMaxSql
136141
}
137142

138143
for _, s := range m.NumberMetrics {

parser.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ package slowlog
99

1010
import (
1111
"bufio"
12+
"bytes"
1213
"errors"
1314
"fmt"
1415
"io"
@@ -396,6 +397,92 @@ func (p *FileParser) parseAdmin(line string) {
396397
}
397398
}
398399

400+
// Tested here: https://play.golang.org/p/u7XZnxu2LLL
401+
func parseComments(queryWithComments string) map[string]string {
402+
startIndex := strings.Index(queryWithComments, "/*")
403+
if startIndex != -1 {
404+
endIndex := strings.LastIndex(queryWithComments, "*/")
405+
sqlComments := queryWithComments[startIndex:endIndex]
406+
return parseKeyValuePairToMap(sqlComments)
407+
}
408+
return map[string]string{}
409+
}
410+
411+
// Copied verbatim from https://gist.github.com/alexisvisco/4b846978c9346e4eaf618bb632c0693a
412+
func parseKeyValuePairToMap(msg string) map[string]string {
413+
414+
type kv struct {
415+
key, val string
416+
}
417+
418+
var pair *kv = nil
419+
pairs := make(map[string]string)
420+
buf := bytes.NewBuffer([]byte{})
421+
422+
var (
423+
escape = false
424+
garbage = false
425+
quoted = false
426+
)
427+
428+
completePair := func(buffer *bytes.Buffer, pair *kv) kv {
429+
if pair != nil {
430+
return kv{pair.key, buffer.String()}
431+
} else {
432+
return kv{buffer.String(), ""}
433+
}
434+
}
435+
436+
for _, c := range msg {
437+
if !quoted && c == ' ' {
438+
if buf.Len() != 0 {
439+
if !garbage {
440+
p := completePair(buf, pair)
441+
pairs[p.key] = p.val
442+
pair = nil
443+
}
444+
buf.Reset()
445+
}
446+
garbage = false
447+
} else if !quoted && c == '=' {
448+
if buf.Len() != 0 {
449+
pair = &kv{key: buf.String(), val: ""}
450+
buf.Reset()
451+
} else {
452+
garbage = true
453+
}
454+
} else if quoted && c == '\\' {
455+
escape = true
456+
} else if c == '"' {
457+
if escape {
458+
buf.WriteRune(c)
459+
escape = false
460+
} else {
461+
quoted = !quoted
462+
}
463+
} else {
464+
if escape {
465+
buf.WriteRune('\\')
466+
escape = false
467+
}
468+
buf.WriteRune(c)
469+
}
470+
}
471+
472+
if !garbage {
473+
p := completePair(buf, pair)
474+
pairs[p.key] = p.val
475+
}
476+
477+
// Remove any key value pair where either of them is a blank string
478+
for key, value := range pairs {
479+
if key == "" || value == "" {
480+
delete(pairs, key)
481+
}
482+
}
483+
return pairs
484+
}
485+
399486
func (p *FileParser) sendEvent(inHeader bool, inQuery bool) {
400487
if Debug {
401488
log.Println("send event")
@@ -421,6 +508,7 @@ func (p *FileParser) sendEvent(inHeader bool, inQuery bool) {
421508
// Clean up the event.
422509
p.event.Db = strings.TrimSuffix(p.event.Db, ";\n")
423510
p.event.Query = strings.TrimSuffix(p.event.Query, ";")
511+
p.event.CommentMetadata = parseComments(p.event.Query)
424512

425513
// Send the event. This will block.
426514
select {

0 commit comments

Comments
 (0)