diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 37da57c26..a7ea67fff 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -81,9 +81,9 @@ checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" [[package]] name = "android_log-sys" -version = "0.2.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85965b6739a430150bdd138e2374a98af0c3ee0d030b3bb7fc3bddff58d0102e" +checksum = "5ecc8056bf6ab9892dcd53216c83d1597487d7dacac16c8df6b877d127df9937" [[package]] name = "android_system_properties" @@ -1065,6 +1065,7 @@ dependencies = [ name = "connlib-client-android" version = "1.1.1" dependencies = [ + "android_log-sys", "connlib-client-shared", "ip_network", "jni 0.21.1", @@ -1074,7 +1075,6 @@ dependencies = [ "thiserror", "tokio", "tracing", - "tracing-android", "tracing-appender", "tracing-subscriber", "url", @@ -1119,7 +1119,6 @@ dependencies = [ "tokio", "tokio-tungstenite", "tracing", - "tracing-android", "tracing-appender", "tracing-stackdriver", "tracing-subscriber", @@ -1159,7 +1158,6 @@ dependencies = [ "thiserror", "tokio", "tracing", - "tracing-android", "url", "uuid", "windows 0.57.0", @@ -2062,7 +2060,6 @@ dependencies = [ "thiserror", "tokio", "tracing", - "tracing-android", "tracing-subscriber", "uuid", "windows 0.57.0", @@ -6718,17 +6715,6 @@ dependencies = [ "tracing-core", ] -[[package]] -name = "tracing-android" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12612be8f868a09c0ceae7113ff26afe79d81a24473a393cb9120ece162e86c0" -dependencies = [ - "android_log-sys", - "tracing", - "tracing-subscriber", -] - [[package]] name = "tracing-appender" version = "0.2.3" diff --git a/rust/connlib/clients/android/Cargo.toml b/rust/connlib/clients/android/Cargo.toml index e70cb6cc3..d2308163e 100644 --- a/rust/connlib/clients/android/Cargo.toml +++ b/rust/connlib/clients/android/Cargo.toml @@ -27,7 +27,7 @@ url = "2.4.0" tokio = { version = "1.38", default-features = false, features = ["rt"] } [target.'cfg(target_os = "android")'.dependencies] -tracing-android = "0.2" +android_log-sys = "0.3.1" [lints] workspace = true diff --git a/rust/connlib/clients/android/src/lib.rs b/rust/connlib/clients/android/src/lib.rs index c6f3860e4..2f8005545 100644 --- a/rust/connlib/clients/android/src/lib.rs +++ b/rust/connlib/clients/android/src/lib.rs @@ -26,6 +26,8 @@ use tokio::runtime::Runtime; use tracing_subscriber::prelude::*; use tracing_subscriber::EnvFilter; +mod make_writer; + /// The Android client doesn't use platform APIs to detect network connectivity changes, /// so we rely on connlib to do so. We have valid use cases for headless Android clients /// (IoT devices, point-of-sale devices, etc), so try to reconnect for 30 days. @@ -108,22 +110,6 @@ fn call_method( .map_err(|source| CallbackError::CallMethodFailed { name, source }) } -#[cfg(target_os = "android")] -fn android_layer() -> impl tracing_subscriber::Layer -where - S: tracing::Subscriber + for<'span> tracing_subscriber::registry::LookupSpan<'span>, -{ - tracing_android::layer("connlib").unwrap() -} - -#[cfg(not(target_os = "android"))] -fn android_layer() -> impl tracing_subscriber::Layer -where - S: tracing::Subscriber, -{ - tracing_subscriber::layer::Identity::new() -} - fn init_logging(log_dir: &Path, log_filter: String) -> file_logger::Handle { // On Android, logging state is persisted indefinitely after the System.loadLibrary // call, which means that a disconnect and tunnel process restart will not @@ -146,7 +132,14 @@ fn init_logging(log_dir: &Path, log_filter: String) -> file_logger::Handle { let _ = tracing_subscriber::registry() .with(file_layer.with_filter(EnvFilter::new(log_filter.clone()))) - .with(android_layer().with_filter(EnvFilter::new(log_filter))) + .with( + tracing_subscriber::fmt::layer() + .with_ansi(false) + .without_time() + .with_level(false) + .with_writer(make_writer::MakeWriter::new("connlib")) + .with_filter(EnvFilter::new(log_filter)), + ) .try_init(); handle diff --git a/rust/connlib/clients/android/src/make_writer.rs b/rust/connlib/clients/android/src/make_writer.rs new file mode 100644 index 000000000..b12483f30 --- /dev/null +++ b/rust/connlib/clients/android/src/make_writer.rs @@ -0,0 +1,89 @@ +//! Heavily inspired from https://github.com/Actyx/tracing-android/blob/master/src/android.rs. + +use std::{ + ffi::{CStr, CString}, + io::{self, BufWriter}, +}; +use tracing::Level; + +const LOGGING_MSG_MAX_LEN: usize = 4000; + +pub(crate) struct MakeWriter { + tag: CString, +} + +pub(crate) struct Writer { + level: Level, + tag: CString, +} + +impl MakeWriter { + pub(crate) fn new(tag: &'static str) -> Self { + Self { + tag: CString::new(tag).expect("tag must not contain nul-byte"), + } + } + + fn make_writer_for_level(&self, level: Level) -> BufWriter { + let inner = Writer { + level, + tag: self.tag.clone(), + }; + + BufWriter::with_capacity(LOGGING_MSG_MAX_LEN, inner) + } +} + +impl tracing_subscriber::fmt::MakeWriter<'_> for MakeWriter { + type Writer = BufWriter; + + fn make_writer(&self) -> Self::Writer { + self.make_writer_for_level(Level::INFO) + } + + fn make_writer_for(&self, meta: &tracing::Metadata<'_>) -> Self::Writer { + self.make_writer_for_level(*meta.level()) + } +} + +impl io::Write for Writer { + fn write(&mut self, buf: &[u8]) -> io::Result { + let written = buf.len().min(LOGGING_MSG_MAX_LEN); + + let msg = &buf[..written]; + let msg = CString::new(msg.to_vec())?; + + android_log(self.level, self.tag.as_c_str(), &msg); + + Ok(written) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +#[cfg(target_os = "android")] +fn android_log(level: Level, tag: &CStr, msg: &CStr) { + let prio = match level { + Level::WARN => android_log_sys::LogPriority::WARN, + Level::INFO => android_log_sys::LogPriority::INFO, + Level::DEBUG => android_log_sys::LogPriority::DEBUG, + Level::ERROR => android_log_sys::LogPriority::ERROR, + Level::TRACE => android_log_sys::LogPriority::VERBOSE, + }; + + // Safety: FFI calls are unsafe. + unsafe { + android_log_sys::__android_log_write( + prio as android_log_sys::c_int, + tag.as_ptr() as *const android_log_sys::c_char, + msg.as_ptr() as *const android_log_sys::c_char, + ) + }; +} + +#[cfg(not(target_os = "android"))] +fn android_log(_: Level, _: &CStr, _: &CStr) { + unimplemented!("Logger is not meant to be used in non-Android environments") +} diff --git a/rust/connlib/clients/shared/Cargo.toml b/rust/connlib/clients/shared/Cargo.toml index 93576f430..0d81abb2c 100644 --- a/rust/connlib/clients/shared/Cargo.toml +++ b/rust/connlib/clients/shared/Cargo.toml @@ -29,7 +29,6 @@ phoenix-channel = { workspace = true } [target.'cfg(target_os = "android")'.dependencies] tracing = { workspace = true, features = ["std", "attributes"] } -tracing-android = "0.2" [dev-dependencies] chrono = { workspace = true } diff --git a/rust/connlib/shared/Cargo.toml b/rust/connlib/shared/Cargo.toml index b0438b453..3a71598d5 100644 --- a/rust/connlib/shared/Cargo.toml +++ b/rust/connlib/shared/Cargo.toml @@ -44,9 +44,6 @@ tokio = { version = "1.38", features = ["macros", "rt"] } [target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies] swift-bridge = { workspace = true } -[target.'cfg(target_os = "android")'.dependencies] -tracing-android = "0.2" - [target.'cfg(target_os = "linux")'.dependencies] netlink-packet-route = { version = "0.19", default-features = false } netlink-packet-core = { version = "0.7", default-features = false } diff --git a/rust/connlib/tunnel/Cargo.toml b/rust/connlib/tunnel/Cargo.toml index 87c3fdc38..ae3f4543e 100644 --- a/rust/connlib/tunnel/Cargo.toml +++ b/rust/connlib/tunnel/Cargo.toml @@ -59,10 +59,6 @@ netlink-packet-route = { version = "0.19", default-features = false } netlink-packet-core = { version = "0.7", default-features = false } rtnetlink = { workspace = true } -# Android tunnel dependencies -[target.'cfg(target_os = "android")'.dependencies] -tracing-android = "0.2" - # Windows tunnel dependencies [target.'cfg(target_os = "windows")'.dependencies] uuid = { version = "1.7.0", features = ["v4"] }