Panic hook
install_panic_hook() emits one tracing error event for every panic, then calls the hook that was installed before it, so the default message on stderr stays.
Call it once, early in main, after the subscriber is set:
let (log_layer, log_handle) = GcpCloudLoggingLayerBuilder::new(google_project_id)
.with_cloud_logging_api(GcpCloudLoggingApiConfig::new(LogId::new(
"gcloud-observability-example",
)?))
.with_error_reporting(
ServiceContext::new("gcloud-observability-panic-hook-example")
.with_version(env!("CARGO_PKG_VERSION")),
)
.build_async()
.await?;
// The filter keeps the Cloud Logging client's own debug events out of the log it writes.
let subscriber = Registry::default()
.with(EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")))
.with(log_layer);
tracing::subscriber::set_global_default(subscriber)?;
install_panic_hook();
The event carries the panic message and panic.location, and context.reportLocation names that location rather than the hook.
It reaches Error Reporting when the layer was built with with_error_reporting.
The backtrace is captured inside the hook and needs RUST_BACKTRACE or RUST_LIB_BACKTRACE.
Flushing
The JSON lines sink writes the event before the hook returns.
The Cloud Logging API and OTLP sinks only queue it and send it in the background, so it is lost when the process ends first: after panic = "abort", or when a panic unwinds out of main and nothing flushes on the way.
Shut down the GcpCloudLoggingHandle or the logger provider before the process ends.
The example catches the panic with std::panic::catch_unwind and shuts the handle down afterwards.
A guard that shuts the logger provider down when it is dropped covers a panic that unwinds out of main.
Full example available here.