Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,10 @@ class NymBackend private constructor(private val context: Context) : Backend, Tu
) {
runCatching {
startNetworkMonitorJob()
initLogger(null, LOG_LEVEL, false)

initLogger(storagePath, LOG_LEVEL, config.sentryMonitoringEnabled)
?: Timber.e("Failed to initialize backend logger")

initEnvironment(environment)
configureLib(config, userAgent)
initialized.complete(Unit)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ extension PacketTunnelProvider {
tunnelConnectingState: tunnelConnectingState,
connectionInfoData: connectionInfoData
)

// Should we clear tunnelActor.lastError here?

return try JSONEncoder().encode(statusResponse)
} catch {
logger.error("AppMessage: \(error.localizedDescription)")
Expand Down
26 changes: 17 additions & 9 deletions nym-vpn-apple/NymMixnetTunnel/PacketTunnelProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,15 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
let tunnelActor: TunnelActor

lazy var logger = Logger(label: "MixnetTunnel")
var logInitFailure: String?

override init() {
Self.configureLogger()
tunnelActor = TunnelActor()

super.init()

self.configureLogger()

LoggingSystem.bootstrap { label in
let fileLogHandler = FileLogHandler(label: label, logFileManager: LogFileManager(logFileType: .tunnel))
#if DEBUG
Expand All @@ -27,8 +33,6 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
return fileLogHandler
#endif
}

tunnelActor = TunnelActor()
}

override func startTunnel(options: [String: NSObject]? = nil) async throws {
Expand Down Expand Up @@ -125,16 +129,20 @@ extension PacketTunnelProvider {
}
}

static func configureLogger() {
func configureLogger() {
let logPath = LogFileManager.logFileURL(logFileType: .library)?.path()

Task {
let logLevel = await MainActor.run { ConfigurationManager.shared.debugLevel }
await initLogger(
path: logPath,
debugLevel: logLevel,
sentryMonitoring: true
)
do {
try await initLogger(
path: logPath,
debugLevel: logLevel,
sentryMonitoring: true
)
} catch {
self.logInitFailure = error.localizedDescription
}
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions nym-vpn-apple/NymMixnetTunnel/TunnelActor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ actor TunnelActor {

func setTunnelProvider(_ tunnelProvider: NEPacketTunnelProvider?) {
self.tunnelProvider = tunnelProvider

if let provider = tunnelProvider as? PacketTunnelProvider,
let failure = provider.logInitFailure
{
lastError = .createLogFailed(failure)
}
}

private func setCurrentState(_ state: TunnelState) async {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Foundation

public enum PacketTunnelProviderError: String, Error {
case failedToInitLogging
case invalidSavedConfiguration
case backendStartFailure
case noCredentialDataDir
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Theme

public enum VPNErrorReason: LocalizedError {
case initialization(details: String)
case createLogFile(details: String)
case internalError(details: String)
case storage(details: String)
case networkConnectionError(details: String)
Expand Down Expand Up @@ -44,6 +45,8 @@ public enum VPNErrorReason: LocalizedError {
switch vpnError {
case let .Initialization(details: details):
self = .initialization(details: details)
case let .CreateLogFile(details: details):
self = .createLogFile(details: details)
case let .InternalError(details: details):
self = .internalError(details: details)
case let .Storage(details: details):
Expand Down Expand Up @@ -231,6 +234,8 @@ public enum VPNErrorReason: LocalizedError {
switch errorReason {
case .initialization:
self = .initialization(details: nsError.userInfo["details"] as? String ?? Self.somethingWentWrong)
case .createLogFile:
self = .createLogFile(details: nsError.userInfo["details"] as? String ?? Self.somethingWentWrong)
case .internalError:
self = .internalError(details: nsError.userInfo["details"] as? String ?? Self.somethingWentWrong)
case .storage:
Expand Down Expand Up @@ -317,6 +322,8 @@ extension VPNErrorReason {
switch self {
case let .internalError(details):
details
case let .createLogFile(details):
details
case let .storage(details):
details
case let .networkConnectionError(details):
Expand Down Expand Up @@ -384,6 +391,7 @@ extension VPNErrorReason: Equatable {
/// The VPNErrorReasonCode mirrors the error codes as raw integers and can be constructed from a VPNErrorReason.
enum VPNErrorReasonCode: Int, RawRepresentable {
case initialization
case createLogFile
case internalError
case storage
case networkConnectionError
Expand Down Expand Up @@ -416,6 +424,8 @@ enum VPNErrorReasonCode: Int, RawRepresentable {
switch vpnErrorReason {
case .initialization:
self = .initialization
case .createLogFile:
self = .createLogFile
case .internalError:
self = .internalError
case .storage:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ public enum ErrorReason: LocalizedError, Codable {
case offline
case noAccountStored
case noDeviceStored
// PacketTunnelProvider
case createLogFailed(String)
// Tunnel
case setFirewallPolicy
case setRouting
Expand Down Expand Up @@ -114,6 +116,8 @@ public enum ErrorReason: LocalizedError, Codable {
self = .noAccountStored
case .noDeviceStored:
self = .noDeviceStored
case .createLogFailed:
self = .createLogFailed("Unknown")
case .setFirewallPolicy:
self = .setFirewallPolicy
case .setRouting:
Expand Down Expand Up @@ -201,6 +205,8 @@ extension ErrorReason {
private extension ErrorReason {
var description: String {
switch self {
case .createLogFailed(let message):
"errorReason.createLogFailed".localizedString + ": " + message
case .setFirewallPolicy:
"errorReason.firewall".localizedString
case .setRouting:
Expand Down Expand Up @@ -285,6 +291,7 @@ enum ErrorReasonCode: Int, RawRepresentable {
case offline
case noAccountStored
case noDeviceStored
case createLogFailed
case setFirewallPolicy
case setRouting
case setDns
Expand Down Expand Up @@ -323,6 +330,8 @@ enum ErrorReasonCode: Int, RawRepresentable {
self = .noAccountStored
case .noDeviceStored:
self = .noDeviceStored
case .createLogFailed:
self = .createLogFailed
case .internalUnknown:
self = .internalUnknown
case .sameEntryAndExitGateway:
Expand Down
5 changes: 4 additions & 1 deletion nym-vpn-core/crates/nym-firewall/src/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ pub static ALLOWED_LAN_NETS: LazyLock<[IpNetwork; 6]> = LazyLock::new(|| {
]
});
/// When "allow local network" is enabled the app will allow traffic to these networks.
#[cfg_attr(target_os = "windows", allow(unused))]
#[cfg_attr(
any(target_os = "windows", target_os = "android", target_os = "ios"),
allow(unused)
)]
pub static ALLOWED_LAN_MULTICAST_NETS: LazyLock<[IpNetwork; 8]> = LazyLock::new(|| {
[
// Local network broadcast. Not routable
Expand Down
7 changes: 5 additions & 2 deletions nym-vpn-core/crates/nym-vpn-lib-uniffi/src/android.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@

use log::LevelFilter;

pub(crate) fn init_logs(level: String) {
use crate::error::VpnError;

pub(crate) fn init_logs(level: String) -> Result<(), VpnError> {
use android_logger::{Config, FilterBuilder};
let levels = level + ",tungstenite=warn,mio=warn,tokio_tungstenite=warn";

Expand All @@ -16,5 +18,6 @@ pub(crate) fn init_logs(level: String) {
.with_tag("libnymvpn")
.with_filter(FilterBuilder::new().parse(levels.as_str()).build()),
);
tracing::debug!("Logger initialized");

Ok(())
}
3 changes: 3 additions & 0 deletions nym-vpn-core/crates/nym-vpn-lib-uniffi/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ pub enum VpnError {
#[error("initialization error: {details}")]
Initialization { details: String },

#[error("failed to create log file: {details}")]
CreateLogFile { details: String },

#[error("storage error: {details}")]
Storage { details: String },

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ use sentry::integrations::tracing as sentry_tracing;
use tracing::Level;
use tracing_oslog::OsLogger;
use tracing_subscriber::{
Layer, Registry, filter::LevelFilter, fmt::Layer as fmtLayer, layer::SubscriberExt,
util::SubscriberInitExt,
filter::LevelFilter, fmt::Layer as fmtLayer, layer::SubscriberExt, util::SubscriberInitExt, Layer,
Registry,
};

pub fn init_logs(level: String, path: Option<PathBuf>, sentry: bool) {
use crate::error::VpnError;

pub fn init_logs(level: String, path: Option<PathBuf>, sentry: bool) -> Result<(), VpnError> {
let oslogger_layer = OsLogger::new("net.nymtech.vpn.agent", "default");

let filter = tracing_subscriber::EnvFilter::builder()
Expand Down Expand Up @@ -41,36 +43,38 @@ pub fn init_logs(level: String, path: Option<PathBuf>, sentry: bool) {
let registry = Registry::default().with(oslogger_layer);

let mut layers = Vec::new();
let file_layer = path.as_ref().and_then(|path| {

if let Some(path) = &path {
// Ensure log directory exists
if let Some(parent) = path.parent()
&& !parent.exists()
&& let Err(e) = std::fs::create_dir_all(parent)
{
eprintln!("Failed to create log directory {}: {e}", parent.display());
return Err(VpnError::CreateLogFile {
details: format!("Failed to create log directory {}: {e}", parent.display()),
});
}

// Attempting to get the tracing_appending solution to work was not successful.
// Falling back to a more basic solution that does not support log rotation, for now.

// Attempt to open the log file for writing
OpenOptions::new()
let file = match OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(path)
.ok()
.map(|file| {
fmtLayer::default()
.with_writer(file)
.with_ansi(false)
.compact()
})
});
.map_err(|e| VpnError::CreateLogFile {)
details: format!("Failed to open log file {}: {e}", path.display()),
})?;

let file_layer = fmtLayer::default()
.with_writer(file)
.with_ansi(false)
.compact();

if let Some(file_layer) = file_layer {
layers.push(file_layer.boxed());
};
}

if sentry {
let layer = sentry_tracing::layer().event_filter(|md| match md.level() {
&Level::ERROR | &Level::WARN => sentry_tracing::EventFilter::Event,
Expand All @@ -80,11 +84,11 @@ pub fn init_logs(level: String, path: Option<PathBuf>, sentry: bool) {
layers.push(layer.boxed());
}

let result = registry.with(layers).with(filter).try_init();

if let Err(err) = result {
eprintln!("Failed to initialize logger: {err}");
} else {
tracing::debug!("Logger initialized level: {level}, path?:{path:?}");
}
registry
.with(layers)
.with(filter)
.try_init()
.map_err(|err| VpnError::CreateLogFile {
details: format!("Failed to initialize logger: {err}"),
})
}
28 changes: 21 additions & 7 deletions nym-vpn-core/crates/nym-vpn-lib-uniffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,11 @@ uniffi::setup_scaffolding!();

#[cfg(target_os = "android")]
pub mod android;
#[cfg(target_os = "ios")]
pub mod ios;

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

mod account;
mod environment;
Expand Down Expand Up @@ -204,7 +205,11 @@ async fn configure_lib_for_main_process(user_agent: UserAgent) -> Result<(), Vpn
Ok(())
}

async fn init_logger(path: Option<PathBuf>, debug_level: Option<String>, sentry_monitoring: bool) {
async fn init_logger(
path: Option<PathBuf>,
debug_level: Option<String>,
sentry_monitoring: bool,
) -> Result<(), VpnError> {
let default_log_level = env::var("RUST_LOG").unwrap_or("info".to_string());
let log_level = debug_level.unwrap_or(default_log_level);
tracing::info!("Setting log level: {log_level}, path?: {path:?}");
Expand All @@ -214,10 +219,19 @@ async fn init_logger(path: Option<PathBuf>, debug_level: Option<String>, sentry_
let mut guard = SENTRY_CLIENT.lock().await;
*guard = sentry_monitoring::init();
}

#[cfg(target_os = "ios")]
swift::init_logs(log_level, path, sentry_monitoring);
{
ios::init_logs(log_level, path, sentry_monitoring)
}
#[cfg(target_os = "android")]
android::init_logs(log_level);
{
android::init_logs(log_level)
}
#[cfg(not(any(target_os = "ios", target_os = "android")))]
{
Ok(())
}
}

/// Additional extra function for when only want to set the logger without initializing the
Expand All @@ -228,8 +242,8 @@ pub async fn initLogger(
path: Option<PathBuf>,
debug_level: Option<String>,
sentry_monitoring: bool,
) {
init_logger(path, debug_level, sentry_monitoring).await;
) -> Result<(), VpnError> {
init_logger(path, debug_level, sentry_monitoring).await
}

/// Returns the system messages for the current network environment
Expand Down
Loading