Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for file based logging in ios and macos #1713

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 17 additions & 12 deletions nym-vpn-core/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions nym-vpn-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ tower = "0.5.2"
tower-http = { version = "0.6.2", features = ["cors"] }
tracing = "0.1"
tracing-appender = "0.2.3"
tracing-oslog = "0.2.0"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
triggered = "0.1.1"
tun = { version = "0.6.1", features = ["async"] }
Expand Down
5 changes: 2 additions & 3 deletions nym-vpn-core/crates/nym-vpn-lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ tokio = { workspace = true, features = [
tokio-stream.workspace = true
tokio-util = { workspace = true, features = ["codec", "rt"] }
tracing-subscriber = { workspace = true, features = ["env-filter"] }
tracing-appender.workspace = true
tracing.workspace = true
tun = { workspace = true, features = ["async"] }
uniffi.workspace = true
Expand Down Expand Up @@ -98,10 +99,8 @@ android_logger.workspace = true
rand.workspace = true

[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies]
oslog.workspace = true

[target.'cfg(target_os = "ios")'.dependencies]
debounced.workspace = true
tracing-oslog.workspace = true

[build-dependencies]
uniffi = { workspace = true, features = ["build"] }
Expand Down
3 changes: 1 addition & 2 deletions nym-vpn-core/crates/nym-vpn-lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,10 @@ pub use nym_task::{
};
pub use nym_wg_gateway_client as wg_gateway_client;

#[cfg(any(target_os = "ios", target_os = "macos"))]
pub use crate::platform::swift;
pub use crate::{
error::{Error, GatewayDirectoryError},
mixnet::MixnetError,
platform::init_logger,
};

pub const DEFAULT_DNS_SERVERS: [IpAddr; 4] = [
Expand Down
17 changes: 0 additions & 17 deletions nym-vpn-core/crates/nym-vpn-lib/src/platform/android.rs

This file was deleted.

115 changes: 115 additions & 0 deletions nym-vpn-core/crates/nym-vpn-lib/src/platform/logging.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// Copyright 2023 - Nym Technologies SA <[email protected]>
// SPDX-License-Identifier: GPL-3.0-only

use tracing_subscriber::{filter::LevelFilter, EnvFilter};

pub(crate) const DEFAULT_LOG_FILE: &str = "nym-vpn-lib.log";

/// Enables and configures logging using the `tracing-subscriber` and `tracing-appender` libraries. If a non-empty
/// string is provided for the path, we attempt to cannonicalize and parse the path such that logs are written to file.
/// If the provided path is a directory, logs will be written to "{provided_dir}/nym-vpn-lib.log".
///
/// On call this subscriber attempts to parse filter level from the (default) logging environment variable `"RUST_LOG"`.
/// If that is not set it defaults to `INFO` level.
///
/// Android logging is handled using the [`android_logger`] crate.
//
// Is there a state object associated with `uniffi::export` stored in `nym-vpn-lib`? As is, the
// [`tracing_appender::rolling::RollingFileAppender`] may write in blocking mode. Without somewhere to store the
// worker guard provided by the construction of a [`tracing_appender::non_blocking::NonBlocking`] the appender
// may not flush properly on drop (i.e. around a crash).
//
// let (writer, worker_guard) = tracing_appender::non_blocking(appender);
//
// see https://docs.rs/tracing-appender/latest/tracing_appender/non_blocking/struct.WorkerGuard.html
pub fn init_logger(path_str: &str) {
#[cfg(target_os = "android")]
{
let log_level = ::std::env::var("RUST_LOG").unwrap_or("info".to_string());
init_logs(log_level);
/// todo
return;
}

#[cfg(any(target_os = "ios", target_os = "macos"))]
let mut filter = EnvFilter::builder()
.with_env_var("RUST_LOG")
.with_default_directive(LevelFilter::INFO.into())
.from_env_lossy();

#[cfg(not(any(target_os = "ios", target_os = "macos")))]
let mut filter = EnvFilter::builder()
.with_default_directive(LevelFilter::INFO.into())
.from_env_lossy()
.add_directive("netlink_proto=info".parse().unwrap());

filter = filter
.add_directive("hyper=info".parse().unwrap())
.add_directive("tokio_reactor=warn".parse().unwrap())
.add_directive("reqwest=warn".parse().unwrap())
.add_directive("mio=warn".parse().unwrap())
.add_directive("want=warn".parse().unwrap())
.add_directive("tungstenite=warn".parse().unwrap())
.add_directive("tokio_tungstenite=warn".parse().unwrap())
.add_directive("handlebars=warn".parse().unwrap())
.add_directive("sled=warn".parse().unwrap());

let log_builder = tracing_subscriber::fmt().with_env_filter(filter).compact();

if let Some(appender) = try_make_writer(path_str) {
std::panic::set_hook(Box::new(|panic| {
tracing::error!(message = %panic);
}));

log_builder.with_writer(appender).init();
} else {
log_builder.init();
}
}

fn try_make_writer(path_str: &str) -> Option<tracing_appender::rolling::RollingFileAppender> {
if path_str.is_empty() {
return None;
}

let path = ::std::path::Path::new(path_str).canonicalize().ok()?;

let (maybe_log_dir, filename) = if path.is_dir() {
(
Some(path.as_path()),
::std::path::Path::new(DEFAULT_LOG_FILE),
)
} else if path.is_file() {
(
path.parent(),
::std::path::Path::new(path.file_name().unwrap()),
)
} else {
return None;
};

// make sure that the path provides a directory, the directory exists and we have permission to access it.
if !maybe_log_dir.is_some_and(|d| d.try_exists().is_ok_and(|exists| exists)) {
return None;
};

let log_dir = maybe_log_dir.unwrap();

println!("log_path: {}", path.display());

Some(tracing_appender::rolling::never(log_dir, filename))
}

#[cfg(target_os = "android")]
pub(crate) fn init_logs(level: String) {
use android_logger::{Config, FilterBuilder};
let levels = level + ",tungstenite=warn,mio=warn,tokio_tungstenite=warn";

android_logger::init_once(
Config::default()
.with_max_level(log::LevelFilter::Trace)
.with_tag("libnymvpn")
.with_filter(FilterBuilder::new().parse(levels.as_str()).build()),
);
log::debug!("Logger initialized");
}
23 changes: 6 additions & 17 deletions nym-vpn-core/crates/nym-vpn-lib/src/platform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,16 @@
//! This will stop the account controller and clean up any resources, including make sure there
//! are no open DB connections.

#[cfg(target_os = "android")]
pub mod android;
pub(crate) mod error;
pub mod helpers;
#[cfg(any(target_os = "ios", target_os = "macos"))]
pub mod swift;

mod account;
mod environment;
mod logging;
mod state_machine;
pub use logging::init_logger;

use std::{env, path::PathBuf, sync::Arc, time::Duration};
use std::{path::PathBuf, sync::Arc, time::Duration};

use account::AccountControllerHandle;
use lazy_static::lazy_static;
Expand Down Expand Up @@ -123,26 +121,17 @@ pub fn configureLib(data_dir: String, credential_mode: Option<bool>) -> Result<(
}

async fn configure_lib(data_dir: String, credential_mode: Option<bool>) -> Result<(), VpnError> {
init_logger();
init_logger("");
let network = environment::current_environment_details().await?;
account::init_account_controller(PathBuf::from(data_dir), credential_mode, network).await
}

fn init_logger() {
let log_level = env::var("RUST_LOG").unwrap_or("info".to_string());
tracing::info!("Setting log level: {}", log_level);
#[cfg(target_os = "ios")]
swift::init_logs(log_level);
#[cfg(target_os = "android")]
android::init_logs(log_level);
}

/// Additional extra function for when only only want to set the logger without initializing the
/// library. Thus it's only needed when `configureLib` is not used.
#[allow(non_snake_case)]
#[uniffi::export]
pub fn initLogger() {
init_logger();
pub fn initLogger(logfile_path: &str) {
init_logger(logfile_path);
}

/// Returns the system messages for the current network environment
Expand Down
31 changes: 0 additions & 31 deletions nym-vpn-core/crates/nym-vpn-lib/src/platform/swift.rs

This file was deleted.

23 changes: 3 additions & 20 deletions nym-vpn-core/crates/nym-vpnd/src/logging.rs
Original file line number Diff line number Diff line change
@@ -1,36 +1,19 @@
// Copyright 2024 - Nym Technologies SA <[email protected]>
// SPDX-License-Identifier: GPL-3.0-only
#[cfg(target_os = "macos")]
use std::env;

use tracing_appender::non_blocking::WorkerGuard;

use crate::service;

pub fn setup_logging(_as_service: bool) {
#[cfg(target_os = "macos")]
if _as_service {
let log_level = env::var("RUST_LOG").unwrap_or("info".to_string());
nym_vpn_lib::swift::init_logs(log_level);
return;
}

let filter = tracing_subscriber::EnvFilter::builder()
.with_default_directive(tracing_subscriber::filter::LevelFilter::INFO.into())
.from_env()
.unwrap()
.add_directive("hyper::proto=info".parse().unwrap())
.add_directive("netlink_proto=info".parse().unwrap());

tracing_subscriber::fmt()
.with_env_filter(filter)
.compact()
.init();
nym_vpn_lib::init_logger("");
}

#[allow(unused)]
pub fn setup_logging_to_file() -> WorkerGuard {
let log_dir = service::log_dir();
// let path = log_dir.join(service::DEFAULT_LOG_FILE);
// nym_vpn_lib::init_logger(path);

println!("log_dir: {}", log_dir.display());

Expand Down
Loading