Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support customized logger for Boomer, Output and runner #194

Merged
merged 6 commits into from
Oct 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 31 additions & 8 deletions boomer.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"time"
)

var defaultBoomer = &Boomer{}
var defaultBoomer = &Boomer{logger: log.Default()}

// Mode is the running mode of boomer, both standalone and distributed are supported.
type Mode int
Expand All @@ -24,6 +24,7 @@ const (

// A Boomer is used to run tasks.
// This type is exposed, so users can create and control a Boomer instance programmatically.
// A non-nil logger is supposed to be set.
type Boomer struct {
masterHost string
masterPort int
Expand All @@ -42,6 +43,8 @@ type Boomer struct {
memoryProfileDuration time.Duration

outputs []Output

logger *log.Logger
}

// NewBoomer returns a new Boomer.
Expand All @@ -50,6 +53,7 @@ func NewBoomer(masterHost string, masterPort int) *Boomer {
masterHost: masterHost,
masterPort: masterPort,
mode: DistributedMode,
logger: log.Default(),
}
}

Expand All @@ -59,7 +63,24 @@ func NewStandaloneBoomer(spawnCount int, spawnRate float64) *Boomer {
spawnCount: spawnCount,
spawnRate: spawnRate,
mode: StandaloneMode,
logger: log.Default(),
}
}

// WithLogger allows user to use their own logger.
// If the logger is nil, it will not take effect.
func (b *Boomer) WithLogger(logger *log.Logger) *Boomer {
if logger == nil {
return b
}
b.logger = logger
if b.slaveRunner != nil {
b.slaveRunner.setLogger(logger)
}
if b.localRunner != nil {
b.localRunner.setLogger(logger)
}
return b
}

// SetRateLimiter allows user to use their own rate limiter.
Expand All @@ -76,7 +97,7 @@ func (b *Boomer) SetMode(mode Mode) {
case StandaloneMode:
b.mode = StandaloneMode
default:
log.Println("Invalid mode, ignored!")
b.logger.Println("Invalid mode, ignored!")
}
}

Expand All @@ -102,33 +123,35 @@ func (b *Boomer) Run(tasks ...*Task) {
if b.cpuProfileFile != "" {
err := StartCPUProfile(b.cpuProfileFile, b.cpuProfileDuration)
if err != nil {
log.Printf("Error starting cpu profiling, %v", err)
b.logger.Printf("Error starting cpu profiling, %v", err)
}
}
if b.memoryProfileFile != "" {
err := StartMemoryProfile(b.memoryProfileFile, b.memoryProfileDuration)
if err != nil {
log.Printf("Error starting memory profiling, %v", err)
b.logger.Printf("Error starting memory profiling, %v", err)
}
}

switch b.mode {
case DistributedMode:
b.slaveRunner = newSlaveRunner(b.masterHost, b.masterPort, tasks, b.rateLimiter)
println("new slave runner")
b.slaveRunner.setLogger(b.logger)
b.logger.Println("new slave runner")
for _, o := range b.outputs {
b.slaveRunner.addOutput(o)
}
b.slaveRunner.run()
case StandaloneMode:
b.localRunner = newLocalRunner(tasks, b.rateLimiter, b.spawnCount, b.spawnRate)
println("new local runner")
b.localRunner.setLogger(b.logger)
b.logger.Println("new local runner")
for _, o := range b.outputs {
b.localRunner.addOutput(o)
}
b.localRunner.run()
default:
log.Println("Invalid mode, expected boomer.DistributedMode or boomer.StandaloneMode")
b.logger.Println("Invalid mode, expected boomer.DistributedMode or boomer.StandaloneMode")
}
}

Expand Down Expand Up @@ -202,7 +225,7 @@ func (b *Boomer) Quit() {
case <-b.slaveRunner.client.disconnectedChannel():
break
case <-ticker.C:
log.Println("Timeout waiting for sending quit message to master, boomer will quit any way.")
b.logger.Println("Timeout waiting for sending quit message to master, boomer will quit any way.")
break
}
b.slaveRunner.shutdown()
Expand Down
21 changes: 19 additions & 2 deletions boomer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package boomer

import (
"flag"
"log"
"math"
"os"
"runtime"
Expand Down Expand Up @@ -215,7 +216,7 @@ var _ = Describe("Test Boomer", func() {

It("test record success", func() {
defer func() {
defaultBoomer = &Boomer{}
defaultBoomer = &Boomer{logger: log.Default()}
}()

// called before runner instance created
Expand Down Expand Up @@ -245,7 +246,7 @@ var _ = Describe("Test Boomer", func() {

It("test record failure", func() {
defer func() {
defaultBoomer = &Boomer{}
defaultBoomer = &Boomer{logger: log.Default()}
}()

// called before runner instance created
Expand Down Expand Up @@ -274,4 +275,20 @@ var _ = Describe("Test Boomer", func() {
Expect(requestFailureMsg.responseTime).To(BeEquivalentTo(2))
Expect(requestFailureMsg.error).To(Equal("udp error"))
})

It("test loggers", func() {
defer func() {
defaultBoomer = &Boomer{logger: log.Default()}
}()

logger := log.New(os.Stdout, "[boomer]", log.LstdFlags)

defaultBoomer = &Boomer{}
defaultBoomer.WithLogger(nil)
defaultBoomer.WithLogger(logger)

defaultBoomer.slaveRunner = &slaveRunner{}
defaultBoomer.localRunner = &localRunner{}
defaultBoomer.WithLogger(logger)
})
})
39 changes: 30 additions & 9 deletions output.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"encoding/json"
"fmt"
"log"
"os"
"sort"
"strconv"
"time"
Expand Down Expand Up @@ -35,11 +34,21 @@ type Output interface {

// ConsoleOutput is the default output for standalone mode.
type ConsoleOutput struct {
logger *log.Logger
}

// NewConsoleOutput returns a ConsoleOutput.
func NewConsoleOutput() *ConsoleOutput {
return &ConsoleOutput{}
return &ConsoleOutput{logger: log.Default()}
}

// WithLogger allows user to use their own logger.
// If the logger is nil, it will not take effect.
func (o *ConsoleOutput) WithLogger(logger *log.Logger) *ConsoleOutput {
if logger != nil {
o.logger = logger
}
return o
}

func getMedianResponseTime(numRequests int64, responseTimes map[int64]int64) int64 {
Expand Down Expand Up @@ -119,14 +128,15 @@ func (o *ConsoleOutput) OnStop() {
func (o *ConsoleOutput) OnEvent(data map[string]interface{}) {
output, err := convertData(data)
if err != nil {
log.Printf("convert data error: %v\n", err)
o.logger.Printf("convert data error: %v\n", err)
return
}

currentTime := time.Now()
println(fmt.Sprintf("Current time: %s, Users: %d, Total RPS: %d, Total Fail Ratio: %.1f%%",
o.logger.Println(fmt.Sprintf("Current time: %s, Users: %d, Total RPS: %d, Total Fail Ratio: %.1f%%",
currentTime.Format("2006/01/02 15:04:05"), output.UserCount, output.TotalRPS, output.TotalFailRatio*100))
table := tablewriter.NewWriter(os.Stdout)
noPrefixLogger := log.New(o.logger.Writer(), "", 0)
table := tablewriter.NewWriter(noPrefixLogger.Writer())
table.SetHeader([]string{"Type", "Name", "# requests", "# fails", "Median", "Average", "Min", "Max", "Content Size", "# reqs/sec", "# fails/sec"})

for _, stat := range output.Stats {
Expand All @@ -145,7 +155,7 @@ func (o *ConsoleOutput) OnEvent(data map[string]interface{}) {
table.Append(row)
}
table.Render()
println()
o.logger.Println()
}

type statsEntryOutput struct {
Expand Down Expand Up @@ -334,17 +344,28 @@ var (
func NewPrometheusPusherOutput(gatewayURL, jobName string) *PrometheusPusherOutput {
return &PrometheusPusherOutput{
pusher: push.New(gatewayURL, jobName),
logger: log.Default(),
}
}

// WithLogger allows user to use their own logger.
// If the logger is nil, it will not take effect.
func (o *PrometheusPusherOutput) WithLogger(logger *log.Logger) *PrometheusPusherOutput {
if logger != nil {
o.logger = logger
}
return o
}

// PrometheusPusherOutput pushes boomer stats to Prometheus Pushgateway.
type PrometheusPusherOutput struct {
pusher *push.Pusher // Prometheus Pushgateway Pusher
logger *log.Logger
}

// OnStart will register all prometheus metric collectors
func (o *PrometheusPusherOutput) OnStart() {
log.Println("register prometheus metric collectors")
o.logger.Println("register prometheus metric collectors")
registry := prometheus.NewRegistry()
registry.MustRegister(
// gauge vectors for requests
Expand Down Expand Up @@ -374,7 +395,7 @@ func (o *PrometheusPusherOutput) OnStop() {
func (o *PrometheusPusherOutput) OnEvent(data map[string]interface{}) {
output, err := convertData(data)
if err != nil {
log.Printf("convert data error: %v\n", err)
o.logger.Printf("convert data error: %v\n", err)
return
}

Expand Down Expand Up @@ -402,6 +423,6 @@ func (o *PrometheusPusherOutput) OnEvent(data map[string]interface{}) {
}

if err := o.pusher.Push(); err != nil {
log.Printf("Could not push to Pushgateway: error: %v\n", err)
o.logger.Printf("Could not push to Pushgateway: error: %v\n", err)
}
}
16 changes: 16 additions & 0 deletions output_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package boomer

import (
"log"
"os"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
Expand Down Expand Up @@ -94,4 +97,17 @@ var _ = Describe("test output", func() {

o.OnStop()
})

It("test loggers", func() {
o := NewConsoleOutput()

logger := log.New(os.Stdout, "[boomer]", log.LstdFlags)

o.WithLogger(nil)
o.WithLogger(logger)

o2 := NewPrometheusPusherOutput("", "")
o2.WithLogger(nil)
o2.WithLogger(logger)
})
})
Loading