将堆分配的字符串添加到 Panic 处理程序
Add heap-allocated string to Panic handler
我在 Web 应用程序的上下文中,其中每个请求都分配有一个唯一的相关 ID。
我 运行 在 wasm
环境中,目标是 wasm32-unknown-unknown
。一个请求始终由一个线程服务,然后整个环境被拆除。
我想注册一个恐慌处理程序,如果请求出现恐慌,它还会记录此请求 ID。
事实证明这很困难,因为任何必须进入 set_hook
方法的东西都需要 'static
生命周期约束,而请求 ID 显然没有。
我想编译以下几行代码
// Assume we have a request here from somewhere.
let request = get_request_from_framework();
// This is at the start of the request
panic::set_hook(Box::new(|info| {
let request_id = request.get_request_id();
// Log panic messages here with request_id here
}));
可能的解决方案
我有一些可能的方法。我不确定哪一个是最好的,或者是否有任何我遗漏的方法。
1。泄漏内存
据我所知,每次请求后我的环境都会被拆除,一种将字符串移入 'static
生命周期以泄漏它的方法是这样的
let request_id = uuid::Uuid::new_v4().to_string();
let request_id: &'static str = Box::leak(request_id.into_boxed_str());
request_id
这将在实践中起作用,因为请求 ID 理论上是“静态的”(因为在请求被服务后,应用程序被关闭)——但是它的缺点是如果我将这段代码移到非 wasm 中环境,我们很快就会泄漏内存。
2。线程本地
据我所知,每个请求都由一个线程提供服务,我可以将请求 ID 填充到 ThreadLocal 中,并在发生恐慌时从该 ThreadLocal 中读取。
pub fn create_request_id() -> &'static str {
let request_id = uuid::Uuid::new_v4().to_string();
CURRENT_REQUEST_ID.with(|current_request_id| {
*current_request_id.borrow_mut() = request_id;
});
}
thread_local! {
pub static CURRENT_REQUEST_ID: RefCell<String> = RefCell::new(uuid::Uuid::new_v4().to_string());
}
// And then inside the panic handler get the request_id with something like
let request_id = CURRENT_REQUEST_ID.with(|current_request_id| {
let current_request_id = current_request_id.try_borrow();
match current_request_id {
Ok(current_request_id) => current_request_id.clone(),
Err(err) => "Unknown".to_string(),
}
});
这似乎是我能想到的“最佳”解决方案。但是我不确定性能是什么。在每个请求上初始化 ThreadLocal 的含义是,特别是因为我们很少恐慌,所以我不想为我几乎从不使用的东西预先支付大笔费用。
3。 Catch_unwind
我尝试了 catch_unwind
API,因为这似乎是一个不错的选择。然后我会用 catch_unwind
包装每个请求的处理。不过好像是 wasm32-unknown-unknown
currently doesn't respect catch_unwind
最好的解决方案是什么?有什么方法可以将堆分配到我不知道的 Rust panic hook 中吗?
根据您的示例,您可以将 id 移动到子句中:
// Assume we have a request here from somewhere.
let request = get_request_from_framework();
let request_id = request.get_request_id();
// This is at the start of the request
panic::set_hook(Box::new(move |info| {
let panic_message = format!("Request {} failed", request_id);
// Log panic messages here with request_id here
}));
我在 Web 应用程序的上下文中,其中每个请求都分配有一个唯一的相关 ID。
我 运行 在 wasm
环境中,目标是 wasm32-unknown-unknown
。一个请求始终由一个线程服务,然后整个环境被拆除。
我想注册一个恐慌处理程序,如果请求出现恐慌,它还会记录此请求 ID。
事实证明这很困难,因为任何必须进入 set_hook
方法的东西都需要 'static
生命周期约束,而请求 ID 显然没有。
我想编译以下几行代码
// Assume we have a request here from somewhere.
let request = get_request_from_framework();
// This is at the start of the request
panic::set_hook(Box::new(|info| {
let request_id = request.get_request_id();
// Log panic messages here with request_id here
}));
可能的解决方案
我有一些可能的方法。我不确定哪一个是最好的,或者是否有任何我遗漏的方法。
1。泄漏内存
据我所知,每次请求后我的环境都会被拆除,一种将字符串移入 'static
生命周期以泄漏它的方法是这样的
let request_id = uuid::Uuid::new_v4().to_string();
let request_id: &'static str = Box::leak(request_id.into_boxed_str());
request_id
这将在实践中起作用,因为请求 ID 理论上是“静态的”(因为在请求被服务后,应用程序被关闭)——但是它的缺点是如果我将这段代码移到非 wasm 中环境,我们很快就会泄漏内存。
2。线程本地
据我所知,每个请求都由一个线程提供服务,我可以将请求 ID 填充到 ThreadLocal 中,并在发生恐慌时从该 ThreadLocal 中读取。
pub fn create_request_id() -> &'static str {
let request_id = uuid::Uuid::new_v4().to_string();
CURRENT_REQUEST_ID.with(|current_request_id| {
*current_request_id.borrow_mut() = request_id;
});
}
thread_local! {
pub static CURRENT_REQUEST_ID: RefCell<String> = RefCell::new(uuid::Uuid::new_v4().to_string());
}
// And then inside the panic handler get the request_id with something like
let request_id = CURRENT_REQUEST_ID.with(|current_request_id| {
let current_request_id = current_request_id.try_borrow();
match current_request_id {
Ok(current_request_id) => current_request_id.clone(),
Err(err) => "Unknown".to_string(),
}
});
这似乎是我能想到的“最佳”解决方案。但是我不确定性能是什么。在每个请求上初始化 ThreadLocal 的含义是,特别是因为我们很少恐慌,所以我不想为我几乎从不使用的东西预先支付大笔费用。
3。 Catch_unwind
我尝试了 catch_unwind
API,因为这似乎是一个不错的选择。然后我会用 catch_unwind
包装每个请求的处理。不过好像是 wasm32-unknown-unknown
currently doesn't respect catch_unwind
最好的解决方案是什么?有什么方法可以将堆分配到我不知道的 Rust panic hook 中吗?
根据您的示例,您可以将 id 移动到子句中:
// Assume we have a request here from somewhere.
let request = get_request_from_framework();
let request_id = request.get_request_id();
// This is at the start of the request
panic::set_hook(Box::new(move |info| {
let panic_message = format!("Request {} failed", request_id);
// Log panic messages here with request_id here
}));