Skip to content

Commit 5f94075

Browse files
Merge pull request #8 from red-bashmak/feature/gatling-binary-log
Feature/gatling binary log
2 parents 33bf490 + c8dade5 commit 5f94075

File tree

6 files changed

+111
-13
lines changed

6 files changed

+111
-13
lines changed

gatlingparser/decoders.go

+14-1
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@ package gatlingparser
33
import (
44
"bufio"
55
"encoding/binary"
6+
"encoding/hex"
67
"fmt"
8+
"io"
79
"math"
810
"strings"
11+
12+
l "github.com/perfana/x2i/logger"
913
)
1014

1115
const (
@@ -366,7 +370,15 @@ func ReadErrorRecord(reader *bufio.Reader, runStartTimestamp int64) (ErrorRecord
366370
}
367371

368372
func ReadNotHeaderRecord(reader *bufio.Reader, runStartTimestapm int64, scenarios []string) (interface{}, error) {
369-
recordType, err := reader.ReadByte()
373+
headBytes, err := reader.Peek(8)
374+
if err == io.EOF {
375+
return nil, err
376+
}
377+
if err != nil {
378+
return nil, fmt.Errorf("could not read bytes from log file - %v", err)
379+
}
380+
var recordType byte
381+
recordType, err = reader.ReadByte()
370382
if err != nil {
371383
return nil, err
372384
}
@@ -381,6 +393,7 @@ func ReadNotHeaderRecord(reader *bufio.Reader, runStartTimestapm int64, scenario
381393
case ErrorRecordType:
382394
return ReadErrorRecord(reader, runStartTimestapm)
383395
default:
396+
l.Debugf("Unknown record start fragment: %s\n", hex.EncodeToString(headBytes))
384397
return nil, fmt.Errorf("unknown record type: %d", recordType)
385398
}
386399
}

gatlingparser/gatlingparser.go

+68-12
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import (
4444
"github.com/perfana/x2i/influx"
4545
l "github.com/perfana/x2i/logger"
4646
"github.com/spf13/cobra"
47+
"golang.org/x/mod/semver"
4748
)
4849

4950
const (
@@ -79,8 +80,6 @@ var (
7980
groupLine = regexp.MustCompile(`GROUP\s`)
8081
runLine = regexp.MustCompile(`^RUN\s`)
8182
errorLine = regexp.MustCompile(`^ERROR\s`)
82-
// for checking gatling version
83-
gatlingVersion313x = regexp.MustCompile(`3\.13\..*`)
8483

8584
parserStopped = make(chan struct{})
8685
)
@@ -596,8 +595,12 @@ func processRemainingRecords(
596595
scenarios []string,
597596
records chan<- interface{},
598597
) {
599-
defer close(records)
600-
defer wg.Done()
598+
defer func() {
599+
close(records)
600+
wg.Done()
601+
}()
602+
603+
latestReadTime := time.Now()
601604

602605
for {
603606
select {
@@ -608,19 +611,31 @@ func processRemainingRecords(
608611
record, err := ReadNotHeaderRecord(reader, runMessage.Start, scenarios)
609612
if err != nil {
610613
if err == io.EOF {
611-
time.Sleep(time.Duration(waitTime) * time.Second) // Wait if end of file
614+
// If no new data read for more than value provided by 'stop-timeout' key then processing is stopped
615+
if time.Now().After(latestReadTime.Add(time.Duration(waitTime) * time.Second)) {
616+
l.Infof("No new entries found for %d seconds. Stopping application...", waitTime)
617+
return
618+
}
619+
time.Sleep(time.Second) // Wait if end of file
612620
continue
613621
}
614622
l.Errorf("Reading error: %v", err)
615623
continue
616624
}
617625

618626
records <- record
627+
latestReadTime = time.Now()
619628
}
620629
}
621630
}
622631

623-
func writeRecords(wg *sync.WaitGroup, records <-chan interface{}) {
632+
type RecordsWriter interface {
633+
writeAll(wg *sync.WaitGroup, records <-chan interface{})
634+
}
635+
636+
type InfluxRecordsWriter struct{}
637+
638+
func (w *InfluxRecordsWriter) writeAll(wg *sync.WaitGroup, records <-chan interface{}) {
624639
defer wg.Done()
625640
for record := range records {
626641
switch r := record.(type) {
@@ -665,7 +680,45 @@ func writeRecords(wg *sync.WaitGroup, records <-chan interface{}) {
665680
}
666681
}
667682

668-
func fileProcessorBinary(ctx context.Context, file *os.File) {
683+
type SumRecordsWriter struct{}
684+
685+
func (w *SumRecordsWriter) writeAll(wg *sync.WaitGroup, records <-chan interface{}) {
686+
defer wg.Done()
687+
var (
688+
users = 0
689+
reqs = 0
690+
rumMessages = 0
691+
errors = 0
692+
groups = 0
693+
)
694+
695+
for record := range records {
696+
// l.Infoln(record)
697+
switch r := record.(type) {
698+
case RunMessage:
699+
rumMessages += 1
700+
701+
case RequestRecord:
702+
reqs += 1
703+
704+
case GroupRecord:
705+
groups += 1
706+
707+
case UserRecord:
708+
users += 1
709+
710+
case ErrorRecord:
711+
errors += 1
712+
713+
default:
714+
l.Errorf("Unknown record type: %T", r)
715+
}
716+
717+
}
718+
l.Debugf("msg = %d, users = %d, reqs = %d, groups = %d, errors = %d\n", rumMessages, users, reqs, groups, errors)
719+
}
720+
721+
func fileProcessorBinary(ctx context.Context, file *os.File, recordsWriter RecordsWriter) {
669722
defer func() { parserStopped <- struct{}{} }()
670723
reader := bufio.NewReader(file)
671724
runMessage, scenarios, err := processLogHeader(reader)
@@ -675,14 +728,13 @@ func fileProcessorBinary(ctx context.Context, file *os.File) {
675728
}
676729

677730
wg := &sync.WaitGroup{}
678-
records := make(chan interface{}, 10)
731+
records := make(chan interface{}, 100)
679732
records <- *runMessage
680733

681734
wg.Add(2)
682735
go processRemainingRecords(ctx, wg, reader, *runMessage, scenarios, records)
683-
go writeRecords(wg, records)
736+
go recordsWriter.writeAll(wg, records)
684737
wg.Wait()
685-
686738
}
687739

688740
func parseStart(ctx context.Context, wg *sync.WaitGroup) {
@@ -703,8 +755,12 @@ func parseStart(ctx context.Context, wg *sync.WaitGroup) {
703755
if err != nil {
704756
l.Errorf("Failed to read %s file: %v\n", simulationLogFileName, err)
705757
}
706-
if gatlingVersion313x.MatchString(ver) {
707-
fileProcessorBinary(ctx, file)
758+
if !semver.IsValid(ver) {
759+
ver = "v" + ver
760+
}
761+
if semver.Compare(ver, "v3.12.1") >= 0 {
762+
writer := InfluxRecordsWriter{}
763+
fileProcessorBinary(ctx, file, &writer)
708764
} else {
709765
fileProcessor(ctx, file)
710766
}

gatlingparser/gatlingparser_test.go

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package gatlingparser
2+
3+
import (
4+
"context"
5+
"os"
6+
"testing"
7+
l "github.com/perfana/x2i/logger"
8+
)
9+
10+
func TestFileProcessorBinary(t *testing.T) {
11+
l.InitLogger("testlog.log")
12+
waitTime = 10
13+
ctx := context.Background()
14+
15+
file, err := os.Open("../test/data/simulation.log")
16+
if err != nil {
17+
t.Errorf("os.Open(%v) returned error: %v", ctx, err)
18+
}
19+
go func () {
20+
<- parserStopped
21+
}()
22+
23+
writer := SumRecordsWriter{}
24+
25+
fileProcessorBinary(ctx, file, &writer)
26+
}

go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ require (
1010
require (
1111
github.com/inconshreveable/mousetrap v1.1.0 // indirect
1212
github.com/spf13/pflag v1.0.5 // indirect
13+
golang.org/x/mod v0.23.0
1314
)

go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,7 @@ github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
88
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
99
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
1010
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
11+
golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
12+
golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
1113
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
1214
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

test/data/simulation.log

2.77 KB
Binary file not shown.

0 commit comments

Comments
 (0)