Skip to content

Commit

Permalink
created interface to parse different databases in a different way
Browse files Browse the repository at this point in the history
  • Loading branch information
eze-kiel committed Feb 25, 2021
1 parent c444374 commit 0f0df32
Show file tree
Hide file tree
Showing 7 changed files with 332 additions and 248 deletions.
46 changes: 22 additions & 24 deletions cmd/example/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"time"

"github.com/devops-works/slowql"
"github.com/sirupsen/logrus"
)

func main() {
Expand All @@ -19,37 +18,36 @@ func main() {
if err != nil {
panic(err)
}
p := slowql.NewParser(fd)

p := slowql.NewParser(slowql.MariaDB, fd)
var count int
start := time.Now()
for {
q, err := p.GetNext()
if err != nil {
logrus.Error(err)
}
if q.Query == "" {
q := p.GetNext()
if q == (slowql.Query{}) {
break
}
// fmt.Printf("Time: %s\nUser: %s\nHost: %s\nID: %d\nSchema: %s\nLast_errno: %d\nKilled: %d\nQuery_time: %s\nLock_time: %s\nRows_sent: %d\nRows_examined: %d\nRows_affected: %d\nBytes_sent: %d\nQuery: %s\n",
// q.Time,
// q.User,
// q.Host,
// q.ID,
// q.Schema,
// q.LastErrNo,
// q.Killed,
// q.QueryTime,
// q.LockTime,
// q.RowsSent,
// q.RowsExamined,
// q.RowsAffected,
// q.BytesSent,
// q.Query,
// )

fmt.Printf("Time: %s\nUser: %s\nHost: %s\nID: %d\nSchema: %s\nLast_errno: %d\nKilled: %d\nQuery_time: %f\nLock_time: %f\nRows_sent: %d\nRows_examined: %d\nRows_affected: %d\nBytes_sent: %d\nQuery: %s\n",
q.Time,
q.User,
q.Host,
q.ID,
q.Schema,
q.LastErrNo,
q.Killed,
q.QueryTime,
q.LockTime,
q.RowsSent,
q.RowsExamined,
q.RowsAffected,
q.BytesSent,
q.Query,
)
count++
}

elapsed := time.Since(start)
fmt.Printf("parsed %d queries in %s\n", count, elapsed)
fmt.Printf("\nparsed %d queries in %s\n", count, elapsed)

}
3 changes: 0 additions & 3 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/magefile/mage v1.10.0 h1:3HiXzCUY12kh9bIuyXShaVe529fJfyqoVM42o/uom2g=
github.com/magefile/mage v1.10.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.8.0 h1:nfhvjKcUMhBMVqbKHJlk5RPrrfYr/NMo3692g0dwfWU=
github.com/sirupsen/logrus v1.8.0/go.mod h1:4GuYW9TZmE769R5STWrRakJc4UqQ3+QQ95fyz7ENv1A=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
116 changes: 59 additions & 57 deletions query.go → mariadb.go
Original file line number Diff line number Diff line change
@@ -1,100 +1,97 @@
package slowql

import (
"crypto/md5"
"fmt"
"io"
"strconv"
"strings"
"time"

"github.com/sirupsen/logrus"
)

// Query contains query informations. Those fields can be accessed from the
// outside of the package to do calculation. If a field does not exists in the
// log file, it will be empty in the returned query.
type Query struct {
// Date and time of the query
Time string
// MariaDB is the MariaDB kind
const MariaDB Kind = 1

// The user who issued the query
User string

// The host from where the query were issued
Host string

// The ID of the query
ID int

// The table schema
Schema string

// Value of the error message from previous MySQL operation
LastErrNo int

Killed int

// Duration of the query
QueryTime string

// Duration of the lock time due to the query
LockTime string

// Rows sent during query
RowsSent int

// Rows examined during query
RowsExamined int

// Rows affected by the query
RowsAffected int

// Bytes sent by the query
BytesSent int
type mariadbParser struct {
wl chan Query
}

// The query itself. If therre were multiple queries, they are appended
Query string
func (p *mariadbParser) parseBlocs(rawBlocs chan []string) {
for {
select {
case bloc := <-rawBlocs:
var q Query

for _, line := range bloc {
if strings.HasPrefix(line, "#") {
q.parseMariaDBHeader(line)
} else {
q.Query = q.Query + line
}
}
p.wl <- q
}
}
}

// Fingerprint returns Query.query's MD5 fingerprint.
func (q Query) Fingerprint() (string, error) {
h := md5.New()
_, err := io.WriteString(h, q.Query)
if err != nil {
return "", err
func (p *mariadbParser) GetNext() Query {
var q Query
select {
case q = <-p.wl:
return q
case <-time.After(2 * time.Second):
close(p.wl)
}
return fmt.Sprintf("%x", h.Sum(nil)), nil
return q
}

// parseHeader parses everything that begin with #
func (q *Query) parseHeader(line string) {
func (q *Query) parseMariaDBHeader(line string) {
var err error
parts := strings.Split(line, " ")

for idx, part := range parts {
part = strings.ToLower(part)

if strings.Contains(part, "query_time:") {
q.QueryTime = parts[idx+1]
time := parts[idx+1]
q.QueryTime, err = strconv.ParseFloat(time, 64)
if err != nil {
logrus.Errorf("query_time: error converting %s to time: %s", parts[idx+1], err)
}

} else if strings.Contains(part, "lock_time:") {
q.LockTime = parts[idx+1]
time := parts[idx+1]
q.LockTime, err = strconv.ParseFloat(time, 64)
if err != nil {
logrus.Errorf("lock_time: error converting %s to time: %s", parts[idx+1], err)
}

} else if strings.Contains(part, "time:") {
q.Time = parts[idx+1]
date := parts[idx+1] + " " + parts[idx+2]
fmt.Printf("\n\n\n%s\n\n\n\n", date)
q.Time, err = time.Parse("060102 15:04:05", date)
if err != nil {
logrus.Errorf("time: error converting %s to time: %s", parts[idx+1], err)
}

} else if strings.Contains(part, "rows_sent:") {
q.RowsSent, err = strconv.Atoi(parts[idx+1])
if err != nil {
logrus.Errorf("row_sent: error converting %s to int: %s", parts[idx+1], err)
}

} else if strings.Contains(part, "rows_examined:") {
q.RowsExamined, err = strconv.Atoi(parts[idx+1])
if err != nil {
logrus.Errorf("rows_examined: error converting %s to int: %s", parts[idx+1], err)
}

} else if strings.Contains(part, "rows_affected:") {
q.RowsAffected, err = strconv.Atoi(parts[idx+1])
if err != nil {
logrus.Errorf("rows_affected: error converting %s to int: %s", parts[idx+1], err)
}

} else if strings.Contains(part, "id:") {
// Some IDs can have multiple spaces, so we try to bruteforce the
// number of spaces. I tried implementing a version that keeps in
Expand All @@ -109,24 +106,29 @@ func (q *Query) parseHeader(line string) {
if err != nil {
logrus.Errorf("id: error converting %s to int: %s", parts[idx+1], err)
}

} else if strings.Contains(part, "user@host:") {
items := re.FindAllString(line, -1)
items := stringInBrackets.FindAllString(line, -1)
// We remove first and last bytes of the strings because they are
// square brackets
q.User = items[0][1 : len(items[0])-1]
q.Host = items[1][1 : len(items[1])-1]

} else if strings.Contains(part, "schema:") {
q.Schema = parts[idx+1]

} else if strings.Contains(part, "last_errno:") {
q.LastErrNo, err = strconv.Atoi(parts[idx+1])
if err != nil {
logrus.Errorf("last_errno: error converting %s to int: %s", parts[idx+1], err)
}

} else if strings.Contains(part, "killed:") {
q.Killed, err = strconv.Atoi(parts[idx+1])
if err != nil {
logrus.Errorf("killed: error converting %s to int: %s", parts[idx+1], err)
}

} else if strings.Contains(part, "bytes_sent:") {
q.BytesSent, err = strconv.Atoi(parts[idx+1])
if err != nil {
Expand Down
Loading

0 comments on commit 0f0df32

Please sign in to comment.