package main import ( "os" "github.com/vaughan0/go-ini" "go.bigb.es/auxilia/scribe" "sourcecraft.dev/bigbes/sr-ht-ecore/logging" ) // setupLogging installs the process-wide slog handler. // // It sets the *default* logger rather than building one to thread through // constructors, and that is the point rather than a shortcut. sr-ht-ecore's // middleware reports a recovered panic through slog's default; so does every // library package in this service that has no constructor to be handed a logger // through (authn's cookie and JWT resolvers, the web renderer). A daemon that // skipped this call would still log all of it — into Go's plain stderr handler, // without a level, without source positions, and above all without the masking // below. // // 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) { opts := logging.Defaults(conf, serviceName) logging.Install(scribe.NewTintHandler( scribe.WithWriter(os.Stderr), 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(!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". 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), )) }