diff --git a/cli/agent.go b/cli/agent.go index 073581bd95..43af444536 100644 --- a/cli/agent.go +++ b/cli/agent.go @@ -12,7 +12,6 @@ import ( "runtime" "strconv" "strings" - "sync" "time" "cloud.google.com/go/compute/metadata" @@ -30,6 +29,7 @@ import ( "github.com/coder/coder/v2/agent/agentssh" "github.com/coder/coder/v2/agent/reaper" "github.com/coder/coder/v2/buildinfo" + "github.com/coder/coder/v2/cli/clilog" "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/codersdk/agentsdk" "github.com/coder/serpent" @@ -110,7 +110,7 @@ func (r *RootCmd) workspaceAgent() *serpent.Command { // Spawn a reaper so that we don't accumulate a ton // of zombie processes. if reaper.IsInitProcess() && !noReap && isLinux { - logWriter := &lumberjackWriteCloseFixer{w: &lumberjack.Logger{ + logWriter := &clilog.LumberjackWriteCloseFixer{Writer: &lumberjack.Logger{ Filename: filepath.Join(logDir, "coder-agent-init.log"), MaxSize: 5, // MB // Without this, rotated logs will never be deleted. @@ -153,7 +153,7 @@ func (r *RootCmd) workspaceAgent() *serpent.Command { // reaper. go DumpHandler(ctx, "agent") - logWriter := &lumberjackWriteCloseFixer{w: &lumberjack.Logger{ + logWriter := &clilog.LumberjackWriteCloseFixer{Writer: &lumberjack.Logger{ Filename: filepath.Join(logDir, "coder-agent.log"), MaxSize: 5, // MB // Per customer incident on November 17th, 2023, its helpful @@ -478,33 +478,6 @@ func ServeHandler(ctx context.Context, logger slog.Logger, handler http.Handler, } } -// lumberjackWriteCloseFixer is a wrapper around an io.WriteCloser that -// prevents writes after Close. This is necessary because lumberjack -// re-opens the file on Write. -type lumberjackWriteCloseFixer struct { - w io.WriteCloser - mu sync.Mutex // Protects following. - closed bool -} - -func (c *lumberjackWriteCloseFixer) Close() error { - c.mu.Lock() - defer c.mu.Unlock() - - c.closed = true - return c.w.Close() -} - -func (c *lumberjackWriteCloseFixer) Write(p []byte) (int, error) { - c.mu.Lock() - defer c.mu.Unlock() - - if c.closed { - return 0, io.ErrClosedPipe - } - return c.w.Write(p) -} - // extractPort handles different url strings. // - localhost:6060 // - http://localhost:6060 diff --git a/cli/clilog/clilog.go b/cli/clilog/clilog.go index 33851155a5..e2ad3d339f 100644 --- a/cli/clilog/clilog.go +++ b/cli/clilog/clilog.go @@ -6,6 +6,7 @@ import ( "io" "regexp" "strings" + "sync" "golang.org/x/xerrors" "gopkg.in/natefinch/lumberjack.v2" @@ -111,12 +112,12 @@ func (b *Builder) Build(inv *serpent.Invocation) (log slog.Logger, closeLog func sinks = append(sinks, sinkFn(inv.Stderr)) default: - logWriter := &lumberjack.Logger{ + logWriter := &LumberjackWriteCloseFixer{Writer: &lumberjack.Logger{ Filename: loc, MaxSize: 5, // MB // Without this, rotated logs will never be deleted. MaxBackups: 1, - } + }} closers = append(closers, logWriter.Close) sinks = append(sinks, sinkFn(logWriter)) } @@ -210,3 +211,30 @@ func (f *debugFilterSink) Sync() { sink.Sync() } } + +// LumberjackWriteCloseFixer is a wrapper around an io.WriteCloser that +// prevents writes after Close. This is necessary because lumberjack +// re-opens the file on Write. +type LumberjackWriteCloseFixer struct { + Writer io.WriteCloser + mu sync.Mutex // Protects following. + closed bool +} + +func (c *LumberjackWriteCloseFixer) Close() error { + c.mu.Lock() + defer c.mu.Unlock() + + c.closed = true + return c.Writer.Close() +} + +func (c *LumberjackWriteCloseFixer) Write(p []byte) (int, error) { + c.mu.Lock() + defer c.mu.Unlock() + + if c.closed { + return 0, io.ErrClosedPipe + } + return c.Writer.Write(p) +}