mirror of
https://github.com/bitwarden/browser
synced 2025-12-06 00:13:28 +00:00
[BEEEP][PM-255518] Use tracing for improved observability (#16321)
* [BEEEP][PM-255518] Use tracing for improved observability
* feedback dani-garcia: use DefaultVisitor
* set default log level
* convert printlns in objc crate
* convert printlns in autotype crate
* convert printlns in autostart crate
* convert printlns in core/password crate
* convert printlns in core/biometric crate
* convert printlns in napi crate
* convert log usage in macos provider crate
* convert existing log macros to tracing
* fix the cargo.toml sort lint errors
* Revert "fix the cargo.toml sort lint errors"
This reverts commit fd149ab697.
* fix the sort lint using correct cargo sort version
* feedback coltonhurst: more comments/clarity on behavior
* revert changes to ssh_agent
This commit is contained in:
@@ -175,6 +175,7 @@ pub mod sshagent {
|
||||
threadsafe_function::{ErrorStrategy::CalleeHandled, ThreadsafeFunction},
|
||||
};
|
||||
use tokio::{self, sync::Mutex};
|
||||
use tracing::error;
|
||||
|
||||
#[napi]
|
||||
pub struct SshAgentState {
|
||||
@@ -242,7 +243,7 @@ pub mod sshagent {
|
||||
.expect("should be able to send auth response to agent");
|
||||
}
|
||||
Err(e) => {
|
||||
println!("[SSH Agent Native Module] calling UI callback promise was rejected: {e}");
|
||||
error!(error = %e, "Calling UI callback promise was rejected");
|
||||
let _ = auth_response_tx_arc
|
||||
.lock()
|
||||
.await
|
||||
@@ -251,7 +252,7 @@ pub mod sshagent {
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
println!("[SSH Agent Native Module] calling UI callback could not create promise: {e}");
|
||||
error!(error = %e, "Calling UI callback could not create promise");
|
||||
let _ = auth_response_tx_arc
|
||||
.lock()
|
||||
.await
|
||||
@@ -513,6 +514,7 @@ pub mod autofill {
|
||||
ErrorStrategy, ThreadsafeFunction, ThreadsafeFunctionCallMode,
|
||||
};
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
use tracing::error;
|
||||
|
||||
#[napi]
|
||||
pub async fn run_command(value: String) -> napi::Result<String> {
|
||||
@@ -668,7 +670,7 @@ pub mod autofill {
|
||||
MessageType::Connected | MessageType::Disconnected => continue,
|
||||
MessageType::Message => {
|
||||
let Some(message) = message else {
|
||||
println!("[ERROR] Message is empty");
|
||||
error!("Message is empty");
|
||||
continue;
|
||||
};
|
||||
|
||||
@@ -686,7 +688,7 @@ pub mod autofill {
|
||||
continue;
|
||||
}
|
||||
Err(e) => {
|
||||
println!("[ERROR] Error deserializing message1: {e}");
|
||||
error!(error = %e, "Error deserializing message1");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -705,7 +707,7 @@ pub mod autofill {
|
||||
continue;
|
||||
}
|
||||
Err(e) => {
|
||||
println!("[ERROR] Error deserializing message1: {e}");
|
||||
error!(error = %e, "Error deserializing message1");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -722,11 +724,11 @@ pub mod autofill {
|
||||
continue;
|
||||
}
|
||||
Err(e) => {
|
||||
println!("[ERROR] Error deserializing message2: {e}");
|
||||
error!(error = %e, "Error deserializing message2");
|
||||
}
|
||||
}
|
||||
|
||||
println!("[ERROR] Received an unknown message2: {message:?}");
|
||||
error!(message, "Received an unknown message2");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -823,11 +825,28 @@ pub mod passkey_authenticator {
|
||||
|
||||
#[napi]
|
||||
pub mod logging {
|
||||
use log::{Level, Metadata, Record};
|
||||
//! `logging` is the interface between the native desktop's usage of the `tracing` crate
|
||||
//! for logging, to intercept events and write to the JS space.
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! [Elec] 14:34:03.517 › [NAPI] [INFO] desktop_core::ssh_agent::platform_ssh_agent: Starting SSH Agent server {socket=/Users/foo/.bitwarden-ssh-agent.sock}
|
||||
|
||||
use std::fmt::Write;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use napi::threadsafe_function::{
|
||||
ErrorStrategy::CalleeHandled, ThreadsafeFunction, ThreadsafeFunctionCallMode,
|
||||
};
|
||||
use std::sync::OnceLock;
|
||||
use tracing::Level;
|
||||
use tracing_subscriber::fmt::format::{DefaultVisitor, Writer};
|
||||
use tracing_subscriber::{
|
||||
filter::{EnvFilter, LevelFilter},
|
||||
layer::SubscriberExt,
|
||||
util::SubscriberInitExt,
|
||||
Layer,
|
||||
};
|
||||
|
||||
struct JsLogger(OnceLock<ThreadsafeFunction<(LogLevel, String), CalleeHandled>>);
|
||||
static JS_LOGGER: JsLogger = JsLogger(OnceLock::new());
|
||||
|
||||
@@ -840,42 +859,86 @@ pub mod logging {
|
||||
Error,
|
||||
}
|
||||
|
||||
impl From<Level> for LogLevel {
|
||||
fn from(level: Level) -> Self {
|
||||
match level {
|
||||
Level::Trace => LogLevel::Trace,
|
||||
Level::Debug => LogLevel::Debug,
|
||||
Level::Info => LogLevel::Info,
|
||||
Level::Warn => LogLevel::Warn,
|
||||
Level::Error => LogLevel::Error,
|
||||
impl From<&Level> for LogLevel {
|
||||
fn from(level: &Level) -> Self {
|
||||
match *level {
|
||||
Level::TRACE => LogLevel::Trace,
|
||||
Level::DEBUG => LogLevel::Debug,
|
||||
Level::INFO => LogLevel::Info,
|
||||
Level::WARN => LogLevel::Warn,
|
||||
Level::ERROR => LogLevel::Error,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// JsLayer lets us intercept events and write them to the JS Logger.
|
||||
struct JsLayer;
|
||||
|
||||
impl<S> Layer<S> for JsLayer
|
||||
where
|
||||
S: tracing::Subscriber,
|
||||
{
|
||||
// This function builds a log message buffer from the event data and
|
||||
// calls the JS logger with it.
|
||||
//
|
||||
// For example, this log call:
|
||||
//
|
||||
// ```
|
||||
// mod supreme {
|
||||
// mod module {
|
||||
// let foo = "bar";
|
||||
// info!(best_variable_name = %foo, "Foo done it again.");
|
||||
// }
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// , results in the following string:
|
||||
//
|
||||
// [INFO] supreme::module: Foo done it again. {best_variable_name=bar}
|
||||
fn on_event(
|
||||
&self,
|
||||
event: &tracing::Event<'_>,
|
||||
_ctx: tracing_subscriber::layer::Context<'_, S>,
|
||||
) {
|
||||
let mut buffer = String::new();
|
||||
|
||||
// create the preamble text that precedes the message and vars. e.g.:
|
||||
// [INFO] desktop_core::ssh_agent::platform_ssh_agent:
|
||||
let level = event.metadata().level().as_str();
|
||||
let module_path = event.metadata().module_path().unwrap_or_default();
|
||||
|
||||
write!(&mut buffer, "[{level}] {module_path}:")
|
||||
.expect("Failed to write tracing event to buffer");
|
||||
|
||||
let writer = Writer::new(&mut buffer);
|
||||
|
||||
// DefaultVisitor adds the message and variables to the buffer
|
||||
let mut visitor = DefaultVisitor::new(writer, false);
|
||||
event.record(&mut visitor);
|
||||
|
||||
let msg = (event.metadata().level().into(), buffer);
|
||||
|
||||
if let Some(logger) = JS_LOGGER.0.get() {
|
||||
let _ = logger.call(Ok(msg), ThreadsafeFunctionCallMode::NonBlocking);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn init_napi_log(js_log_fn: ThreadsafeFunction<(LogLevel, String), CalleeHandled>) {
|
||||
let _ = JS_LOGGER.0.set(js_log_fn);
|
||||
let _ = log::set_logger(&JS_LOGGER);
|
||||
log::set_max_level(log::LevelFilter::Debug);
|
||||
}
|
||||
|
||||
impl log::Log for JsLogger {
|
||||
fn enabled(&self, metadata: &Metadata) -> bool {
|
||||
metadata.level() <= log::max_level()
|
||||
}
|
||||
let filter = EnvFilter::builder()
|
||||
// set the default log level to INFO.
|
||||
.with_default_directive(LevelFilter::INFO.into())
|
||||
// parse directives from the RUST_LOG environment variable,
|
||||
// overriding the default directive for matching targets.
|
||||
.from_env_lossy();
|
||||
|
||||
fn log(&self, record: &Record) {
|
||||
if !self.enabled(record.metadata()) {
|
||||
return;
|
||||
}
|
||||
let Some(logger) = self.0.get() else {
|
||||
return;
|
||||
};
|
||||
let msg = (record.level().into(), record.args().to_string());
|
||||
let _ = logger.call(Ok(msg), ThreadsafeFunctionCallMode::NonBlocking);
|
||||
}
|
||||
|
||||
fn flush(&self) {}
|
||||
tracing_subscriber::registry()
|
||||
.with(filter)
|
||||
.with(JsLayer)
|
||||
.init();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user