I'm actually +1 on the proposal as written (sorry for chiming in late), though I agree recordError might make sense to remove.
Before we add the error parameter to LogHandler, however, I think we should pause for a second and consider the consequences.
Generally, these API packages (Swift Log/Metrics/Tracing) promise moving from M * N (every library needs to support every logging backend explicitly) to M + N (every library works with every logging backend). In other words, we need to avoid creating an API that couples specific libraries to specific LogHandlers. Why? Because it breaks the ecosystem - suddenly we'll have library maintainers recommending a list of "blessed" LogHandlers in their README, with which their library works correctly. We'll lose M + N, and we'll go back to ~M * N. I think that'd be a step backwards in the ecosystem's interoperability.
When we look at what the Error protocol is - it's just a Sendable Any with special handling by the compiler. But it provides no actual methods to extract information. This proposal, as-is, took a pragmatic approach of extracting 1) the type and 2) the stringified representation (allowing errors to conform to CustomStringConvertible to take control over that output). Now, if we're saying every LogHandler will only extract these two fields, then we can just do it, as proposed, at the Logger level, and LogHandlers don't need to change anything and benefit right away.
However, it sounds like that's not what would happen; rather specific LogHandlers would dynamically cast that error parameter into various apriori known error types, and handle them specially. That would give us code like this in LogHandlers:
import Foo
import Bar
struct MyLogHandler: LogHandler {
func log(..., error: any Error, ...) {
if let fooError = error as? Foo.FooError {
// extract specific Foo.FooError properties
} else if let barError = error as? Bar.BarError {
// extract specific Bar.BarError properties
} else {
// default handling, extract type and message, at most
}
}
}
While the above might seem okay, or even desirable, it basically breaks the point of the LogHandler protocol and the N + M promise from earlier. The LogHandler suddenly needs to start directly depending on important ecosystem libraries (doesn't matter if from the toolchain or as a package dependency) just to be able to inspect their specific errors, creating a leaky abstraction that undermines type safety of Swift Log.
Passing the Error to the LogHandler is functionally equivalent to passing an opaque "context" object, like:
import Foo
import Bar
struct MyLogHandler: LogHandler {
func log(..., context: any Sendable, ...) {
if let foo = context as? Foo.FooContext {
// extract specific Foo properties
} else if let bar = error as? Bar.BarContext {
// extract specific Bar properties
} else {
// default handling, extract type and message, at most
}
}
}
But in the Swift ecosystem, we've successfully pushed back against passing void* context around, because while it appears to be flexible, it only results in coupling the two sides of the abstraction that are passing such a void * object.
So while an attractive "quick fix", I think it's the wrong model for the long term health of our API packages.
These are the reasons why I'm a strong -1 on poking a hole through LogHandler, as it removes the incentive to work on improving the abstraction itself, and instead it lets anyone pass arbitrary data through it, resulting in creating fractures in the "Swift Log ecosystem", as no longer will every library work with every LogHandler, instead there will appear these implicit, undocumented contracts between specific libraries and specific LogHandlers. And I think that would be a significant regression for the overall ecosystem.
My suggestion would be to evaluate the proposal as written on its own merits, of whether we want a utility on Logger for storing metadata about an Error in publicly documented metadata keys. The community can decide whether that's worth it or not, I'm personally a +1 on that.
Then there can be a separate proposal for poking a hole through LogHandler, however I think I've made my position clear on why I'd be a strong -1 on that. And I'd definitely recommend we don't try to turn the former into the latter, let's use a separate proposal.