feat(cli): support fine-grained server log filtering (#8748)

This commit is contained in:
Ammar Bandukwala
2023-07-26 16:46:22 -05:00
committed by GitHub
parent 4e9e480cc6
commit 25e30c6f41
16 changed files with 148 additions and 60 deletions
+60 -7
View File
@@ -334,7 +334,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
)
if cfg.AccessURL.String() == "" {
cliui.Infof(inv.Stderr, "Opening tunnel so workspaces can connect to your deployment. For production scenarios, specify an external access URL")
tunnel, err = devtunnel.New(ctx, logger.Named("devtunnel"), cfg.WgtunnelHost.String())
tunnel, err = devtunnel.New(ctx, logger.Named("net.devtunnel"), cfg.WgtunnelHost.String())
if err != nil {
return xerrors.Errorf("create tunnel: %w", err)
}
@@ -1751,6 +1751,50 @@ func IsLocalhost(host string) bool {
return host == "localhost" || host == "127.0.0.1" || host == "::1"
}
var _ slog.Sink = &filterSink{}
type filterSink struct {
next []slog.Sink
re *regexp.Regexp
}
func (f *filterSink) compile(res []string) error {
if len(res) == 0 {
return nil
}
var reb strings.Builder
for i, re := range res {
_, _ = fmt.Fprintf(&reb, "(%s)", re)
if i != len(res)-1 {
_, _ = reb.WriteRune('|')
}
}
re, err := regexp.Compile(reb.String())
if err != nil {
return xerrors.Errorf("compile regex: %w", err)
}
f.re = re
return nil
}
func (f *filterSink) LogEntry(ctx context.Context, ent slog.SinkEntry) {
logName := strings.Join(ent.LoggerNames, ".")
if f.re != nil && !f.re.MatchString(logName) {
return
}
for _, sink := range f.next {
sink.LogEntry(ctx, ent)
}
}
func (f *filterSink) Sync() {
for _, sink := range f.next {
sink.Sync()
}
}
func BuildLogger(inv *clibase.Invocation, cfg *codersdk.DeploymentValues) (slog.Logger, func(), error) {
var (
sinks = []slog.Sink{}
@@ -1795,16 +1839,25 @@ func BuildLogger(inv *clibase.Invocation, cfg *codersdk.DeploymentValues) (slog.
sinks = append(sinks, tracing.SlogSink{})
}
level := slog.LevelInfo
if cfg.Verbose {
level = slog.LevelDebug
}
// User should log to null device if they don't want logs.
if len(sinks) == 0 {
return slog.Logger{}, nil, xerrors.New("no loggers provided")
}
return slog.Make(sinks...).Leveled(level), func() {
filter := &filterSink{next: sinks}
err = filter.compile(cfg.Logging.Filter.Value())
if err != nil {
return slog.Logger{}, nil, xerrors.Errorf("compile filters: %w", err)
}
level := slog.LevelInfo
// Debug logging is always enabled if a filter is present.
if cfg.Verbose || filter.re != nil {
level = slog.LevelDebug
}
return slog.Make(filter).Leveled(level), func() {
for _, closer := range closers {
_ = closer()
}
+5 -5
View File
@@ -1305,7 +1305,7 @@ func TestServer(t *testing.T) {
root, _ := clitest.New(t,
"server",
"--verbose",
"--log-filter=.*",
"--in-memory",
"--http-address", ":0",
"--access-url", "http://example.com",
@@ -1322,7 +1322,7 @@ func TestServer(t *testing.T) {
root, _ := clitest.New(t,
"server",
"--verbose",
"--log-filter=.*",
"--in-memory",
"--http-address", ":0",
"--access-url", "http://example.com",
@@ -1339,7 +1339,7 @@ func TestServer(t *testing.T) {
root, _ := clitest.New(t,
"server",
"--verbose",
"--log-filter=.*",
"--in-memory",
"--http-address", ":0",
"--access-url", "http://example.com",
@@ -1359,7 +1359,7 @@ func TestServer(t *testing.T) {
inv, _ := clitest.New(t,
"server",
"--verbose",
"--log-filter=.*",
"--in-memory",
"--http-address", ":0",
"--access-url", "http://example.com",
@@ -1393,7 +1393,7 @@ func TestServer(t *testing.T) {
// HTTP.
inv, _ := clitest.New(t,
"server",
"--verbose",
"--log-filter=.*",
"--in-memory",
"--http-address", ":0",
"--access-url", "http://example.com",
+5 -5
View File
@@ -83,12 +83,13 @@ Use a YAML configuration file when your server launch become unwieldy.
--log-json string, $CODER_LOGGING_JSON
Output JSON logs to a given file.
-l, --log-filter string-array, $CODER_LOG_FILTER
Filter debug logs by matching against a given regex. Use .* to match
all debug logs.
--log-stackdriver string, $CODER_LOGGING_STACKDRIVER
Output Stackdriver compatible logs to a given file.
-v, --verbose bool, $CODER_VERBOSE
Output debug-level logs.
Introspection / Prometheus Options
--prometheus-address host:port, $CODER_PROMETHEUS_ADDRESS (default: 127.0.0.1:2112)
The bind address to serve prometheus metrics.
@@ -106,8 +107,7 @@ Use a YAML configuration file when your server launch become unwieldy.
--trace-logs bool, $CODER_TRACE_LOGS
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.
to the tracing backend which may incur significant costs.
--trace bool, $CODER_TRACE_ENABLE
Whether application tracing data is collected. It exports to a backend
+5 -2
View File
@@ -183,14 +183,17 @@ introspection:
enable: false
# 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.
# which may incur significant costs.
# (default: <unset>, type: bool)
captureLogs: false
logging:
# Output debug-level logs.
# (default: <unset>, type: bool)
verbose: false
# Filter debug logs by matching against a given regex. Use .* to match all debug
# logs.
# (default: <unset>, type: string-array)
filter: []
# Output human-readable logs to a given file.
# (default: /dev/stderr, type: string)
humanPath: /dev/stderr