4 个版本
0.2.2 | 2024 年 2 月 29 日 |
---|---|
0.2.1 | 2024 年 2 月 22 日 |
0.2.0 | 2024 年 2 月 22 日 |
0.1.0 | 2024 年 2 月 19 日 |
在 调试 类别中排名 #129
每月下载次数为 178 次
160KB
2.5K SLoC
unwind-context
通过添加简单的宏,使 unwind-context
crate 简化了 panic 的调试过程,并添加了带颜色的 panic 上下文。
简介
在 Rust 中,panic 通常用于发生不可恢复错误或编写示例、原型代码或测试时。
但是,确定 panic 的确切原因可能很困难,尤其是如果它发生在代码深处或循环中。虽然添加日志记录可能会有所帮助,但这可能会导致大量日志条目,从而难以识别与 panic 相关的条目。
关于
此 crate 的目标是通过简单的方式添加 panic 上下文,并使上下文本身足够详细和易于阅读。相应地,它还简化了在测试中添加断言上下文的过程。此 crate 提供了 unwind_context
和 debug_unwind_context
宏以及其他辅助类型、特性和函数,帮助您定义函数或作用域上下文并将其写入 std::io::stderr
或其他可写入目标,如果发生 panic。如果发生 panic,上下文将在解构过程中以“逆”时间顺序写入。
除非函数发生 panic,否则此库对编译函数的额外开销非常小
- 首先,它会在堆栈上构建一个包含上下文数据、代码位置、编写器和颜色方案的结构的结构。如果指定,它还会存储自定义 panic 检测器的引用。
- 当删除这个“上下文作用域保护”结构时,其析构函数会检查
std::thread::panicking
并在检测到 panic 时调用冷打印函数。
这个crate旨在用于诊断。panic时打印的消息的确切内容和格式没有指定,但应清晰简洁。
注意,只有在将 panic
设置为 unwind
时,上下文才会被打印,这是 dev
和 release
配置的默认值。
用法
首先,将以下内容添加到您的 Cargo.toml
[dependencies]
unwind-context = "0.2.2"
然后,将带有给定函数参数或作用域参数的宏调用添加到要跟踪的函数的开头,并将结果绑定到某个作用域变量(否则 unwind 上下文作用域保护将立即被丢弃)
use unwind_context::unwind_context;
fn func1(a: u32, b: &str, c: bool) {
let _ctx = unwind_context!(fn(a, b, c));
// ...
for i in 0..10 {
let _ctx = unwind_context!(i);
// ...
}
// ...
}
使用 unwind_context!(a, b, c)
语法,它将打印代码位置、给定参数名(字符串化表达式)和 unwind 时的值,而使用 unwind_context!(fn(a, b, c))
语法时,它还将打印函数名。注意,它使用 core::fmt::Debug
表示形式。如果您想使用 core::fmt::Display
表示形式,您可以使用 WithDisplay
包装器。
您可以使用 set_colors_enabled
函数无条件启用16-ANSI-color着色。如果您只想在终端支持时启用着色,可以使用 enable_colors_if_supported
函数,这将需要启用 detect-color-support
功能标志
[dependencies.unwind-context]
version = "0.2.2"
features = [ "detect-color-support" ]
fn main() {
unwind_context::enable_colors_if_supported();
// ...
}
#[test]
fn test() {
unwind_context::enable_colors_if_supported()
// ...
}
如果您想指定自定义颜色方案,可以使用 set_default_color_scheme
函数。此外,可以使用 unwind_context_with_io
和 unwind_context_with_fmt
宏分别针对每个上下文作用域保护自定义着色。
该crate默认依赖标准库,这是写入std::io::stderr
和检测panic所需的。要在具有自定义core::fmt::Write
写入器和自定义PanicDetector
的#![no_std]
环境中使用此crate,请在您的Cargo.toml
中添加以下代码
[dependencies.unwind-context]
version = "0.2.2"
default-features = false
示例
以下crate示例
#![allow(missing_docs, unused_crate_dependencies)]
use unwind_context::unwind_context;
#[derive(Clone, Debug)]
struct Wrapper<T>(T);
fn main() {
unwind_context::enable_colors_if_supported();
app_logic(Wrapper("abc\nbcd".to_owned()), &[1, 2], "secret", false);
}
fn app_logic(value: Wrapper<String>, arr: &[u8], secret: &str, flag: bool) {
let _ctx = unwind_context!(fn(value.clone(), arr, ..., flag));
// ...
let _ = collect_rotations("áöù");
// ...
let _ = (value, arr, secret, flag);
}
fn collect_rotations(value: &str) -> Vec<String> {
let _ctx = unwind_context!(fn(value));
(0..value.len())
.map(|mid| rotate_left(value, mid))
.collect()
}
fn rotate_left(value: &str, mid: usize) -> String {
let _ctx = unwind_context!(fn(value, mid));
let (left, right) = split(value, mid);
format!("{right}{left}")
}
fn split(value: &str, at: usize) -> (&str, &str) {
let _ctx = unwind_context!(fn(value, at));
(&value[0..at], &value[at..])
}
将输出
宏展开
以下函数
use unwind_context::unwind_context;
fn foo(a: &str, b: Vec<u8>, c: bool, d: String) {
let _ctx = unwind_context!(fn(a, &b, ..., d.clone()));
// ...
for i in 0..10 {
let _ctx = unwind_context!(i);
// ...
}
}
将部分展开为
fn foo(a: u32, b: Vec<u8>, c: bool, d: String) {
let _ctx = unwind_context::UnwindContextWithIo::new(
unwind_context::UnwindContextFunc::new(
{
struct Item;
let module_path = ::core::module_path!();
let item_type_name = ::core::any::type_name::<Item>();
unwind_context::func_name_from_item_type_name(
module_path, item_type_name
)
},
(
unwind_context::UnwindContextArg::new(Some("a"), a),
(
unwind_context::UnwindContextArg::new(Some("&b"), &b),
(
unwind_context::UnwindContextArg::new(
None,
unwind_context::NonExhaustiveMarker,
),
(
unwind_context::UnwindContextArg::new(
Some("d.clone()"), d.clone()
),
(),
),
),
),
),
),
::std::io::stderr(),
unwind_context::StdPanicDetector,
unwind_context::get_default_color_scheme_if_enabled(),
);
// ...
for i in 0..10 {
let _ctx = unwind_context::UnwindContextWithIo::new(
unwind_context::UnwindContextArgs::new((
unwind_context::UnwindContextArg::new(Some("i"), i),
(),
)),
::std::io::stderr(),
unwind_context::StdPanicDetector,
unwind_context::get_default_color_scheme_if_enabled(),
);
// ...
}
}
文档
功能标志
std
(默认启用):启用UnwindContextWithIo
结构体,unwind_context
,debug_unwind_context
,unwind_context_with_io
和debug_unwind_context_with_io
宏。detect-color-support
:启用enable_colors_if_supported
函数和supports-color
可选依赖。custom-default-colors
:启用set_default_color_scheme
函数和atomic_ref
可选依赖。
类似crate
scopeguard
允许你在作用域结束时运行任何代码。它具有成功和unwind保护变体,并且不需要修改panic钩子。panic-context
允许您使用自定义panic钩子指定和修改panic上下文。它提供了对输出的更精细控制。但是,它隐式地使用互斥锁进行一次性的线程局部初始化来修改panic钩子,并且不添加任何自动上下文或着色。econtext
允许您指定panic上下文,并自动添加一些上下文,包括函数名称和位置。但是,它需要通过init函数修改panic钩子,并使用动态派发和一些不安全代码。
许可证
根据您的选择,许可协议为
- Apache License,版本2.0(LICENSE-APACHE 或 https://apache.ac.cn/licenses/LICENSE-2.0)
- MIT许可证(LICENSE-MIT 或 https://opensource.org/licenses/MIT)
。
贡献
除非您明确声明,否则根据Apache-2.0许可证定义,您有意提交以包含在工作中的任何贡献,都应以上述方式双授权,无需任何额外条款或条件。