6 个稳定版本
1.0.7 | 2023年7月31日 |
---|---|
1.0.5 | 2023年7月30日 |
1.0.4 | 2023年5月17日 |
1.0.3 | 2023年5月16日 |
1.0.2 | 2023年5月12日 |
#336 在 Rust 模式
在 doc-sync 中使用
25KB
52 行
问题
如果您想记录错误发生时以及错误原因,您可能会发现自己在每个可能出现的错误上使用 match 语句,而不是使用 ?
操作符。
这会导致代码非常冗长。编写和维护都很痛苦。
现在介绍 wrap-match!
wrap-match 是一个属性宏,可以将您的函数包装在 match 语句中。此外,它还将在所有使用 ?
操作符(即 try 表达式)的语句中附加丰富的错误信息。
wrap-match 支持日志和跟踪。它默认使用日志,但如果启用了跟踪功能,它将使用跟踪。有关更多信息,请参阅 tracing
支持。
注意
wrap-match 使用
log
或tracing
crate 来记录成功和错误消息。它不公开log
或tracing
crate 以供展开函数使用;您必须自己依赖它们。此外,除非您使用日志实现或
tracing
订阅者,否则不会显示任何消息。 对于log
,我推荐env_logger
,但您可以在 此处 找到完整的列表。对于tracing
,我推荐tracing-subscriber
,但您可以在 此处 找到完整的列表。
示例
首先,将以下内容添加到您的 Cargo.toml
[dependencies]
# For log users:
wrap-match = "1"
log = "*"
# You'll also want a logging implementation, for example `env_logger`
# More info here: https://docs.rs/log/#available-logging-implementations
# For tracing users:
wrap-match = { version = "1", features = ["tracing"] }
tracing = "0.1"
# You'll also want a `tracing` subscriber, for example `tracing-subscriber`
# More info here: https://docs.rs//tracing/#related-crates
现在您可以使用 wrap_match
属性宏
#[wrap_match::wrap_match]
fn my_function() -> Result<(), CustomError> {
Err(CustomError::Error)?; // notice the ?; when the macro is expanded, it will be modified to include line number and expression
// If you need to return an error, just do `Err(CustomError::Error.into())`
Ok(())
}
这将扩展为类似以下的内容(通常不包括注释,并且部分输出已简化;如果您想了解宏实际扩展的内容,请使用cargo-expand
)
fn my_function() -> Result<(), CustomError> {
// This is where the original function is
fn _wrap_match_inner_my_function() -> Result<(), WrapMatchError<CustomError>> {
Err(CustomError::Error)
.map_err(|e| WrapMatchError {
// Here, line number and expression are added to the error
line_and_expr: Some((3, "Err(CustomError::Error)")),
inner: e.into(), // This is so you can have `Box<dyn Error>` as your error type
})?;
// If you need to return an error, just do `Err(CustomError::Error.into())`
Ok(())
}
match _wrap_match_inner_my_function() {
Ok(r) => {
::log::info!("Successfully ran my_function"); // when the tracing feature is enabled, it will use tracing macros instead
Ok(r)
}
Err(e) => {
if let Some((_line, _expr)) = e.line_and_expr {
::log::error!("An error occurred when running my_function (when running `{_expr}` on line {_line}): {:?}", e.inner); // when the tracing feature is enabled, it will use tracing macros instead
} else {
::log::error!("An error occurred when running my_function: {:?}", e.inner); // when the tracing feature is enabled, it will use tracing macros instead
}
Err(e.inner)
}
}
}
如果我们运行此代码,它将记录以下内容
[ERROR] An error occurred when running my_function (when running `Err(CustomError::Error)` on line 3): Error
如您所见,wrap-match使错误日志非常容易,同时还能记录导致错误的信息。
tracing
支持
从wrap-match 1.0.5版本开始,wrap-match支持tracing
,前提是启用了tracing
功能。wrap-match 不会对span进行任何操作。此外,您将无法在应用wrap-match的功能中手动创建span。这是因为span将在wrap-match记录任何内容之前被丢弃。
要将函数和wrap-match的日志放入一个span中,您必须使用tracing::instrument
属性宏。属性宏的顺序很重要;它必须在wrap-match之后。
示例
#[wrap_match::wrap_match(success_message = "still in span!")]
#[tracing::instrument] // IMPORTANT: after wrap-match!
fn my_function() -> Result<(), ()> {
tracing::info!("hello from tracing!");
Ok(())
}
自定义
wrap-match允许用户自定义成功和错误消息,以及选择是否在成功时记录任何内容。
success_message
成功时记录的消息。
可用的格式参数
function
:原始函数名称。注意:您只能使用{function}
;不支持其他格式,如{function:?}
。- 函数参数
默认值:Successfully ran {function}
示例
#[wrap_match::wrap_match(success_message = "{function} ran successfully!! 🎉🎉")]
fn my_function() -> Result<(), CustomError> {
Ok(())
}
这将记录以下内容
[INFO] my_function ran successfully!! 🎉🎉
error_message
当行和表达式信息可用时,记录错误时的消息。目前,这仅适用于try表达式(有?
的语句)。
可用的格式参数
function
:原始函数名称。注意:您只能使用{function}
;不支持其他格式,如{function:?}
。line
:错误发生的行。expr
:导致错误的表达式。error
:错误。- 函数参数
默认值:An error occurred when running {function} (caused by `{expr}` on line `{line}): `{error:?}
示例
#[wrap_match::wrap_match(error_message = "oh no, {function} failed! `{expr}` on line {line} caused the error: {error:?}")]
fn my_function() -> Result<(), CustomError> {
Err(CustomError::Error)?;
Ok(())
}
这将记录以下内容
[ERROR] oh no, my_function failed! `Err(CustomError::Error)` on line 3 caused the error: Error
error_message_without_info
当行和表达式信息不可用时,记录错误时的消息。这通常在您自己返回错误并使用.into()
时触发。
可用的格式参数
function
:原始函数名称。注意:您只能使用{function}
;不支持其他格式,如{function:?}
。error
:错误。- 函数参数
默认值:An error occurred when running {function}: `{error:?}
示例
#[wrap_match::wrap_match(error_message_without_info = "oh no, {function} failed with this error: {error:?}")]
fn my_function() -> Result<(), CustomError> {
Err(CustomError::Error.into())
}
这将记录以下内容
[ERROR] oh no, my_function failed with this error: Error
log_success
如果设置为false
,则在成功时不会记录任何内容。
默认值:true
示例
#[wrap_match::wrap_match(log_success = false)]
fn my_function() -> Result<(), CustomError> {
Ok(())
}
这将不记录任何内容。
disregard_result
如果 true
,则生成的函数将返回 ()
并丢弃 Result
的任何内容。对于 main
函数很有用。
默认值:false
示例
#[wrap_match::wrap_match(disregard_result = true)]
fn main() -> Result<(), CustomError> {
Ok(())
}
main
函数将被转换为以下形式
fn main() {
fn _wrap_match_inner_main() -> Result<(), WrapMatchError<CustomError>> {
Ok(())
}
match _wrap_match_inner_main() {
// the Result would be logged like normal, but it is not returned
}
}
在消息中使用函数参数
从 wrap-match 1.0.5 版本开始,您可以在消息中使用函数参数,只要它们没有被移动/丢弃。您应该只为引用和实现 Copy
的项使用此功能。
示例
#[wrap_match::wrap_match(success_message = "Success! input = {input}")]
fn my_function(input: i64) -> Result<i64, ()> {
Ok(input)
}
限制
wrap-match 当前有以下限制
-
wrap-match 无法用于接受现在已支持!但是,这需要 wrap-match 将内部函数移出生成的函数,因此它将在实现中添加一个新方法。此方法被标记为已弃用,并设置为私有,不会在文档中显示。希望这不会引起任何问题。self
参数的函数实现。如果您需要支持此功能,请创建一个 GitHub 问题说明您的使用情况。 -
wrap-match 只支持
Result
。如果您需要支持Option
,请创建一个 GitHub 问题说明您的使用情况。 -
所有格式参数(除了error_message
和error_message_without_info
只支持使用Debug
或Display
格式化程序格式化error
。这是因为我们确定使用了哪些格式说明符。如果您需要支持其他格式说明符,请创建一个 GitHub 问题说明您的使用情况。function
)现在都支持format!
所支持的所有基本格式(然而,诸如精度、符号、填充、对齐和宽度等特性可能永远不会得到支持)。 -
wrap-match 无法用于
const
函数。这是因为log
crate 无法在const
上下文中使用。
如果 wrap-match 对本列表中未列出的内容不起作用,请创建一个 GitHub 问题!
依赖项
~0.5–1MB
~24K SLoC