Logging std::error::Errors #357
Labels
No labels
bug
duplicate
easy
enhancement
help wanted
invalid
question
rfc
structured-logging
wontfix
No milestone
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
gh-rust-lang/log#357
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
It would be really nice to have a specialized way of logging errors that implement
std::error::Error.This would allow automatically capturing detailed information about an error, including the
DisplayandDebugrepresentations, and especially backtraces via the newError::backtrace, which has an open PR.The main purpose is to give the backend implementation the option to extract all desired information about an error and use it as appropriate for the output.
Not sure how this could fit into the current design, but I'd imagine an additional method on
Logand a macro.Plus a macro.
Naming for that macro would of course be somewhat awkward, considering
error!exists. Maybewith_error!(). Also there could be a variant oferror!that allows specifying an error value.One could of course ask if this is really necessary, since you could already write a custom macro or method that captures the required information as a
Record. But I'd like to see a standardized way of doing this that gives the logger implementation the power to do what it wants, without forcing the user to make a decision here up-front.Personally, I think treating errors as first-class concepts in logs is a worthwhile thing to do. It looks like we might not have given this too much thought in the past, but now that the
std::error::Errortype is more useful and backtrace support is in the works it could be a good time to consider it.We could add something like a
fn source(&self) -> Option<&(dyn Error + 'static)>method toRecordalong with macro support similar to howtargetwas added:Alternatively we could design support into the key-values API and leave it up to convention to capture an error with a common key name. That would probably be my preferred approach, because it would avoid creating too many parallel syntaxes in the
log!macros.I like the
source: errsyntax. Together with addingRecord::source()this would also enable attaching an error to all the macros, and prevent clutter.The ability to log an error without providing an additional message would also be nice though.
Yep, I definitely agree that it makes sense to allow Errors to be tacked onto log records - it will be a field that's only available with the
stdfeature, but that should be fine.I thought a missing
Sendbound on theErrorcould be a problem for async loggers that ship the record to a different thread. But then I noticed thatRecordalready is notSend.How is that dealt with in, eg,
slog? (cc @dpc)I've explicitly mentioned that Send and Sync is something to consider for the future, but I don't think anyone followed up on that. In
slogthere are these explicitly built contexts that are Arced so they can be sent cheaply. The idea is that they are more permanent, so they take an upfront cost during creation to be cheaper during normal operations. The immediate key-values and stuff inRecords are borrowed, butslogrequires them to be Send andjust clones/copies/kind-of-serializes them. The idea here is that they are more ad-hoc and should be generally smaller, so cost of the clone is OK.I think it is worthwhile to investigate and built an async logger for
logto iron out the async story. IfRecordhad an explicit field for errors, then it could require them to be sync and avoid copying. Similiarily ifloghad more general way to group borrowed ad-hoc vs owned and Arced more persistent data, then some optimizations around these would be possible.For reference:
github.com/slog-rs/async@e33823ceb8/lib.rs (L448)This seems reasonable approach that could be done without additional support from the
logcrate (pending #353). I've been exploring some other conventions inlog-types, and this seems like it would work as part of that.We're on board with adding specific support for
std::error::Errortolog. There's a PR open at #378 with some initial support that allows you to attach an error to aRecord.For
Send, sincelogalready makes no direct concessions to allowingRecords to be passed across thread boundaries it isn't going to be required here. You can, however, downcast astd::error::Error, so if your application needed to capture a sendable structured representation of the record then you could downcast it to the kind of error you expect to see at that point.There is some space to explore about macro support though. I think all log levels should support accepting an error, because not every error you encounter is necessarily an error-worthy log. You might want to log them as warnings or debug if they're non-critical. We could follow the same approach as
target, by allowing another kind of optional special field before the format arguments:We are looking at adding error logging inside AWS Lambda Runtime for Rust (https://github.com/awslabs/aws-lambda-rust-runtime/issues/241). The plan was to use Display trait, but that means the user would have to implement it, potentially more than once. Having a standard way of logging
std::error::Errorwould make it easier for our users.Looks like the work on this issue stalled.
Is there something I can help with to get it released?
Could some of this now be handled with log's builtin structured logging interfaces?
Hey @rimutaka 👋
The blocker for
log’s stable API is macro support. To fit in with the existing syntax it would probably look something like:we could cobble that in with some liberal duplication to the macros, but would be better off converting
log!to a tt muncher that could handle any combination oftarget,sourceandlevel. In the past we’ve found changing the macros to be tricky, but the scope of this should be reasonably small.There’s nothing blocking support in the unstable structured API, like @softprops mentioned. We could add
Value::from_errorandValue::as_errormethods at any time.The latter seems to keep the surface area small.
error!("whoops", { error: e })you get the reuse the same syntax for the same semantic purpose, annotating a log message with additional information. You get to pick the name for that information,logserializes it@softprops That would be much nicer, but we've had trouble in the past attempting to wrangle new syntax into the macros, especially after the message string, because currently that whole lot is shelled straight off to
format_argsas a bag of tokens. Things break in strange ways.Until we can come up with entirely new macros (I've been prototyping some stuff in this repo) I think we'll have to attach the error at the front, before the message.
Heads up: I've recently contributed
std::error::Errorimplementation intoslogunaware of this issue here. I hopelogcan be interoperable with that and I didn't cause some catastrophic incompatibility.@Kixunil No sweat! It looks like the
&dyn (std::error::Error + 'static)type you've used inslogshould be compatible with bothlogandtracing, which also use&dyn (Error + 'static).That's great! I don't follow
slog/loginterop efforts closely, which one will be responsible for connecting them together?