Skip to content
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
1 change: 1 addition & 0 deletions 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 packages/rs-platform-wallet-ffi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ hex = "0.4"
# corrupt rows so operators can detect snapshot drift without a
# native debugger attached.
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] }

# anyhow surfaces from `KeyType::try_from` / `Purpose::try_from`
# / `SecurityLevel::try_from` in dpp; we need the From impl in
Expand Down
30 changes: 30 additions & 0 deletions packages/rs-platform-wallet-ffi/build.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::path::Path;
use std::process::Command;
use std::{env, fs};

fn main() {
Expand All @@ -9,6 +10,23 @@ fn main() {
println!("cargo:rerun-if-changed=cbindgen.toml");
println!("cargo:rerun-if-changed=src/");

let commit = run_git(&["rev-parse", "HEAD"]).unwrap_or_else(|| "unknown".to_string());
println!("cargo:rustc-env=PLATFORM_WALLET_GIT_COMMIT={commit}");

let dirty = match run_git(&["status", "--porcelain"]) {
Some(out) if !out.is_empty() => "1",
Some(_) => "0",
None => "unknown",
};
Comment thread
ZocoLini marked this conversation as resolved.
println!("cargo:rustc-env=PLATFORM_WALLET_GIT_DIRTY={dirty}");
Comment thread
ZocoLini marked this conversation as resolved.

if let Some(head) = run_git(&["rev-parse", "--git-path", "HEAD"]) {
println!("cargo:rerun-if-changed={head}");
}
if let Some(index) = run_git(&["rev-parse", "--git-path", "index"]) {
println!("cargo:rerun-if-changed={index}");
}
Comment thread
ZocoLini marked this conversation as resolved.
Comment thread
ZocoLini marked this conversation as resolved.

let target_dir = Path::new(&out_dir)
.ancestors()
.nth(3) // This line moves up to the target/<PROFILE> directory
Expand All @@ -30,3 +48,15 @@ fn main() {
.expect("Unable to generate bindings")
.write_to_file(&output_path);
}

fn run_git(args: &[&str]) -> Option<String> {
let output = Command::new("git").args(args).output().ok()?;

if !output.status.success() {
return None;
}

String::from_utf8(output.stdout)
.ok()
.map(|s| s.trim().to_string())
}
2 changes: 2 additions & 0 deletions packages/rs-platform-wallet-ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ pub mod identity_top_up;
pub mod identity_transfer;
pub mod identity_update;
pub mod identity_withdrawal;
pub mod logging;
pub mod managed_identity;
pub mod manager;
pub mod manager_diagnostics;
Expand Down Expand Up @@ -104,6 +105,7 @@ pub use identity_top_up::*;
pub use identity_transfer::*;
pub use identity_update::*;
pub use identity_withdrawal::*;
pub use logging::*;
pub use managed_identity::*;
pub use manager::*;
pub use manager_diagnostics::*;
Expand Down
170 changes: 170 additions & 0 deletions packages/rs-platform-wallet-ffi/src/logging.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
use std::ffi::CStr;
use std::fs;
use std::path::{Path, PathBuf};
use std::sync::Mutex;

use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
use tracing_subscriber::Layer;

const VERSION: &str = env!("CARGO_PKG_VERSION");
const GIT_COMMIT: &str = env!("PLATFORM_WALLET_GIT_COMMIT");
const GIT_DIRTY: &str = env!("PLATFORM_WALLET_GIT_DIRTY");

/// Install the global `tracing` subscriber. Returns
/// `true` only when this call installed the subscriber.
///
/// A `false` return covers both (a) a subscriber was already
/// installed (first init wins) and (b) path couldn't be opened.
///
/// # Safety
/// - `path` must be a valid pointer to a null terminated string
/// or null.
#[no_mangle]
pub unsafe extern "C" fn platform_wallet_enable_file_logging(
level: u8,
path: *const std::ffi::c_char,
) -> bool {
if path.is_null() {
return false;
}

let Some(path) = CStr::from_ptr(path).to_str().ok().map(PathBuf::from) else {
return false;
};

enable_file_logging(level_to_directive(level), &path)
}

fn enable_file_logging(log_level: &str, path: &Path) -> bool {
let Some(f_sdk) = open_file(path.join("dash_sdk").join("run.log")) else {
return false;
};
let Some(f_pw) = open_file(path.join("platform_wallet").join("run.log")) else {
return false;
};
let Some(f_spv) = open_file(path.join("dash_spv").join("run.log")) else {
return false;
};
let Some(f_kw) = open_file(path.join("key_wallet").join("run.log")) else {
return false;
};
let Some(f_grpc) = open_file(path.join("grpc").join("run.log")) else {
return false;
};

let l_sdk = tracing_subscriber::fmt::layer()
.with_writer(Mutex::new(f_sdk))
Comment thread
coderabbitai[bot] marked this conversation as resolved.
.with_ansi(false)
.with_filter(tracing_subscriber::EnvFilter::new(format!(
"dash_sdk={log_level},rs_sdk_ffi={log_level}"
)));
Comment thread
ZocoLini marked this conversation as resolved.

let l_pw = tracing_subscriber::fmt::layer()
.with_writer(Mutex::new(f_pw))
.with_ansi(false)
.with_filter(tracing_subscriber::EnvFilter::new(format!(
"platform_wallet={log_level},platform_wallet_ffi={log_level}"
)));

let l_spv = tracing_subscriber::fmt::layer()
.with_writer(Mutex::new(f_spv))
.with_ansi(false)
.with_filter(tracing_subscriber::EnvFilter::new(format!(
"dash_spv={log_level}"
)));

let l_kw = tracing_subscriber::fmt::layer()
.with_writer(Mutex::new(f_kw))
.with_ansi(false)
.with_filter(tracing_subscriber::EnvFilter::new(format!(
"key_wallet={log_level}"
)));

let l_grpc = tracing_subscriber::fmt::layer()
.with_writer(Mutex::new(f_grpc))
.with_ansi(false)
.with_filter(tracing_subscriber::EnvFilter::new(format!(
"dapi_grpc={log_level},tonic={log_level},h2={log_level},\
hyper={log_level},tower={log_level}"
)));

if fs::write(path.join("build_info.txt"), build_info_string()).is_err() {
return false;
}

let stdout_layer = tracing_subscriber::fmt::layer().with_filter(broad_env_filter(log_level));

if tracing_subscriber::registry()
.with(stdout_layer)
.with(l_sdk)
.with(l_pw)
.with(l_spv)
.with(l_kw)
.with(l_grpc)
.try_init()
.is_err()
{
return false;
}

tracing::info!(level = log_level, "file logging enabled");
true
}
Comment thread
ZocoLini marked this conversation as resolved.
Comment thread
ZocoLini marked this conversation as resolved.
Comment thread
ZocoLini marked this conversation as resolved.
Comment thread
ZocoLini marked this conversation as resolved.

fn open_file(path: PathBuf) -> Option<fs::File> {
if let Some(parent) = path.parent() {
fs::create_dir_all(parent).ok()?;
}

fs::OpenOptions::new()
.create(true)
.append(true)
.open(&path)
.ok()
}

fn broad_env_filter(log_level: &str) -> tracing_subscriber::EnvFilter {
let directives = format!(
"dash_sdk={log_level},rs_sdk={log_level},rs_sdk_ffi={log_level},\
platform_wallet={log_level},platform_wallet_ffi={log_level},\
dash_spv={log_level},key_wallet={log_level},\
dapi_grpc={log_level},h2={log_level},tower={log_level},\
hyper={log_level},tonic={log_level}"
);

tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| tracing_subscriber::EnvFilter::new(directives))
}

fn level_to_directive(level: u8) -> &'static str {
match level {
0 => "error",
1 => "warn",
2 => "info",
3 => "debug",
4 => "trace",
_ => "info",
}
}

fn build_info_string() -> String {
let dirty = match GIT_DIRTY {
"0" => "no",
"1" => "yes",
_ => "unknown",
};
let mut out = format!(
"platform-wallet-version: {VERSION}\n\
git-commit: {GIT_COMMIT}\n\
git-dirty: {dirty}\n\
# to reproduce: git checkout {GIT_COMMIT}\n"
);
if dirty == "yes" {
out.push_str(
"# WARNING: this build had uncommitted changes; the commit hash above does NOT \
fully describe the source state.\n",
);
}
out
}
1 change: 1 addition & 0 deletions packages/swift-sdk/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
logs-*/
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,16 @@ public enum LoggingPreferences {
let preset = loadPreset()
let enableSwiftVerbose: Bool

// File logging is gated to the iOS Simulator
#if targetEnvironment(simulator)
if let sessionRoot = launchLogPaths(),
SDK.enableFileLogging(level: .info, sessionRoot: sessionRoot) {
} else {
SDK.enableLogging(level: .info)
}
#else
SDK.enableLogging(level: .info)
#endif

switch preset {
case .high:
Expand All @@ -45,6 +54,26 @@ public enum LoggingPreferences {
return preset
}

private static func launchLogPaths() -> String? {
guard
let libraryURL = FileManager.default
.urls(for: .libraryDirectory, in: .userDomainMask).first
else {
return nil
}

let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "yyyy-MM-dd'T'HH-mm-ss'Z'"

return libraryURL
.appendingPathComponent("Logs", isDirectory: true)
.appendingPathComponent("SwiftDashSDK", isDirectory: true)
.appendingPathComponent(formatter.string(from: Date()), isDirectory: true)
.path
}

public static var preset: LoggingPreset { loadPreset() }

public static var shouldEmitDefaultLogs: Bool { preset == .high }
Expand Down
15 changes: 15 additions & 0 deletions packages/swift-sdk/Sources/SwiftDashSDK/SDK.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,21 @@ public final class SDK: @unchecked Sendable {
print("🔵 SDK: Logging enabled at level: \(level)")
}

/// Route the global tracing subscriber to per-bucket files under
/// `sessionRoot`. Returns `false` if a subscriber was already
/// installed or the path couldn't be written.
@discardableResult
public static func enableFileLogging(
level: LogLevel = .debug,
sessionRoot: String
) -> Bool {
let installed = sessionRoot.withCString { ptr in
platform_wallet_enable_file_logging(level.rawValue, ptr)
}

return installed
}

/// Local Platform DAPI addresses; override via UserDefaults key "platformDAPIAddresses"
private static var platformDAPIAddresses: String {
if let override = UserDefaults.standard.string(forKey: "platformDAPIAddresses"), !override.isEmpty {
Expand Down
Loading
Loading