mirror of
https://github.com/coder/coder.git
synced 2025-07-12 00:14:10 +00:00
feat: Add logging options for coder agent (#7474)
Similar to logging options in the coderd server, but for the agent running in workspaces. Meant to make hollistic log collection and querying simpler.
This commit is contained in:
86
cli/agent.go
86
cli/agent.go
@ -22,6 +22,8 @@ import (
|
|||||||
|
|
||||||
"cdr.dev/slog"
|
"cdr.dev/slog"
|
||||||
"cdr.dev/slog/sloggers/sloghuman"
|
"cdr.dev/slog/sloggers/sloghuman"
|
||||||
|
"cdr.dev/slog/sloggers/slogjson"
|
||||||
|
"cdr.dev/slog/sloggers/slogstackdriver"
|
||||||
"github.com/coder/coder/agent"
|
"github.com/coder/coder/agent"
|
||||||
"github.com/coder/coder/agent/reaper"
|
"github.com/coder/coder/agent/reaper"
|
||||||
"github.com/coder/coder/buildinfo"
|
"github.com/coder/coder/buildinfo"
|
||||||
@ -32,14 +34,17 @@ import (
|
|||||||
|
|
||||||
func (r *RootCmd) workspaceAgent() *clibase.Cmd {
|
func (r *RootCmd) workspaceAgent() *clibase.Cmd {
|
||||||
var (
|
var (
|
||||||
auth string
|
auth string
|
||||||
logDir string
|
logDir string
|
||||||
pprofAddress string
|
pprofAddress string
|
||||||
noReap bool
|
noReap bool
|
||||||
sshMaxTimeout time.Duration
|
sshMaxTimeout time.Duration
|
||||||
tailnetListenPort int64
|
tailnetListenPort int64
|
||||||
prometheusAddress string
|
prometheusAddress string
|
||||||
debugAddress string
|
debugAddress string
|
||||||
|
slogHumanPath string
|
||||||
|
slogJSONPath string
|
||||||
|
slogStackdriverPath string
|
||||||
)
|
)
|
||||||
cmd := &clibase.Cmd{
|
cmd := &clibase.Cmd{
|
||||||
Use: "agent",
|
Use: "agent",
|
||||||
@ -62,7 +67,46 @@ func (r *RootCmd) workspaceAgent() *clibase.Cmd {
|
|||||||
MaxSize: 5, // MB
|
MaxSize: 5, // MB
|
||||||
}
|
}
|
||||||
defer logWriter.Close()
|
defer logWriter.Close()
|
||||||
logger := slog.Make(sloghuman.Sink(inv.Stderr), sloghuman.Sink(logWriter)).Leveled(slog.LevelDebug)
|
|
||||||
|
sinks := []slog.Sink{sloghuman.Sink(logWriter)}
|
||||||
|
closers := []func() error{}
|
||||||
|
addSinkIfProvided := func(sinkFn func(io.Writer) slog.Sink, loc string) error {
|
||||||
|
switch loc {
|
||||||
|
case "":
|
||||||
|
|
||||||
|
case "/dev/stdout":
|
||||||
|
sinks = append(sinks, sinkFn(inv.Stdout))
|
||||||
|
|
||||||
|
case "/dev/stderr":
|
||||||
|
sinks = append(sinks, sinkFn(inv.Stderr))
|
||||||
|
|
||||||
|
default:
|
||||||
|
fi, err := os.OpenFile(loc, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0o644)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("open log file %q: %w", loc, err)
|
||||||
|
}
|
||||||
|
closers = append(closers, fi.Close)
|
||||||
|
sinks = append(sinks, sinkFn(fi))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := addSinkIfProvided(sloghuman.Sink, slogHumanPath); err != nil {
|
||||||
|
return xerrors.Errorf("add human sink: %w", err)
|
||||||
|
}
|
||||||
|
if err := addSinkIfProvided(slogjson.Sink, slogJSONPath); err != nil {
|
||||||
|
return xerrors.Errorf("add json sink: %w", err)
|
||||||
|
}
|
||||||
|
if err := addSinkIfProvided(slogstackdriver.Sink, slogStackdriverPath); err != nil {
|
||||||
|
return xerrors.Errorf("add stackdriver sink: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger := slog.Make(sinks...).Leveled(slog.LevelDebug)
|
||||||
|
defer func() {
|
||||||
|
for _, closer := range closers {
|
||||||
|
_ = closer()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
logger.Info(ctx, "spawning reaper process")
|
logger.Info(ctx, "spawning reaper process")
|
||||||
// Do not start a reaper on the child process. It's important
|
// Do not start a reaper on the child process. It's important
|
||||||
@ -290,6 +334,30 @@ func (r *RootCmd) workspaceAgent() *clibase.Cmd {
|
|||||||
Value: clibase.StringOf(&debugAddress),
|
Value: clibase.StringOf(&debugAddress),
|
||||||
Description: "The bind address to serve a debug HTTP server.",
|
Description: "The bind address to serve a debug HTTP server.",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "Human Log Location",
|
||||||
|
Description: "Output human-readable logs to a given file.",
|
||||||
|
Flag: "log-human",
|
||||||
|
Env: "CODER_AGENT_LOGGING_HUMAN",
|
||||||
|
Default: "/dev/stderr",
|
||||||
|
Value: clibase.StringOf(&slogHumanPath),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "JSON Log Location",
|
||||||
|
Description: "Output JSON logs to a given file.",
|
||||||
|
Flag: "log-json",
|
||||||
|
Env: "CODER_AGENT_LOGGING_JSON",
|
||||||
|
Default: "",
|
||||||
|
Value: clibase.StringOf(&slogJSONPath),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Stackdriver Log Location",
|
||||||
|
Description: "Output Stackdriver compatible logs to a given file.",
|
||||||
|
Flag: "log-stackdriver",
|
||||||
|
Env: "CODER_AGENT_LOGGING_STACKDRIVER",
|
||||||
|
Default: "",
|
||||||
|
Value: clibase.StringOf(&slogStackdriverPath),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
|
9
cli/testdata/coder_agent_--help.golden
vendored
9
cli/testdata/coder_agent_--help.golden
vendored
@ -3,6 +3,15 @@ Usage: coder agent [flags]
|
|||||||
Starts the Coder workspace agent.
|
Starts the Coder workspace agent.
|
||||||
|
|
||||||
[1mOptions[0m
|
[1mOptions[0m
|
||||||
|
--log-human string, $CODER_AGENT_LOGGING_HUMAN (default: /dev/stderr)
|
||||||
|
Output human-readable logs to a given file.
|
||||||
|
|
||||||
|
--log-json string, $CODER_AGENT_LOGGING_JSON
|
||||||
|
Output JSON logs to a given file.
|
||||||
|
|
||||||
|
--log-stackdriver string, $CODER_AGENT_LOGGING_STACKDRIVER
|
||||||
|
Output Stackdriver compatible logs to a given file.
|
||||||
|
|
||||||
--auth string, $CODER_AGENT_AUTH (default: token)
|
--auth string, $CODER_AGENT_AUTH (default: token)
|
||||||
Specify the authentication type to use for the agent.
|
Specify the authentication type to use for the agent.
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user