Skip to content

Commit

Permalink
feat: support user provided loggers
Browse files Browse the repository at this point in the history
  • Loading branch information
nvloff-f3 committed Jul 11, 2024
1 parent 4209fa2 commit 6367340
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 10 deletions.
7 changes: 7 additions & 0 deletions internal/ui/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,10 @@ func NewDefaultOutput(logLevel slog.Level, jsonFormat bool) *Output {

return NewOutput(logger, printer, interactive, true)
}

func NewDefaultOutputWithLogger(logger *slog.Logger) *Output {
printer := NewDefaultPrinter()
interactive := isatty.IsTerminal(os.Stdin.Fd())

return NewOutput(logger, printer, interactive, true)
}
14 changes: 13 additions & 1 deletion pkg/f1/f1.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"log/slog"
"os"
"os/signal"
"syscall"
Expand Down Expand Up @@ -32,7 +33,7 @@ type F1 struct {
settings envsettings.Settings
}

// Instantiates a new instance of an F1 CLI.
// New instantiates a new instance of an F1 CLI.
func New() *F1 {
settings := envsettings.Get()

Expand All @@ -44,6 +45,17 @@ func New() *F1 {
}
}

// WithLogger allows specifying logger to be used for all internal and scenario logs
//
// This will disable the LOG_LEVEL and LOG_FORMAT options, as they only relate to the built-in
// logger.
//
// The logger will be used for non-interactive output, file logs or when `--verbose` is specified.
func (f *F1) WithLogger(logger *slog.Logger) *F1 {
f.output = ui.NewDefaultOutputWithLogger(logger)
return f
}

// Registers a new test scenario with the given name. This is the name used when running
// load test scenarios. For example, calling the function with the following arguments:
//
Expand Down
56 changes: 47 additions & 9 deletions pkg/f1/f1_stage_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package f1_test

import (
"bytes"
"fmt"
"os"
"strings"
"sync/atomic"
"syscall"
"testing"
Expand All @@ -11,21 +14,21 @@ import (
"github.com/stretchr/testify/require"
"go.uber.org/goleak"

"github.com/form3tech-oss/f1/v2/internal/log"
"github.com/form3tech-oss/f1/v2/pkg/f1"
f1_testing "github.com/form3tech-oss/f1/v2/pkg/f1/testing"
)

type f1Stage struct {
t *testing.T
assert *assert.Assertions
require *require.Assertions

f1 *f1.F1
errCh chan error
scenario string
runCount atomic.Uint32

executeErr error
t *testing.T
assert *assert.Assertions
require *require.Assertions
f1 *f1.F1
errCh chan error
scenario string
logOutput bytes.Buffer
runCount atomic.Uint32
}

func newF1Stage(t *testing.T) (*f1Stage, *f1Stage, *f1Stage) {
Expand All @@ -46,6 +49,13 @@ func (s *f1Stage) and() *f1Stage {
return s
}

func (s *f1Stage) a_custom_logger_is_configured_with_attr(key, value string) *f1Stage {
logger := log.NewTestLogger(&s.logOutput).With(key, value)
s.f1 = f1.New().WithLogger(logger)

return s
}

func (s *f1Stage) after_duration_signal_will_be_sent(duration time.Duration, signal syscall.Signal) *f1Stage {
go func() {
time.Sleep(duration)
Expand Down Expand Up @@ -74,6 +84,20 @@ func (s *f1Stage) a_scenario_where_each_iteration_takes(duration time.Duration)
return s
}

func (s *f1Stage) a_scenario_that_logs() *f1Stage {
s.scenario = "logging_scenario"
s.f1.Add(s.scenario, func(sceanrioT *f1_testing.T) f1_testing.RunFn {
sceanrioT.Log("scenario")

return func(*f1_testing.T) {
sceanrioT.Log("iteration")
sceanrioT.Logger().Info("iteration")
}
})

return s
}

func (s *f1Stage) the_f1_scenario_is_executed_with_constant_rate_and_args(args ...string) *f1Stage {
err := s.f1.ExecuteWithArgs(append([]string{
"run", "constant", s.scenario,
Expand Down Expand Up @@ -115,3 +139,17 @@ func (s *f1Stage) expect_no_goroutines_to_run() *f1Stage {

return s
}

func (s *f1Stage) expect_all_log_lines_to_contain_attr(key, value string) *f1Stage {
lines := strings.Split(s.logOutput.String(), "\n")

s.require.Len(lines, 7)

for _, line := range lines {
if line != "" {
s.require.Contains(line, fmt.Sprintf(" %s=%s ", key, value))
}
}

return s
}
17 changes: 17 additions & 0 deletions pkg/f1/f1_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,20 @@ func TestMissingScenario(t *testing.T) {
then.
the_execute_command_returns_an_error("scenario not defined: unknownScenario")
}

func TestWithCustomLogger(t *testing.T) {
given, when, then := newF1Stage(t)

given.
a_custom_logger_is_configured_with_attr("custom", "value").and().
a_scenario_that_logs()

when.
the_f1_scenario_is_executed_with_constant_rate_and_args(
"--rate", "1/1s",
"--max-duration", "2s",
)

then.
expect_all_log_lines_to_contain_attr("custom", "value")
}

0 comments on commit 6367340

Please sign in to comment.