This reminds me a little of SwiftUI's Environment
and Dispatch's QoS
, both of which propagate information down into callers, potentially through intermediate layers that don't understand the context.
Personally I'd be interested in a language-level solution so that everyone isn't making up their own incompatible tool. Just spitballing here, but vaguely like
//Framework.swift
@threadscoped var activeLogger = DefaultLogger()
public func connectToDatabase() {
activeLogger.log("Connecting to database...")
}
//main.swift
import Framework
//will log with the default logger
connectToDatabase()
with activeLogger = CustomLogger() {
connectToDatabase() //will log with custom logger
}
The advantage of thread storage is you can trampoline the context between a high-level caller and any number of intermediate function calls, that may not know/care about participating in a context-passing-bucket-brigrade.
The advantage of a language feature is that packages that desire to coordinate on a context can do so. For example, if activeLogger
is defined somewhere convenient (stdlib or a popular package), everyone can log into that, and at top level a specific logger might be chosen. For a web framework this might be a new logger per-request, for an app it might separate by subsystem, etc.