Skip to content

Commit 698d22e

Browse files
committed
feat(cli): support fine-grained server log filtering
1 parent 6b92abe commit 698d22e

File tree

15 files changed

+139
-52
lines changed

15 files changed

+139
-52
lines changed

agent/agent.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -755,7 +755,7 @@ func (a *agent) createTailnet(ctx context.Context, agentID uuid.UUID, derpMap *t
755755
network, err := tailnet.NewConn(&tailnet.Options{
756756
Addresses: a.wireguardAddresses(agentID),
757757
DERPMap: derpMap,
758-
Logger: a.logger.Named("tailnet"),
758+
Logger: a.logger.Named("net.tailnet"),
759759
ListenPort: a.tailnetListenPort,
760760
BlockEndpoints: disableDirectConnections,
761761
})

cli/server.go

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
334334
)
335335
if cfg.AccessURL.String() == "" {
336336
cliui.Infof(inv.Stderr, "Opening tunnel so workspaces can connect to your deployment. For production scenarios, specify an external access URL")
337-
tunnel, err = devtunnel.New(ctx, logger.Named("devtunnel"), cfg.WgtunnelHost.String())
337+
tunnel, err = devtunnel.New(ctx, logger.Named("net.devtunnel"), cfg.WgtunnelHost.String())
338338
if err != nil {
339339
return xerrors.Errorf("create tunnel: %w", err)
340340
}
@@ -1751,6 +1751,50 @@ func IsLocalhost(host string) bool {
17511751
return host == "localhost" || host == "127.0.0.1" || host == "::1"
17521752
}
17531753

1754+
var _ slog.Sink = &filterSink{}
1755+
1756+
type filterSink struct {
1757+
next []slog.Sink
1758+
re *regexp.Regexp
1759+
}
1760+
1761+
func (f *filterSink) compile(res []string) error {
1762+
if len(res) == 0 {
1763+
return nil
1764+
}
1765+
1766+
var reb strings.Builder
1767+
for i, re := range res {
1768+
_, _ = fmt.Fprintf(&reb, "(%s)", re)
1769+
if i != len(res)-1 {
1770+
_, _ = reb.WriteRune('|')
1771+
}
1772+
}
1773+
1774+
re, err := regexp.Compile(reb.String())
1775+
if err != nil {
1776+
return xerrors.Errorf("compile regex: %w", err)
1777+
}
1778+
f.re = re
1779+
return nil
1780+
}
1781+
1782+
func (f *filterSink) LogEntry(ctx context.Context, ent slog.SinkEntry) {
1783+
logName := strings.Join(ent.LoggerNames, ".")
1784+
if f.re != nil && !f.re.MatchString(logName) {
1785+
return
1786+
}
1787+
for _, sink := range f.next {
1788+
sink.LogEntry(ctx, ent)
1789+
}
1790+
}
1791+
1792+
func (f *filterSink) Sync() {
1793+
for _, sink := range f.next {
1794+
sink.Sync()
1795+
}
1796+
}
1797+
17541798
func BuildLogger(inv *clibase.Invocation, cfg *codersdk.DeploymentValues) (slog.Logger, func(), error) {
17551799
var (
17561800
sinks = []slog.Sink{}
@@ -1795,16 +1839,25 @@ func BuildLogger(inv *clibase.Invocation, cfg *codersdk.DeploymentValues) (slog.
17951839
sinks = append(sinks, tracing.SlogSink{})
17961840
}
17971841

1798-
level := slog.LevelInfo
1799-
if cfg.Verbose {
1800-
level = slog.LevelDebug
1801-
}
1802-
1842+
// User should log to null device if they don't want logs.
18031843
if len(sinks) == 0 {
18041844
return slog.Logger{}, nil, xerrors.New("no loggers provided")
18051845
}
18061846

1807-
return slog.Make(sinks...).Leveled(level), func() {
1847+
filter := &filterSink{next: sinks}
1848+
1849+
err = filter.compile(cfg.Logging.Filter.Value())
1850+
if err != nil {
1851+
return slog.Logger{}, nil, xerrors.Errorf("compile filters: %w", err)
1852+
}
1853+
1854+
level := slog.LevelInfo
1855+
// Debug logging is always enabled if a filter is present.
1856+
if cfg.Verbose || filter.re != nil {
1857+
level = slog.LevelDebug
1858+
}
1859+
1860+
return slog.Make(filter).Leveled(level), func() {
18081861
for _, closer := range closers {
18091862
_ = closer()
18101863
}

cli/server_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1305,7 +1305,7 @@ func TestServer(t *testing.T) {
13051305

13061306
root, _ := clitest.New(t,
13071307
"server",
1308-
"--verbose",
1308+
"--log-filter=.*",
13091309
"--in-memory",
13101310
"--http-address", ":0",
13111311
"--access-url", "http://example.com",
@@ -1322,7 +1322,7 @@ func TestServer(t *testing.T) {
13221322

13231323
root, _ := clitest.New(t,
13241324
"server",
1325-
"--verbose",
1325+
"--log-filter=.*",
13261326
"--in-memory",
13271327
"--http-address", ":0",
13281328
"--access-url", "http://example.com",
@@ -1339,7 +1339,7 @@ func TestServer(t *testing.T) {
13391339

13401340
root, _ := clitest.New(t,
13411341
"server",
1342-
"--verbose",
1342+
"--log-filter=.*",
13431343
"--in-memory",
13441344
"--http-address", ":0",
13451345
"--access-url", "http://example.com",
@@ -1359,7 +1359,7 @@ func TestServer(t *testing.T) {
13591359

13601360
inv, _ := clitest.New(t,
13611361
"server",
1362-
"--verbose",
1362+
"--log-filter=.*",
13631363
"--in-memory",
13641364
"--http-address", ":0",
13651365
"--access-url", "http://example.com",
@@ -1393,7 +1393,7 @@ func TestServer(t *testing.T) {
13931393
// HTTP.
13941394
inv, _ := clitest.New(t,
13951395
"server",
1396-
"--verbose",
1396+
"--log-filter=.*",
13971397
"--in-memory",
13981398
"--http-address", ":0",
13991399
"--access-url", "http://example.com",

cli/testdata/coder_server_--help.golden

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,13 @@ Use a YAML configuration file when your server launch become unwieldy.
8383
--log-json string, $CODER_LOGGING_JSON
8484
Output JSON logs to a given file.
8585

86+
-l, --log-filter string-array, $CODER_LOG_FILTER
87+
Filter debug logs by matching against a given regex. Use .* to match
88+
all debug logs.
89+
8690
--log-stackdriver string, $CODER_LOGGING_STACKDRIVER
8791
Output Stackdriver compatible logs to a given file.
8892

89-
-v, --verbose bool, $CODER_VERBOSE
90-
Output debug-level logs.
91-
9293
Introspection / Prometheus Options
9394
--prometheus-address host:port, $CODER_PROMETHEUS_ADDRESS (default: 127.0.0.1:2112)
9495
The bind address to serve prometheus metrics.

coderd/apidoc/docs.go

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/apidoc/swagger.json

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/workspaceagents.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -691,7 +691,7 @@ func (api *API) _dialWorkspaceAgentTailnet(agentID uuid.UUID) (*codersdk.Workspa
691691
conn, err := tailnet.NewConn(&tailnet.Options{
692692
Addresses: []netip.Prefix{netip.PrefixFrom(tailnet.IP(), 128)},
693693
DERPMap: api.DERPMap(),
694-
Logger: api.Logger.Named("tailnet"),
694+
Logger: api.Logger.Named("net.tailnet"),
695695
BlockEndpoints: api.DeploymentValues.DERP.Config.BlockDirect.Value(),
696696
})
697697
if err != nil {

codersdk/deployment.go

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -340,9 +340,10 @@ type SwaggerConfig struct {
340340
}
341341

342342
type LoggingConfig struct {
343-
Human clibase.String `json:"human" typescript:",notnull"`
344-
JSON clibase.String `json:"json" typescript:",notnull"`
345-
Stackdriver clibase.String `json:"stackdriver" typescript:",notnull"`
343+
Filter clibase.StringArray `json:"log_filter" typescript:",notnull"`
344+
Human clibase.String `json:"human" typescript:",notnull"`
345+
JSON clibase.String `json:"json" typescript:",notnull"`
346+
Stackdriver clibase.String `json:"stackdriver" typescript:",notnull"`
346347
}
347348

348349
type DangerousConfig struct {
@@ -533,6 +534,16 @@ when required by your organization's security policy.`,
533534
Group: &deploymentGroupNetworking,
534535
YAML: "redirectToAccessURL",
535536
}
537+
logFilter := clibase.Option{
538+
Name: "Log Filter",
539+
Description: "Filter debug logs by matching against a given regex. Use .* to match all debug logs.",
540+
Flag: "log-filter",
541+
FlagShorthand: "l",
542+
Env: "CODER_LOG_FILTER",
543+
Value: &c.Logging.Filter,
544+
Group: &deploymentGroupIntrospectionLogging,
545+
YAML: "filter",
546+
}
536547
opts := clibase.OptionSet{
537548
{
538549
Name: "Access URL",
@@ -1249,12 +1260,14 @@ when required by your organization's security policy.`,
12491260
Flag: "verbose",
12501261
Env: "CODER_VERBOSE",
12511262
FlagShorthand: "v",
1252-
1253-
Value: &c.Verbose,
1254-
Group: &deploymentGroupIntrospectionLogging,
1255-
YAML: "verbose",
1256-
Annotations: clibase.Annotations{}.Mark(annotationExternalProxies, "true"),
1263+
Hidden: true,
1264+
UseInstead: []clibase.Option{logFilter},
1265+
Value: &c.Verbose,
1266+
Group: &deploymentGroupIntrospectionLogging,
1267+
YAML: "verbose",
1268+
Annotations: clibase.Annotations{}.Mark(annotationExternalProxies, "true"),
12571269
},
1270+
logFilter,
12581271
{
12591272
Name: "Human Log Location",
12601273
Description: "Output human-readable logs to a given file.",

docs/api/general.md

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/api/schemas.md

Lines changed: 9 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/cli/server.md

Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

enterprise/cli/testdata/coder_server_--help.golden

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,13 @@ Use a YAML configuration file when your server launch become unwieldy.
8383
--log-json string, $CODER_LOGGING_JSON
8484
Output JSON logs to a given file.
8585

86+
-l, --log-filter string-array, $CODER_LOG_FILTER
87+
Filter debug logs by matching against a given regex. Use .* to match
88+
all debug logs.
89+
8690
--log-stackdriver string, $CODER_LOGGING_STACKDRIVER
8791
Output Stackdriver compatible logs to a given file.
8892

89-
-v, --verbose bool, $CODER_VERBOSE
90-
Output debug-level logs.
91-
9293
Introspection / Prometheus Options
9394
--prometheus-address host:port, $CODER_PROMETHEUS_ADDRESS (default: 127.0.0.1:2112)
9495
The bind address to serve prometheus metrics.

enterprise/wsproxy/wsproxy.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -178,19 +178,19 @@ func New(ctx context.Context, opts *Options) (*Server, error) {
178178
ServerName: opts.AccessURL.Hostname(),
179179
}
180180

181-
derpServer := derp.NewServer(key.NewNode(), tailnet.Logger(opts.Logger.Named("derp")))
181+
derpServer := derp.NewServer(key.NewNode(), tailnet.Logger(opts.Logger.Named("net.derp")))
182182

183183
ctx, cancel := context.WithCancel(context.Background())
184184
r := chi.NewRouter()
185185
s := &Server{
186186
Options: opts,
187187
Handler: r,
188188
DashboardURL: opts.DashboardURL,
189-
Logger: opts.Logger.Named("workspace-proxy"),
189+
Logger: opts.Logger.Named("net.workspace-proxy"),
190190
TracerProvider: opts.Tracing,
191191
PrometheusRegistry: opts.PrometheusRegistry,
192192
SDKClient: client,
193-
derpMesh: derpmesh.New(opts.Logger.Named("derpmesh"), derpServer, meshTLSConfig),
193+
derpMesh: derpmesh.New(opts.Logger.Named("net.derpmesh"), derpServer, meshTLSConfig),
194194
ctx: ctx,
195195
cancel: cancel,
196196
}

site/src/api/typesGenerated.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,8 @@ export interface LinkConfig {
550550

551551
// From codersdk/deployment.go
552552
export interface LoggingConfig {
553+
// This is likely an enum in an external package ("github.com/coder/coder/cli/clibase.StringArray")
554+
readonly log_filter: string[]
553555
readonly human: string
554556
readonly json: string
555557
readonly stackdriver: string

0 commit comments

Comments
 (0)