Skip to content

Commit 6166a42

Browse files
mtGitHub CopilotCopilot
authored
refactor: remove package-level loggers, thread via struct fields and context (#29)
* refactor: remove package-level loggers, thread via struct fields and context - Delete internal/log package (abtrlog); inline setup logic into arbiter.go as a setupLoggers() helper function - Add logger logr.Logger field to abtr struct; populate from Run() - Convert standalone startModules() to method on abtr - Change setupReporter() to return (report.Reporter, error) and pass a.logger to the yaml reporter - Fix defaultOpts() bug: was setting InfoLogPath twice, never ErrorLogPath - yamlreport.New() now returns (report.Reporter, error); errors when opts.Logger.GetSink() == nil (zero-value / not provided) - Add Logger logr.Logger field to yamlreport.Opts and reporter struct - Replace zerologr.Info() global call in internal/otel with logr.FromContextOrDiscard(ctx).Info() (context transport) - Update yaml_test.go to supply an explicit logger via funcr Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor: remove error return from yamlreport.New() Logger is passed by value, not a pointer, so a zero-value logger is always 'provided' — validating the sink is not meaningful. Revert New() to returning report.Reporter directly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: correct indentation in yaml reporter (goimports) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: GitHub Copilot <copilot@github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 65de2a7 commit 6166a42

5 files changed

Lines changed: 89 additions & 136 deletions

File tree

arbiter.go

Lines changed: 71 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212
"time"
1313

1414
"github.com/go-logr/logr"
15-
abtrlog "github.com/maansaake/arbiter/internal/log"
1615
"github.com/maansaake/arbiter/pkg/module"
1716
"github.com/maansaake/arbiter/pkg/report"
1817
"github.com/maansaake/arbiter/pkg/report/collection"
@@ -25,6 +24,7 @@ import (
2524
"github.com/spf13/cobra"
2625
"github.com/spf13/pflag"
2726
"github.com/trebent/envparser"
27+
"github.com/trebent/zerologr"
2828
)
2929

3030
type (
@@ -38,6 +38,8 @@ type (
3838
reportPath string
3939
// interactive is set when an interactive TUI reporting is used.
4040
interactive bool
41+
// logger is used for info-level logging.
42+
logger logr.Logger
4143
// errorLogger is the logger used for error logs by the reporter.
4244
errorLogger logr.Logger
4345
}
@@ -51,27 +53,26 @@ type (
5153
}
5254
)
5355

56+
const (
57+
defaultInfoLogPath = "info.log"
58+
defaultErrorLogPath = "error.log"
59+
defaultDuration = time.Minute * 5
60+
defaultReportPath = "report.yaml"
61+
defaultInteractive = false
62+
)
63+
5464
// defaultOpts sets zero-value fields to their defaults.
5565
func (o *Opts) defaultOpts() {
5666
if o.ErrorLogPath == "" {
57-
o.InfoLogPath = abtrlog.DefaultErrorLogPath
67+
o.ErrorLogPath = defaultErrorLogPath
5868
}
5969

60-
if o.ErrorLogPath == "" {
61-
o.InfoLogPath = abtrlog.DefaultInfoLogPath
70+
if o.InfoLogPath == "" {
71+
o.InfoLogPath = defaultInfoLogPath
6272
}
6373
}
6474

65-
const (
66-
defaultDuration = time.Minute * 5
67-
defaultReportPath = "report.yaml"
68-
defaultInteractive = false
69-
)
70-
7175
var (
72-
// logger is the package logger for the arbiter package.
73-
logger logr.Logger //nolint:gochecknoglobals // package-level state for arbiter
74-
7576
// rootCmd holds the cobra root command for Usage access.
7677
//nolint:gochecknoglobals // package-level command for Usage access
7778
rootCmd *cobra.Command
@@ -123,21 +124,17 @@ func Run(modules module.Modules, opts *Opts) error {
123124
SilenceUsage: true,
124125
}
125126

126-
errorLogger, err := abtrlog.Setup(&abtrlog.Opts{
127-
Verbosity: logVerbosity.Value(),
128-
ErrorLogPath: opts.ErrorLogPath,
129-
InfoLogPath: opts.InfoLogPath,
130-
})
127+
infoLogger, errorLogger, err := setupLoggers(opts, logVerbosity.Value())
131128
if err != nil {
132129
return fmt.Errorf("failed to build loggers: %w", err)
133130
}
134-
logger = abtrlog.GetLogger()
135131

136132
abtr := &abtr{
137133
opts: opts,
138134
duration: defaultDuration,
139135
reportPath: defaultReportPath,
140136
interactive: defaultInteractive,
137+
logger: infoLogger,
141138
errorLogger: errorLogger,
142139
}
143140

@@ -240,18 +237,14 @@ func (a *abtr) buildRunnerFlagSet() *pflag.FlagSet {
240237
return runnerFlagSet
241238
}
242239

243-
// run runs the input modules and starts generating traffic. Creates a traffic
244-
// model based on the modules opertation settings. Aborts on SIGINT, SIGTERM
245-
// or when the test duration runs out. Will immediately exit if any module
246-
// returns an error from its call to Run().
247240
func (a *abtr) run(metadata module.Metadata) error {
248-
logger.Info("Starting modules")
241+
a.logger.Info("Starting modules")
249242

250-
if err := startModules(metadata); err != nil {
251-
logger.Error(err, "Start failure")
243+
if err := a.startModules(metadata); err != nil {
244+
a.logger.Error(err, "Start failure")
252245
return err
253246
}
254-
logger.Info("All modules started")
247+
a.logger.Info("All modules started")
255248

256249
// Start signal interceptor for SIGINT and SIGTERM
257250
signalCtx, signalCancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
@@ -265,7 +258,7 @@ func (a *abtr) run(metadata module.Metadata) error {
265258
// Traffic context with a timeout of the test's >>> duration <<<
266259
timeoutCtx, timeoutCancel := context.WithTimeout(signalCtx, a.duration)
267260
defer timeoutCancel()
268-
logger.Info("Traffic will run for: " + a.duration.String())
261+
a.logger.Info("Traffic will run for: " + a.duration.String())
269262

270263
// The reporter runs in its own context to allow reporting to finalize separately from traffic and module
271264
// shutdown.
@@ -274,26 +267,26 @@ func (a *abtr) run(metadata module.Metadata) error {
274267
reporter.Start(reporterCtx)
275268

276269
sched := traffic.New(&traffic.Opts{
277-
Logger: logger,
270+
Logger: a.logger,
278271
WorkerLimit: workerLimit.Value(),
279272
})
280273

281274
// Run traffic.
282275
if err := sched.Run(timeoutCtx, metadata, reporter); err != nil {
283276
reporter.ReportError(err) // Report is done in case of early traffic failure, to highlight issues in the TUI.
284-
logger.Error(err, "Failed to start traffic")
277+
a.logger.Error(err, "Failed to start traffic")
285278
return err
286279
}
287280

288-
logger.Info("Awaiting completion (SIGINT/SIGTERM or duration timeout)")
281+
a.logger.Info("Awaiting completion (SIGINT/SIGTERM or duration timeout)")
289282
select {
290283
case <-signalCtx.Done():
291-
logger.Info("Got stop signal")
284+
a.logger.Info("Got stop signal")
292285
// no need to call timeoutCancel() here since the traffic context is a child of the signal context,
293286
// so will be cancelled automatically.
294287
// timeoutCancel()
295288
case <-timeoutCtx.Done():
296-
logger.Info("Deadline exceeded")
289+
a.logger.Info("Deadline exceeded")
297290
// Needed to terminate the parent context, in case other's are reliant on it.
298291
signalCancel()
299292
}
@@ -302,35 +295,35 @@ func (a *abtr) run(metadata module.Metadata) error {
302295
// to be returned at the end of the function.
303296
var stopErr error
304297
if stopErr = sched.Stop(); stopErr != nil {
305-
logger.Error(stopErr, "Error when stopping traffic")
298+
a.logger.Error(stopErr, "Error when stopping traffic")
306299
stopErr = fmt.Errorf("%w: traffic stop: %w", ErrStopping, stopErr)
307300
}
308301

309302
// Now that traffic has been stopped, we can stop the reporter to allow it to finalise the report.
310303
reporterCancel()
311304

312-
logger.Info("Stopping modules")
305+
a.logger.Info("Stopping modules")
313306
for _, m := range metadata {
314307
if moduleStopErr := m.Stop(); moduleStopErr != nil {
315-
logger.Error(moduleStopErr, "Module stop reported an error", "module", m.Name())
308+
a.logger.Error(moduleStopErr, "Module stop reported an error", "module", m.Name())
316309
stopErr = errors.Join(stopErr, fmt.Errorf("module %s stop: %w", m.Name(), moduleStopErr))
317310
}
318311
}
319312

320-
logger.Info("Finalising report")
313+
a.logger.Info("Finalising report")
321314
reporterStopErr := reporter.Finalise()
322315
if reporterStopErr != nil {
323-
logger.Error(reporterStopErr, "Error when finalising report")
316+
a.logger.Error(reporterStopErr, "Error when finalising report")
324317
stopErr = errors.Join(stopErr, fmt.Errorf("reporter stop: %w", reporterStopErr))
325318
}
326319

327320
return stopErr
328321
}
329322

330-
// Starts the input modules and logs any errors.
331-
func startModules(meta []*module.Meta) error {
323+
// startModules starts the input modules and logs any errors.
324+
func (a *abtr) startModules(meta []*module.Meta) error {
332325
for _, m := range meta {
333-
logger.Info("Starting", "module", m.Name())
326+
a.logger.Info("Starting", "module", m.Name())
334327
if err := m.Run(); err != nil {
335328
return fmt.Errorf("failed to start module %s: %w", m.Name(), err)
336329
}
@@ -339,7 +332,7 @@ func startModules(meta []*module.Meta) error {
339332
return nil
340333
}
341334

342-
// Creates the reporter(s). In interactive mode a collection reporter is
335+
// setupReporter creates the reporter(s). In interactive mode a collection reporter is
343336
// returned that fans out to both a YAML reporter and the live TUI reporter.
344337
// trafficCancel is called by the interactive reporter when the user requests an early
345338
// stop (e.g. Ctrl-C inside the TUI), triggering the same shutdown path as
@@ -352,6 +345,7 @@ func (a *abtr) setupReporter(
352345
) report.Reporter {
353346
yamlR := yamlreport.New(&yamlreport.Opts{
354347
Path: a.reportPath,
348+
Logger: a.logger,
355349
ErrorLogger: a.errorLogger,
356350
})
357351

@@ -369,3 +363,38 @@ func (a *abtr) setupReporter(
369363

370364
return yamlR
371365
}
366+
367+
// setupLoggers initialises the info and error loggers from the provided options.
368+
// It returns the info logger, the error logger, and any error encountered.
369+
func setupLoggers(opts *Opts, verbosity int) (logr.Logger, logr.Logger, error) {
370+
errorFile, err := os.Create(opts.ErrorLogPath)
371+
if err != nil {
372+
return logr.Logger{}, logr.Logger{}, err
373+
}
374+
375+
var infoLogger logr.Logger
376+
if opts.InfoLogPath == "" {
377+
infoLogger = logr.Discard()
378+
} else {
379+
infoFile, err := os.Create(opts.InfoLogPath) //nolint:govet // shad
380+
if err != nil {
381+
return logr.Logger{}, logr.Logger{}, err
382+
}
383+
384+
infoLogger = zerologr.New(&zerologr.Opts{
385+
Output: infoFile,
386+
Console: true,
387+
Caller: true,
388+
V: verbosity,
389+
}).WithName("abtr")
390+
}
391+
392+
errorLogger := zerologr.New(&zerologr.Opts{
393+
Output: errorFile,
394+
Console: true,
395+
Caller: false,
396+
V: verbosity,
397+
})
398+
399+
return infoLogger, errorLogger, nil
400+
}

internal/log/log.go

Lines changed: 0 additions & 80 deletions
This file was deleted.

internal/otel/instrument.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import (
44
"context"
55
"errors"
66

7-
"github.com/trebent/zerologr"
7+
"github.com/go-logr/logr"
88
"go.opentelemetry.io/contrib/exporters/autoexport"
99
"go.opentelemetry.io/contrib/instrumentation/runtime"
1010
"go.opentelemetry.io/otel"
@@ -26,7 +26,7 @@ func Instrument(
2626
var shutdownFuncs []func(context.Context) error
2727

2828
shutdown := func(ctx context.Context) error {
29-
zerologr.Info("Shutting down OpenTelemetry SDK")
29+
logr.FromContextOrDiscard(ctx).Info("Shutting down OpenTelemetry SDK")
3030

3131
var err error
3232
for _, fn := range shutdownFuncs {

0 commit comments

Comments
 (0)