fix: avoid instantiating a logger if provided /dev/null (#24027)

- Adds some additional context to workspace traffic logging
- Fails traffic tests if 0 bytes read from connection
This commit is contained in:
Jon Ayers
2026-04-03 16:26:14 -05:00
committed by GitHub
parent a1d51f0dab
commit 7e63fe68f7
4 changed files with 37 additions and 3 deletions
+1 -1
View File
@@ -104,7 +104,7 @@ func (b *Builder) Build(inv *serpent.Invocation) (log slog.Logger, closeLog func
addSinkIfProvided := func(sinkFn func(io.Writer) slog.Sink, loc string) error {
switch loc {
case "":
case "", "/dev/null":
case "/dev/stdout":
sinks = append(sinks, sinkFn(inv.Stdout))
+3
View File
@@ -1401,6 +1401,9 @@ func (r *RootCmd) scaletestWorkspaceTraffic() *serpent.Command {
// Setup our workspace agent connection.
config := workspacetraffic.Config{
AgentID: agent.ID,
WorkspaceID: ws.ID,
WorkspaceName: ws.Name,
AgentName: agent.Name,
BytesPerTick: bytesPerTick,
Duration: strategy.timeout,
TickInterval: tickInterval,
+6
View File
@@ -12,6 +12,12 @@ import (
type Config struct {
// AgentID is the workspace agent ID to which to connect.
AgentID uuid.UUID `json:"agent_id"`
// WorkspaceID is the workspace ID, used for logging.
WorkspaceID uuid.UUID `json:"workspace_id"`
// WorkspaceName is the workspace name, used for logging.
WorkspaceName string `json:"workspace_name"`
// AgentName is the agent name, used for logging.
AgentName string `json:"agent_name"`
// BytesPerTick is the number of bytes to send to the agent per tick.
BytesPerTick int64 `json:"bytes_per_tick"`
+27 -2
View File
@@ -76,7 +76,12 @@ func (r *Runner) Run(ctx context.Context, _ string, logs io.Writer) (err error)
echo = r.cfg.Echo
)
logger = logger.With(slog.F("agent_id", agentID))
logger = logger.With(
slog.F("agent_id", agentID),
slog.F("workspace_id", r.cfg.WorkspaceID),
slog.F("workspace_name", r.cfg.WorkspaceName),
slog.F("agent_name", r.cfg.AgentName),
)
logger.Debug(ctx, "config",
slog.F("reconnecting_pty_id", reconnect),
@@ -153,6 +158,14 @@ func (r *Runner) Run(ctx context.Context, _ string, logs io.Writer) (err error)
conn.readMetrics = r.cfg.ReadMetrics
conn.writeMetrics = r.cfg.WriteMetrics
logTrafficSummary := func() {
//nolint:gocritic
logger.Info(ctx, "traffic summary",
slog.F("actual_bytes_read", r.cfg.ReadMetrics.GetTotalBytes()),
slog.F("actual_bytes_written", r.cfg.WriteMetrics.GetTotalBytes()),
)
}
// Create a ticker for sending data to the conn.
tick := time.NewTicker(tickInterval)
defer tick.Stop()
@@ -179,10 +192,18 @@ func (r *Runner) Run(ctx context.Context, _ string, logs io.Writer) (err error)
var waitCloseTimeoutCh <-chan struct{}
deadlineCtxCh := deadlineCtx.Done()
deadlineReached := false
wchRef, rchRef := wch, rch
for {
if wchRef == nil && rchRef == nil {
logger.Info(ctx, "reading and writing to agent complete! Closing connection")
logTrafficSummary()
if !deadlineReached {
return xerrors.Errorf("test did not complete: context canceled after %s of %s",
time.Since(start).Truncate(time.Second), r.cfg.Duration)
}
if r.cfg.ReadMetrics.GetTotalBytes() == 0 {
return xerrors.Errorf("zero bytes read from agent")
}
return nil
}
@@ -192,23 +213,27 @@ func (r *Runner) Run(ctx context.Context, _ string, logs io.Writer) (err error)
slog.F("write_done", wchRef == nil),
slog.F("read_done", rchRef == nil),
)
logTrafficSummary()
return xerrors.Errorf("timed out waiting for read/write to complete: %w", ctx.Err())
case <-deadlineCtxCh:
go func() {
_ = closeConn()
}()
deadlineCtxCh = nil // Only trigger once.
deadlineReached = true
// Wait at most closeTimeout for the connection to close cleanly.
waitCtx, cancel := context.WithTimeout(context.Background(), waitCloseTimeout)
defer cancel() //nolint:revive // Only called once.
waitCloseTimeoutCh = waitCtx.Done()
case err = <-wchRef:
if err != nil {
logTrafficSummary()
return xerrors.Errorf("write to agent: %w", err)
}
wchRef = nil
case err = <-rchRef:
if err != nil {
logTrafficSummary()
return xerrors.Errorf("read from agent: %w", err)
}
rchRef = nil