mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat(cli): support fine-grained server log filtering (#8748)
This commit is contained in:
+60
-7
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
[1mIntrospection / Prometheus Options[0m
|
||||
--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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user