1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
//! # `console_error_panic_hook`
//!
//! [<img alt="github" src="https://img.shields.io/badge/github-workflow--rs-8da0cb?style=for-the-badge&labelColor=555555&color=8da0cb&logo=github" height="20">](https://github.com/workflow-rs/workflow-rs)
//! [<img alt="crates.io" src="https://img.shields.io/crates/v/workflow-panic-hook.svg?maxAge=2592000&style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/workflow-panic-hook)
//! [<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-workflow--panic--hook-56c2a5?maxAge=2592000&style=for-the-badge&logo=docs.rs" height="20">](https://docs.rs/workflow-panic-hook)
//! <img alt="license" src="https://img.shields.io/crates/l/workflow-panic-hook.svg?maxAge=2592000&color=6ac&style=for-the-badge&logoColor=fff" height="20">
//! <img src="https://img.shields.io/badge/platform- wasm32/browser -informational?style=for-the-badge&color=50a0f0" height="20">
//! <img src="https://img.shields.io/badge/platform- wasm32/node.js -informational?style=for-the-badge&color=50a0f0" height="20">
//!
//! This crate is based on [console_error_panic_hook](https://crates.io/crates/console_error_panic_hook) but
//! provides two configuration modes - console output and full-page output, where the panic will create
//! a full-screen DIV element dumping the stack info in it. This is useful when debugging on devices
//! without access to console output.
//!
//! ## Error.stackTraceLimit
//!
//! Many browsers only capture the top 10 frames of a stack trace. In rust programs this is less likely to be enough. To see more frames, you can set the non-standard value `Error.stackTraceLimit`. For more information see the [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Microsoft_Extensions/Error.stackTraceLimit) or [v8 docs](https://v8.dev/docs/stack-trace-api).
//!
#[macro_use]
extern crate cfg_if;
use std::panic;
cfg_if! {
if #[cfg(target_arch = "wasm32")] {
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
mod logger;
#[wasm_bindgen]
extern {
#[wasm_bindgen(js_namespace = console, js_name="error")]
fn console_error(msg: String);
type Error;
#[wasm_bindgen(constructor)]
fn new() -> Error;
#[wasm_bindgen(structural, method, getter)]
fn stack(error: &Error) -> String;
}
fn process(info: &panic::PanicInfo) -> String{
let mut msg = info.to_string();
// Add the error stack to our message.
//
// This ensures that even if the `console` implementation doesn't
// include stacks for `console.error`, the stack is still available
// for the user. Additionally, Firefox's console tries to clean up
// stack traces, and ruins Rust symbols in the process
// (https://bugzilla.mozilla.org/show_bug.cgi?id=1519569) but since
// it only touches the logged message's associated stack, and not
// the message's contents, by including the stack in the message
// contents we make sure it is available to the user.
msg.push_str("\n\nStack:\n\n");
let e = Error::new();
let stack = e.stack();
msg.push_str(&stack);
// Safari's devtools, on the other hand, _do_ mess with logged
// messages' contents, so we attempt to break their heuristics for
// doing that by appending some whitespace.
// https://github.com/rustwasm/console_error_panic_hook/issues/7
msg.push_str("\n\n");
msg
}
fn console_hook(info: &panic::PanicInfo){
// Finally, log the panic with `console.error`!
console_error(process(info));
}
fn popup_hook(info: &panic::PanicInfo){
// Finally, log the panic with `logger::error`!
logger::error(process(info));
}
fn init(logger_type:Type){
match logger_type {
Type::Console=>{
panic::set_hook(Box::new(console_hook));
}
Type::Popup=>{
logger::init_logger();
panic::set_hook(Box::new(popup_hook));
}
Type::Native=>{
panic!("Native logger not supported under wasm");
}
}
}
pub use logger::show_logs;
} else {
use std::io::{self, Write};
fn hook(info: &panic::PanicInfo) {
let _ = writeln!(io::stderr(), "{info}");
}
fn init(_logger_type:Type){
panic::set_hook(Box::new(hook));
}
pub fn show_logs(){
panic!("Native (non-WASM) platform build doesn't support panic logs");
}
}
}
pub enum Type {
Console,
Popup,
Native,
}
/// Set the `console.error` panic hook the first time this is called. Subsequent
/// invocations do nothing.
#[inline]
pub fn set_once(logger_type: Type) {
use std::sync::Once;
static SET_HOOK: Once = Once::new();
SET_HOOK.call_once(|| init(logger_type));
}