@@ 1,15 1,13 @@
package main
import (
- "log/slog"
"os"
- "time"
"github.com/vaughan0/go-ini"
"go.bigb.es/auxilia/scribe"
- "sourcecraft.dev/bigbes/sr-ht-core/config"
+ "sourcecraft.dev/bigbes/sr-ht-ecore/logging"
)
// setupLogging installs the process-wide slog handler.
@@ 23,38 21,39 @@ import (
// without a level, without source positions, and above all without the masking
// below.
//
-// The level comes from [dolt.sr.ht]log-level ("debug", "info", "warn",
-// "error"); an unreadable value is info, because a daemon that refused to boot
-// over a typo in a log level would be trading an operator's whole service for
-// their logging preference.
+// The policy is sr-ht-ecore's and the handler is ours, which is the split that
+// package documents: the level, the colour decision and — the part that is not
+// presentation — the set of attribute keys that must never reach a log file are
+// facts about this instance and are maintained once, while the handler that
+// spends them stays here, because a service wanting a JSON handler for a log
+// shipper should not have to link a tinting one to share a mask list.
+//
+// The verbosity is [dolt.sr.ht]log-level ("debug", "info", "warn", "error") as
+// before, and now also $LOG_LEVEL and the -d every SourceHut daemon takes. -d is
+// resolved here rather than left to server.New because server.New runs after
+// config loading and validation: a daemon that becomes verbose only once it has
+// started is silent for exactly the window an operator passes -d to watch. An
+// unreadable value is info, because a daemon that refused to boot over a typo in
+// a log level would be trading an operator's whole service for their logging
+// preference.
func setupLogging(conf ini.File) {
- var level slog.Level
- if err := level.UnmarshalText([]byte(config.GetString(conf, serviceName, "log-level", "info"))); err != nil {
- level = slog.LevelInfo
- }
+ opts := logging.Defaults(conf, serviceName)
- slog.SetDefault(slog.New(scribe.NewTintHandler(
+ logging.Install(scribe.NewTintHandler(
scribe.WithWriter(os.Stderr),
- scribe.WithLevel(level),
- scribe.WithSource(true),
- scribe.WithTimeFormat(time.DateTime),
+ scribe.WithLevel(opts.Level),
+ scribe.WithSource(opts.AddSource),
+ scribe.WithTimeFormat(opts.TimeFormat),
// Colour is for a terminal; under systemd or a container's log
// collector the escapes are noise in the journal.
- scribe.WithNoColor(!isTerminal(os.Stderr)),
+ scribe.WithNoColor(!opts.Color),
// The masks are keyed on the attribute *path*, not on the message, so
// they cost nothing in prose and cannot be defeated by a sentence that
- // happens to contain the word "token". These three are the credentials
- // this service handles: the unified-login cookie, the "Internal"
- // service-to-service fernet token and the Authorization header the
- // remotesapi interceptors read a PAT or a keypair JWT out of.
- scribe.WithMaskKeys("token", "cookie", "authorization"),
- scribe.WithMask(`(?i)(secret|token|api_?key|password|pubkey|credential)`, "***"),
- )))
-}
-
-// isTerminal reports whether f is a character device, which is the whole of
-// what the colour decision needs and does not require a dependency to answer.
-func isTerminal(f *os.File) bool {
- info, err := f.Stat()
- return err == nil && info.Mode()&os.ModeCharDevice != 0
+ // happens to contain the word "token". Taking the instance's list rather
+ // than this service's three adds the keys the siblings had learned to
+ // redact and this one had not — the network and webhook private keys out
+ // of config.ini, and the migration DSN, which carries a password.
+ scribe.WithMaskKeys(opts.MaskKeys...),
+ scribe.WithMask(opts.MaskPattern, opts.MaskReplacement),
+ ))
}
@@ 42,6 42,10 @@ migrate-on-upgrade=yes
; Verbosity of the daemon's structured log: debug, info, warn or error. An
; unreadable value is read as info rather than refusing to boot — a typo in a
; logging preference must not cost the service.
+;
+; This is the persistent setting. For one run, $LOG_LEVEL overrides it and the
+; -d flag overrides both — and both apply from the first line of startup, before
+; the config below has been read.
log-level=info
; ---------------------------------------------------------------------------