Skip to content

Commit 363aa35

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

File tree

16 files changed

+148
-60
lines changed

16 files changed

+148
-60
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: 5 additions & 5 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.
@@ -106,8 +107,7 @@ Use a YAML configuration file when your server launch become unwieldy.
106107
--trace-logs bool, $CODER_TRACE_LOGS
107108
Enables capturing of logs as events in traces. This is useful for
108109
debugging, but may result in a very large amount of events being sent
109-
to the tracing backend which may incur significant costs. If the
110-
verbose flag was supplied, debug-level logs will be included.
110+
to the tracing backend which may incur significant costs.
111111

112112
--trace bool, $CODER_TRACE_ENABLE
113113
Whether application tracing data is collected. It exports to a backend

cli/testdata/server-config.yaml.golden

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,14 +183,17 @@ introspection:
183183
enable: false
184184
# Enables capturing of logs as events in traces. This is useful for debugging, but
185185
# may result in a very large amount of events being sent to the tracing backend
186-
# which may incur significant costs. If the verbose flag was supplied, debug-level
187-
# logs will be included.
186+
# which may incur significant costs.
188187
# (default: <unset>, type: bool)
189188
captureLogs: false
190189
logging:
191190
# Output debug-level logs.
192191
# (default: <unset>, type: bool)
193192
verbose: false
193+
# Filter debug logs by matching against a given regex. Use .* to match all debug
194+
# logs.
195+
# (default: <unset>, type: string-array)
196+
filter: []
194197
# Output human-readable logs to a given file.
195198
# (default: /dev/stderr, type: string)
196199
humanPath: /dev/stderr

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: 22 additions & 9 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",
@@ -1159,7 +1170,7 @@ when required by your organization's security policy.`,
11591170
},
11601171
{
11611172
Name: "Capture Logs in Traces",
1162-
Description: "Enables capturing of logs as events in traces. This is useful for debugging, but may result in a very large amount of events being sent to the tracing backend which may incur significant costs. If the verbose flag was supplied, debug-level logs will be included.",
1173+
Description: "Enables capturing of logs as events in traces. This is useful for debugging, but may result in a very large amount of events being sent to the tracing backend which may incur significant costs.",
11631174
Flag: "trace-logs",
11641175
Env: "CODER_TRACE_LOGS",
11651176
Value: &c.Trace.CaptureLogs,
@@ -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.

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy