From 8f4d2a34e24f7144addaaa630dbaf68efff58aa1 Mon Sep 17 00:00:00 2001 From: Zhidong Peng Date: Fri, 13 Jun 2025 14:12:50 -0700 Subject: [PATCH 01/12] Push file logs to telemetry events (#243) * Push logs to events * Get the correct caller and module name for async functions. * Fix the UT failure in code coverage tests * Fix codecoverage run in windows * update unit test for config --- .github/actions/spelling/expect.txt | 1 + Cargo.lock | 1 + proxy_agent/Cargo.toml | 2 +- proxy_agent/config/GuestProxyAgent.linux.json | 3 +- .../config/GuestProxyAgent.windows.json | 3 +- proxy_agent/src/common/config.rs | 26 ++++++- proxy_agent/src/common/logger.rs | 18 +++++ proxy_agent/src/proxy/proxy_connection.rs | 23 +++++- proxy_agent_shared/Cargo.toml | 1 + proxy_agent_shared/src/logger.rs | 78 +++++++++++++++++++ .../src/telemetry/event_logger.rs | 16 ++-- 11 files changed, 157 insertions(+), 15 deletions(-) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index dbf81dd8..a8479979 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -40,6 +40,7 @@ collectguestlogs commandline comspec consoleloggerparameters +covrec CPlat cplusplus cpptools diff --git a/Cargo.lock b/Cargo.lock index 45e5c667..89417abf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -801,6 +801,7 @@ dependencies = [ name = "proxy_agent_shared" version = "9.9.9" dependencies = [ + "backtrace", "concurrent-queue", "ctor", "log", diff --git a/proxy_agent/Cargo.toml b/proxy_agent/Cargo.toml index 5ba092f5..7a690c3f 100644 --- a/proxy_agent/Cargo.toml +++ b/proxy_agent/Cargo.toml @@ -16,7 +16,7 @@ serde-xml-rs = "0.6.0" # xml Deserializer bitflags = "2.6.0" # support bitflag enum hmac-sha256 = "1.1.6" # use HMAC using the SHA-256 hash function hex = "0.4.3" # hex encode -regex = "1.11" # match process name in cmdline +regex = "1.11" # match process name in cmdline tokio = { version = "1", features = ["rt", "rt-multi-thread", "time", "net", "macros", "sync"] } tokio-util = "0.7.11" http = "1.1.0" diff --git a/proxy_agent/config/GuestProxyAgent.linux.json b/proxy_agent/config/GuestProxyAgent.linux.json index 0bdfa956..03288fc3 100644 --- a/proxy_agent/config/GuestProxyAgent.linux.json +++ b/proxy_agent/config/GuestProxyAgent.linux.json @@ -7,5 +7,6 @@ "hostGAPluginSupport": 1, "ebpfProgramName": "ebpf_cgroup.o", "cgroupRoot": "/sys/fs/cgroup", - "fileLogLevel": "Trace" + "fileLogLevel": "Trace", + "fileLogLevelForEvents": "Info" } \ No newline at end of file diff --git a/proxy_agent/config/GuestProxyAgent.windows.json b/proxy_agent/config/GuestProxyAgent.windows.json index 9827ecc7..db05cdda 100644 --- a/proxy_agent/config/GuestProxyAgent.windows.json +++ b/proxy_agent/config/GuestProxyAgent.windows.json @@ -6,5 +6,6 @@ "pollKeyStatusIntervalInSeconds": 15, "hostGAPluginSupport": 1, "ebpfProgramName": "redirect.bpf.sys", - "fileLogLevel": "Trace" + "fileLogLevel": "Trace", + "fileLogLevelForEvents": "Info" } \ No newline at end of file diff --git a/proxy_agent/src/common/config.rs b/proxy_agent/src/common/config.rs index b5a52200..dc8d6374 100644 --- a/proxy_agent/src/common/config.rs +++ b/proxy_agent/src/common/config.rs @@ -70,6 +70,10 @@ pub fn get_file_log_level() -> LoggerLevel { SYSTEM_CONFIG.get_file_log_level() } +pub fn get_file_log_level_for_events() -> Option { + SYSTEM_CONFIG.get_file_log_level_for_events() +} + #[derive(Serialize, Deserialize)] #[allow(non_snake_case)] pub struct Config { @@ -89,6 +93,8 @@ pub struct Config { #[serde(skip_serializing_if = "Option::is_none")] #[cfg(not(windows))] cgroupRoot: Option, + #[serde(skip_serializing_if = "Option::is_none")] + fileLogLevelForEvents: Option, } impl Default for Config { @@ -179,6 +185,14 @@ impl Config { None => PathBuf::from(constants::CGROUP_ROOT), } } + + pub fn get_file_log_level_for_events(&self) -> Option { + if let Some(file_log_level) = &self.fileLogLevelForEvents { + let log_level = LoggerLevel::from_str(file_log_level).unwrap_or(LoggerLevel::Info); + return Some(log_level); + } + None + } } #[cfg(test)] @@ -260,6 +274,12 @@ mod tests { ); } + assert_eq!( + proxy_agent_shared::logger::LoggerLevel::Info, + config.get_file_log_level_for_events().unwrap(), + "get_file_log_level_for_events mismatch" + ); + // clean up _ = fs::remove_dir_all(&temp_test_path); } @@ -275,7 +295,8 @@ mod tests { "wireServerSupport": 2, "hostGAPluginSupport": 1, "imdsSupport": 1, - "ebpfProgramName": "ebpfProgramName" + "ebpfProgramName": "ebpfProgramName", + "fileLogLevelForEvents": "Info" }"# } else { r#"{ @@ -287,7 +308,8 @@ mod tests { "wireServerSupport": 2, "hostGAPluginSupport": 1, "imdsSupport": 1, - "ebpfProgramName": "ebpfProgramName" + "ebpfProgramName": "ebpfProgramName", + "fileLogLevelForEvents": "Info" }"# }; diff --git a/proxy_agent/src/common/logger.rs b/proxy_agent/src/common/logger.rs index 155b8bb0..d4019168 100644 --- a/proxy_agent/src/common/logger.rs +++ b/proxy_agent/src/common/logger.rs @@ -4,8 +4,11 @@ use crate::common::cli; use proxy_agent_shared::{ logger::{logger_manager, LoggerLevel}, misc_helpers, + telemetry::event_logger, }; +use super::config; + pub const AGENT_LOGGER_KEY: &str = "Agent_Logger"; pub fn write(message: String) { @@ -28,6 +31,21 @@ fn log(log_level: LoggerLevel, message: String) { if log_level != LoggerLevel::Trace { write_console_log(message.to_string()); }; + + if let Some(log_for_event) = config::get_file_log_level_for_events() { + if log_for_event >= log_level { + // write to event + let (module_name, caller_name) = + proxy_agent_shared::logger::get_caller_info("proxy_agent::common::logger"); + event_logger::write_event_only( + log_level, + message.to_string(), + &caller_name, + &module_name, + ); + } + } + logger_manager::log(AGENT_LOGGER_KEY.to_string(), log_level, message); } diff --git a/proxy_agent/src/proxy/proxy_connection.rs b/proxy_agent/src/proxy/proxy_connection.rs index 0b034a69..807d1da7 100644 --- a/proxy_agent/src/proxy/proxy_connection.rs +++ b/proxy_agent/src/proxy/proxy_connection.rs @@ -290,15 +290,32 @@ impl ConnectionLogger { } pub fn write(&mut self, logger_level: LoggerLevel, message: String) { + let message = format!( + "{}[{}] - {}", + self.http_connection_id, self.tcp_connection_id, message + ); + if let Some(log_for_event) = crate::common::config::get_file_log_level_for_events() { + if log_for_event >= logger_level { + // write to event + let (module_name, caller_name) = proxy_agent_shared::logger::get_caller_info( + "proxy_agent::proxy::proxy_connection", + ); + proxy_agent_shared::telemetry::event_logger::write_event_only( + logger_level, + message.to_string(), + &caller_name, + &module_name, + ); + } + } + if logger_level > logger_manager::get_logger_level() { return; } self.queue.push(format!( - "{}{}[{}] - {}", + "{}{}", logger::get_log_header(logger_level), - self.http_connection_id, - self.tcp_connection_id, message )); } diff --git a/proxy_agent_shared/Cargo.toml b/proxy_agent_shared/Cargo.toml index 3e6e14a0..77ee5be8 100644 --- a/proxy_agent_shared/Cargo.toml +++ b/proxy_agent_shared/Cargo.toml @@ -18,6 +18,7 @@ thiserror = "1.0.64" tokio = { version = "1", features = ["rt", "macros", "sync", "time"] } log = { version = "0.4.26", features = ["std"] } ctor = "0.3.6" # used for test setup and clean up +backtrace = "0.3" # used for get the caller module and function name [target.'cfg(windows)'.dependencies] windows-service = "0.7.0" # windows NT service diff --git a/proxy_agent_shared/src/logger.rs b/proxy_agent_shared/src/logger.rs index 0eb677f3..165d48dd 100644 --- a/proxy_agent_shared/src/logger.rs +++ b/proxy_agent_shared/src/logger.rs @@ -17,6 +17,71 @@ pub fn get_log_header(level: LoggerLevel) -> String { .to_string() } +const ASYNC_FUNCTION_NAME: &str = "{closure"; +const INTERNAL_BACKTRACE: &str = "backtrace"; +const CURRENT_FUNCTION: &str = "::logger::get_caller_info"; +const RUNTIME_TASK_SCHEDULER: &str = "::runtime::task::Schedule"; // The runtime scheduler function that runs the tasks + +#[cfg(test)] +const TEST_CODE_COVERAGE_FUNCTIONS: &str = "__covrec_"; // code coverage recording, generated by a code coverage tool such as llvm-cov, or a similar instrumentation framework +#[cfg(test)] +const TEST_INTERNAL_FUNCTION: &str = "test::run_test"; // The test framework's internal function that runs the tests + +pub fn get_caller_info(module_to_skip: &str) -> (String, String) { + let bt = backtrace::Backtrace::new(); + for frame in bt.frames().iter() { + for symbol in frame.symbols() { + if let Some(name) = symbol.name() { + let name_str = name.to_string(); + + let mut found_function: bool = true; + // Skip internal frames, current function frame and `module_to_skip` to find the first relevant caller + found_function = found_function + && !name_str.contains(INTERNAL_BACKTRACE) + && !name_str.contains(CURRENT_FUNCTION) + && !name_str.contains(RUNTIME_TASK_SCHEDULER) + && !name_str.contains(module_to_skip); + + #[cfg(test)] + { + found_function = found_function + && !name_str.contains(TEST_CODE_COVERAGE_FUNCTIONS) + && !name_str.starts_with(TEST_INTERNAL_FUNCTION); + } + + if found_function { + // If the name contains `{{closure}}`, it indicates an async function + // We need to find the first segment that contains the async function name + // Example: `azure_proxy_agent::proxy::proxy_server::ProxyServer::handle_new_tcp_connection::{{closure}}::{{closure}}::h537d19fb7a504d22` + let seg = name_str.split("::").collect::>(); + let seg_len = seg.len(); + let mut function_last_index = 0; + for i in 0..seg_len { + if seg[seg_len - 1 - i].contains(ASYNC_FUNCTION_NAME) { + function_last_index = i + 1; + } + } + let caller_name = seg + .get(seg_len - 1 - function_last_index) + .unwrap_or(&"unknown") + .to_string(); + // Get the module name from the first to `function_last_index` segment + let module_name = seg + .into_iter() + .map(String::from) + .collect::>() + .into_iter() + .take(seg_len - 1 - function_last_index) + .collect::>() + .join("::"); + return (module_name, caller_name); + } + } + } + } + ("unknown".to_string(), "unknown".to_string()) +} + #[cfg(test)] mod tests { use log::Level; @@ -39,4 +104,17 @@ mod tests { "Trace level should be greater than or equal to Trace level" ); } + + #[tokio::test] + async fn invoke_get_caller_info_test() { + test_get_caller_info_test("invoke_get_caller_info_test"); + } + + fn test_get_caller_info_test(expected_caller_name: &str) { + let (module_name, caller_name) = super::get_caller_info("test_get_caller_info_test"); + println!("Module Name: {}", module_name); + println!("Caller Name: {}", caller_name); + // Check if the caller name is as expected + assert_eq!(caller_name, expected_caller_name); + } } diff --git a/proxy_agent_shared/src/telemetry/event_logger.rs b/proxy_agent_shared/src/telemetry/event_logger.rs index a9731c7b..3af4d8ef 100644 --- a/proxy_agent_shared/src/telemetry/event_logger.rs +++ b/proxy_agent_shared/src/telemetry/event_logger.rs @@ -128,25 +128,27 @@ pub fn write_event( module_name: &str, logger_key: &str, ) { + write_event_only(level, message.to_string(), method_name, module_name); + + // wrap file log within event log + logger_manager::log(logger_key.to_string(), level, message); +} + +pub fn write_event_only(level: Level, message: String, method_name: &str, module_name: &str) { let event_message = if message.len() > MAX_MESSAGE_LENGTH { message[..MAX_MESSAGE_LENGTH].to_string() } else { message.to_string() }; - let logger_key = logger_key.to_string(); match EVENT_QUEUE.push(Event::new( level.to_string(), event_message, method_name.to_string(), module_name.to_string(), )) { - Ok(()) => { - // wrap file log within event log - logger_manager::log(logger_key, level, message); - } + Ok(()) => {} Err(e) => { - logger_manager::log( - logger_key, + logger_manager::write_log( Level::Warn, format!("Failed to push event to the queue with error: {}", e), ); From bf6bd1621932a3c566ab8c8f32ba3be6326b7759 Mon Sep 17 00:00:00 2001 From: Zhidong Peng Date: Tue, 17 Jun 2025 13:35:18 -0700 Subject: [PATCH 02/12] upgrade windows-sys to 0.52.0 (#244) --- .github/actions/spelling/expect.txt | 2 +- Cargo.lock | 89 ++++++----------------------- proxy_agent/Cargo.toml | 6 +- proxy_agent/src/common/windows.rs | 18 +++--- proxy_agent/src/proxy/windows.rs | 15 +++-- proxy_agent_shared/Cargo.toml | 2 +- proxy_agent_shared/src/windows.rs | 10 ++-- 7 files changed, 48 insertions(+), 94 deletions(-) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index a8479979..ea183bb5 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -158,7 +158,7 @@ logdir Loggerhas logon Lrs -Lsa +lsa ltsc luid macikgo diff --git a/Cargo.lock b/Cargo.lock index 89417abf..982d70ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -99,7 +99,7 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -109,7 +109,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -192,7 +192,7 @@ dependencies = [ "winapi", "windows-acl", "windows-service", - "windows-sys 0.42.0", + "windows-sys", "winres", ] @@ -680,7 +680,7 @@ dependencies = [ "hermit-abi", "libc", "wasi", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -746,7 +746,7 @@ checksum = "ae99c7fa6dd38c7cafe1ec085e804f8f555a2f8659b0dbe03f1f9963a9b51092" dependencies = [ "log", "serde", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -816,7 +816,7 @@ dependencies = [ "time", "tokio", "windows-service", - "windows-sys 0.42.0", + "windows-sys", "winreg", ] @@ -1001,7 +1001,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -1121,7 +1121,7 @@ dependencies = [ "pin-project-lite", "socket2", "tokio-macros", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -1368,22 +1368,7 @@ checksum = "d24d6bcc7f734a4091ecf8d7a64c5f7d7066f45585c1861eba06449909609c8a" dependencies = [ "bitflags", "widestring 1.1.0", - "windows-sys 0.52.0", -] - -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows-sys", ] [[package]] @@ -1401,46 +1386,28 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -1453,48 +1420,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" diff --git a/proxy_agent/Cargo.toml b/proxy_agent/Cargo.toml index 7a690c3f..f16a52c3 100644 --- a/proxy_agent/Cargo.toml +++ b/proxy_agent/Cargo.toml @@ -62,8 +62,10 @@ winres = "0.1.12" # Rust Windows resource helper to add file version static_vcruntime = "2.0.0" # Statically link the VCRuntime when using the MSVC toolchain [target.'cfg(windows)'.dependencies.windows-sys] -version = "0.42.0" +version = "0.52.0" features = [ + "Wdk_Foundation", + "Wdk_System_Threading", "Win32_Foundation", "Win32_Networking_WinSock", "Win32_System_IO", @@ -76,7 +78,7 @@ features = [ "Win32_System_ProcessStatus", "Win32_System_Kernel", "Win32_Security_Cryptography", - "Win32_System_Memory", + "Win32_System_Memory" ] [features] diff --git a/proxy_agent/src/common/windows.rs b/proxy_agent/src/common/windows.rs index a6f34c9e..5513695e 100644 --- a/proxy_agent/src/common/windows.rs +++ b/proxy_agent/src/common/windows.rs @@ -12,7 +12,7 @@ use windows_sys::Win32::Security::Cryptography::{ // msasn1.dll (ASN.1 library) is also used by crypt32.dll CryptProtectData, CryptUnprotectData, - CRYPTOAPI_BLOB, + CRYPT_INTEGER_BLOB, }; use windows_sys::Win32::System::SystemInformation::{ GetSystemInfo, // kernel32.dll @@ -46,11 +46,11 @@ pub fn get_memory_in_mb() -> Result { pub fn store_key_data(encrypted_file_path: &Path, key_data: String) -> Result<()> { let data = key_data.as_bytes(); - let data_in = CRYPTOAPI_BLOB { + let data_in = CRYPT_INTEGER_BLOB { cbData: data.len() as u32, pbData: data.as_ptr() as *mut u8, }; - let mut data_out = CRYPTOAPI_BLOB { + let mut data_out = CRYPT_INTEGER_BLOB { cbData: 0, pbData: std::ptr::null_mut(), }; @@ -73,7 +73,9 @@ pub fn store_key_data(encrypted_file_path: &Path, key_data: String) -> Result<() let encrypted_data = unsafe { std::slice::from_raw_parts(data_out.pbData, data_out.cbData as usize).to_vec() }; - unsafe { windows_sys::Win32::System::Memory::LocalFree(data_out.pbData as isize) }; + unsafe { + windows_sys::Win32::Foundation::LocalFree(data_out.pbData as *mut ::core::ffi::c_void) + }; std::fs::write(encrypted_file_path, encrypted_data).map_err(|e| { Error::Io( format!( @@ -97,11 +99,11 @@ pub fn fetch_key_data(encrypted_file_path: &Path) -> Result { e, ) })?; - let data_in = CRYPTOAPI_BLOB { + let data_in = CRYPT_INTEGER_BLOB { cbData: encrypted_data.len() as u32, pbData: encrypted_data.as_ptr() as *mut u8, }; - let mut data_out = CRYPTOAPI_BLOB { + let mut data_out = CRYPT_INTEGER_BLOB { cbData: 0, pbData: std::ptr::null_mut(), }; @@ -125,7 +127,9 @@ pub fn fetch_key_data(encrypted_file_path: &Path) -> Result { let decrypted_data = unsafe { std::slice::from_raw_parts(data_out.pbData as *const u8, data_out.cbData as usize).to_vec() }; - unsafe { windows_sys::Win32::System::Memory::LocalFree(data_out.pbData as isize) }; + unsafe { + windows_sys::Win32::Foundation::LocalFree(data_out.pbData as *mut ::core::ffi::c_void) + }; let key_data = String::from_utf8_lossy(&decrypted_data).to_string(); Ok(key_data) diff --git a/proxy_agent/src/proxy/windows.rs b/proxy_agent/src/proxy/windows.rs index fe96ed9e..c75869d4 100644 --- a/proxy_agent/src/proxy/windows.rs +++ b/proxy_agent/src/proxy/windows.rs @@ -11,18 +11,23 @@ use once_cell::sync::Lazy; use std::mem::MaybeUninit; use std::ptr::null_mut; use std::{collections::HashMap, ffi::OsString, os::windows::ffi::OsStringExt, path::PathBuf}; +use windows_sys::Wdk::System::Threading::{ + NtQueryInformationProcess, // ntdll.dll + PROCESSINFOCLASS, +}; use windows_sys::Win32::Foundation::{BOOL, HANDLE, LUID, NTSTATUS, UNICODE_STRING}; use windows_sys::Win32::Security::Authentication::Identity; -use windows_sys::Win32::Security::Authentication::Identity::SECURITY_LOGON_SESSION_DATA; +use windows_sys::Win32::Security::Authentication::Identity::{ + LSA_UNICODE_STRING, SECURITY_LOGON_SESSION_DATA, +}; use windows_sys::Win32::System::ProcessStatus::{ K32GetModuleBaseNameW, // kernel32.dll K32GetModuleFileNameExW, // kernel32.dll }; +use windows_sys::Win32::System::Threading::PROCESS_BASIC_INFORMATION; use windows_sys::Win32::System::Threading::{ - NtQueryInformationProcess, // ntdll.dll - OpenProcess, //kernel32.dll + OpenProcess, //kernel32.dll }; -use windows_sys::Win32::System::Threading::{PROCESSINFOCLASS, PROCESS_BASIC_INFORMATION}; const LG_INCLUDE_INDIRECT: u32 = 1u32; const MAX_PREFERRED_LENGTH: u32 = 4294967295u32; @@ -179,7 +184,7 @@ pub fn get_user(logon_id: u64) -> Result<(String, Vec)> { Ok((user_name, user_groups)) } -fn from_unicode_string(unicode_string: &UNICODE_STRING) -> String { +fn from_unicode_string(unicode_string: &LSA_UNICODE_STRING) -> String { let mut v = vec![0u16; unicode_string.Length as usize]; unsafe { std::ptr::copy_nonoverlapping( diff --git a/proxy_agent_shared/Cargo.toml b/proxy_agent_shared/Cargo.toml index 77ee5be8..ef217730 100644 --- a/proxy_agent_shared/Cargo.toml +++ b/proxy_agent_shared/Cargo.toml @@ -25,7 +25,7 @@ windows-service = "0.7.0" # windows NT service winreg = "0.11.0" # windows reg read/write [target.'cfg(windows)'.dependencies.windows-sys] -version = "0.42.0" +version = "0.52.0" features = [ "Win32_Foundation", "Win32_Networking_WinSock", diff --git a/proxy_agent_shared/src/windows.rs b/proxy_agent_shared/src/windows.rs index 27f2e0d3..c9e1fb14 100644 --- a/proxy_agent_shared/src/windows.rs +++ b/proxy_agent_shared/src/windows.rs @@ -174,11 +174,11 @@ pub fn get_processor_arch() -> String { .Anonymous .wProcessorArchitecture { - windows_sys::Win32::System::Diagnostics::Debug::PROCESSOR_ARCHITECTURE_INTEL => "x86", // 0 - windows_sys::Win32::System::Diagnostics::Debug::PROCESSOR_ARCHITECTURE_ARM => "ARM", // 5 - windows_sys::Win32::System::Diagnostics::Debug::PROCESSOR_ARCHITECTURE_IA64 => "IA64", // 6 - windows_sys::Win32::System::Diagnostics::Debug::PROCESSOR_ARCHITECTURE_AMD64 => "AMD64", // 9 - 12 => "ARM64", // 12 - ARM64 is missed here + windows_sys::Win32::System::SystemInformation::PROCESSOR_ARCHITECTURE_INTEL => "x86", // 0 + windows_sys::Win32::System::SystemInformation::PROCESSOR_ARCHITECTURE_ARM => "ARM", // 5 + windows_sys::Win32::System::SystemInformation::PROCESSOR_ARCHITECTURE_IA64 => "IA64", // 6 + windows_sys::Win32::System::SystemInformation::PROCESSOR_ARCHITECTURE_AMD64 => "AMD64", // 9 + windows_sys::Win32::System::SystemInformation::PROCESSOR_ARCHITECTURE_ARM64 => "ARM64", // 12 _ => "unknown", } .to_owned() From 60cca9f235d08ccebdb318142b0d1dadae80dc11 Mon Sep 17 00:00:00 2001 From: Zhidong Peng Date: Tue, 17 Jun 2025 14:27:13 -0700 Subject: [PATCH 03/12] Fix GuestProxyAgentLoadedModulesValidationCase (#245) * Fix GuestProxyAgentLoadedModulesValidationCase * add more dll --- .../Resources/GuestProxyAgentLoadedModulesBaseline.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/e2etest/GuestProxyAgentTest/Resources/GuestProxyAgentLoadedModulesBaseline.txt b/e2etest/GuestProxyAgentTest/Resources/GuestProxyAgentLoadedModulesBaseline.txt index 32d1b5d5..0b7e8fc0 100644 --- a/e2etest/GuestProxyAgentTest/Resources/GuestProxyAgentLoadedModulesBaseline.txt +++ b/e2etest/GuestProxyAgentTest/Resources/GuestProxyAgentLoadedModulesBaseline.txt @@ -34,4 +34,9 @@ SAMLIB.dll WLDAP32.dll crypt32.dll msasn1.dll -version.dll \ No newline at end of file +version.dll +combase.dll +oleaut32.dll +msvcp_win.dll +symsrv.dll +shlwapi.dll \ No newline at end of file From 40e34fb2d986c0520071c5da5d07277eb9e34215 Mon Sep 17 00:00:00 2001 From: Zhidong Peng Date: Mon, 23 Jun 2025 12:03:51 -0700 Subject: [PATCH 04/12] Write GPA logs to system log (#246) * Add mod windows_event_logger * update the mod name * write logs to system log * fix spelling * fix ut * fix * formatting * fix --- .github/actions/spelling/expect.txt | 4 + Cargo.lock | 215 +++++++- proxy_agent/Cargo.toml | 2 +- proxy_agent/config/GuestProxyAgent.linux.json | 3 +- .../config/GuestProxyAgent.windows.json | 3 +- proxy_agent/src/common/config.rs | 26 +- proxy_agent/src/common/logger.rs | 18 - proxy_agent/src/host_clients/goal_state.rs | 7 + proxy_agent/src/proxy/proxy_connection.rs | 7 +- proxy_agent/src/proxy/proxy_server.rs | 1 - proxy_agent/src/service.rs | 16 +- proxy_agent_extension/src/logger.rs | 2 +- proxy_agent_setup/src/logger.rs | 2 +- proxy_agent_shared/Cargo.toml | 3 + proxy_agent_shared/src/etw.rs | 5 + proxy_agent_shared/src/etw/application.rs | 463 ++++++++++++++++++ proxy_agent_shared/src/lib.rs | 2 + .../src/logger/logger_manager.rs | 165 +++++-- proxy_agent_shared/src/windows.rs | 30 ++ 19 files changed, 900 insertions(+), 74 deletions(-) create mode 100644 proxy_agent_shared/src/etw.rs create mode 100644 proxy_agent_shared/src/etw/application.rs diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index ea183bb5..a04c71c9 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -3,6 +3,7 @@ AAFFBB aarch abe addrpair +advapi almalinux ATL ATLMFC @@ -88,7 +89,9 @@ etest etestoutputs etestsharedstorage EToken +etw EUID +EVENTLOG evt exampledatadiskname exampleosdiskname @@ -325,6 +328,7 @@ wdk wdksetup Werror westus +wevtapi WFP winapi windowsazureguestagent diff --git a/Cargo.lock b/Cargo.lock index 982d70ac..a72dcfb3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -63,6 +63,21 @@ version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anstream" version = "0.6.15" @@ -217,6 +232,12 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "bumpalo" +version = "3.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" + [[package]] name = "byteorder" version = "1.5.0" @@ -229,6 +250,15 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +[[package]] +name = "cc" +version = "1.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" +dependencies = [ + "shlex", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -241,6 +271,20 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "chrono" +version = "0.4.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link", +] + [[package]] name = "clap" version = "4.5.18" @@ -594,6 +638,30 @@ dependencies = [ "tokio", ] +[[package]] +name = "iana-time-zone" +version = "0.1.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core 0.61.2", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "indexmap" version = "2.7.1" @@ -625,6 +693,16 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + [[package]] name = "libc" version = "0.2.171" @@ -802,6 +880,7 @@ name = "proxy_agent_shared" version = "9.9.9" dependencies = [ "backtrace", + "chrono", "concurrent-queue", "ctor", "log", @@ -809,6 +888,7 @@ dependencies = [ "os_info", "regex", "serde", + "serde-xml-rs", "serde_derive", "serde_json", "thiserror", @@ -923,6 +1003,12 @@ dependencies = [ "semver", ] +[[package]] +name = "rustversion" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" + [[package]] name = "ryu" version = "1.0.18" @@ -946,9 +1032,9 @@ dependencies = [ [[package]] name = "serde-xml-rs" -version = "0.6.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb3aa78ecda1ebc9ec9847d5d3aba7d618823446a049ba2491940506da6e2782" +checksum = "53630160a98edebde0123eb4dfd0fce6adff091b2305db3154a9e920206eb510" dependencies = [ "log", "serde", @@ -979,6 +1065,12 @@ dependencies = [ "serde", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "slab" version = "0.4.9" @@ -1295,6 +1387,64 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + [[package]] name = "widestring" version = "0.4.3" @@ -1335,7 +1485,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ - "windows-core", + "windows-core 0.52.0", "windows-targets", ] @@ -1360,6 +1510,56 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-service" version = "0.7.0" @@ -1371,6 +1571,15 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.52.0" diff --git a/proxy_agent/Cargo.toml b/proxy_agent/Cargo.toml index f16a52c3..c5b14598 100644 --- a/proxy_agent/Cargo.toml +++ b/proxy_agent/Cargo.toml @@ -12,7 +12,7 @@ once_cell = "1.17.0" # use Lazy serde = "1.0.152" serde_derive = "1.0.152" serde_json = "1.0.91" # json Deserializer -serde-xml-rs = "0.6.0" # xml Deserializer +serde-xml-rs = "0.8.1" # xml Deserializer with xml attribute bitflags = "2.6.0" # support bitflag enum hmac-sha256 = "1.1.6" # use HMAC using the SHA-256 hash function hex = "0.4.3" # hex encode diff --git a/proxy_agent/config/GuestProxyAgent.linux.json b/proxy_agent/config/GuestProxyAgent.linux.json index 03288fc3..34007661 100644 --- a/proxy_agent/config/GuestProxyAgent.linux.json +++ b/proxy_agent/config/GuestProxyAgent.linux.json @@ -8,5 +8,6 @@ "ebpfProgramName": "ebpf_cgroup.o", "cgroupRoot": "/sys/fs/cgroup", "fileLogLevel": "Trace", - "fileLogLevelForEvents": "Info" + "fileLogLevelForEvents": "Info", + "fileLogLevelForSystemEvents": "Info" } \ No newline at end of file diff --git a/proxy_agent/config/GuestProxyAgent.windows.json b/proxy_agent/config/GuestProxyAgent.windows.json index db05cdda..ccad256c 100644 --- a/proxy_agent/config/GuestProxyAgent.windows.json +++ b/proxy_agent/config/GuestProxyAgent.windows.json @@ -7,5 +7,6 @@ "hostGAPluginSupport": 1, "ebpfProgramName": "redirect.bpf.sys", "fileLogLevel": "Trace", - "fileLogLevelForEvents": "Info" + "fileLogLevelForEvents": "Info", + "fileLogLevelForSystemEvents": "Info" } \ No newline at end of file diff --git a/proxy_agent/src/common/config.rs b/proxy_agent/src/common/config.rs index dc8d6374..cf2df59b 100644 --- a/proxy_agent/src/common/config.rs +++ b/proxy_agent/src/common/config.rs @@ -74,6 +74,10 @@ pub fn get_file_log_level_for_events() -> Option { SYSTEM_CONFIG.get_file_log_level_for_events() } +pub fn get_file_log_level_for_system_events() -> Option { + SYSTEM_CONFIG.get_file_log_level_for_system_events() +} + #[derive(Serialize, Deserialize)] #[allow(non_snake_case)] pub struct Config { @@ -95,6 +99,8 @@ pub struct Config { cgroupRoot: Option, #[serde(skip_serializing_if = "Option::is_none")] fileLogLevelForEvents: Option, + #[serde(skip_serializing_if = "Option::is_none")] + fileLogLevelForSystemEvents: Option, } impl Default for Config { @@ -193,6 +199,14 @@ impl Config { } None } + + pub fn get_file_log_level_for_system_events(&self) -> Option { + if let Some(file_log_level) = &self.fileLogLevelForSystemEvents { + let log_level = LoggerLevel::from_str(file_log_level).unwrap_or(LoggerLevel::Info); + return Some(log_level); + } + None + } } #[cfg(test)] @@ -280,6 +294,12 @@ mod tests { "get_file_log_level_for_events mismatch" ); + assert_eq!( + proxy_agent_shared::logger::LoggerLevel::Info, + config.get_file_log_level_for_system_events().unwrap(), + "get_file_log_level_for_system_events mismatch" + ); + // clean up _ = fs::remove_dir_all(&temp_test_path); } @@ -296,7 +316,8 @@ mod tests { "hostGAPluginSupport": 1, "imdsSupport": 1, "ebpfProgramName": "ebpfProgramName", - "fileLogLevelForEvents": "Info" + "fileLogLevelForEvents": "Info", + "fileLogLevelForSystemEvents": "Info" }"# } else { r#"{ @@ -309,7 +330,8 @@ mod tests { "hostGAPluginSupport": 1, "imdsSupport": 1, "ebpfProgramName": "ebpfProgramName", - "fileLogLevelForEvents": "Info" + "fileLogLevelForEvents": "Info", + "fileLogLevelForSystemEvents": "Info" }"# }; diff --git a/proxy_agent/src/common/logger.rs b/proxy_agent/src/common/logger.rs index d4019168..87432231 100644 --- a/proxy_agent/src/common/logger.rs +++ b/proxy_agent/src/common/logger.rs @@ -1,9 +1,7 @@ // Copyright (c) Microsoft Corporation // SPDX-License-Identifier: MIT -use crate::common::cli; use proxy_agent_shared::{ logger::{logger_manager, LoggerLevel}, - misc_helpers, telemetry::event_logger, }; @@ -28,10 +26,6 @@ pub fn write_error(message: String) { } fn log(log_level: LoggerLevel, message: String) { - if log_level != LoggerLevel::Trace { - write_console_log(message.to_string()); - }; - if let Some(log_for_event) = config::get_file_log_level_for_events() { if log_for_event >= log_level { // write to event @@ -49,18 +43,6 @@ fn log(log_level: LoggerLevel, message: String) { logger_manager::log(AGENT_LOGGER_KEY.to_string(), log_level, message); } -pub fn write_console_log(message: String) { - if cli::CLI.is_console_mode() { - println!( - "{} {}", - misc_helpers::get_date_time_string_with_milliseconds(), - message - ); - } else { - println!("{}", message); - } -} - #[cfg(not(windows))] pub fn write_serial_console_log(message: String) { use proxy_agent_shared::misc_helpers; diff --git a/proxy_agent/src/host_clients/goal_state.rs b/proxy_agent/src/host_clients/goal_state.rs index d1e6a179..69c3b7e2 100644 --- a/proxy_agent/src/host_clients/goal_state.rs +++ b/proxy_agent/src/host_clients/goal_state.rs @@ -89,15 +89,20 @@ pub struct SharedConfig { #[derive(Deserialize, Serialize, PartialEq)] #[allow(non_snake_case)] struct DeploymentField { + #[serde(rename = "@name")] name: String, + #[serde(rename = "@guid")] guid: String, + #[serde(rename = "@incarnation")] incarnation: String, } #[derive(Deserialize, Serialize, PartialEq)] #[allow(non_snake_case)] struct RoleField { + #[serde(rename = "@guid")] guid: String, + #[serde(rename = "@name")] name: String, } @@ -110,7 +115,9 @@ struct InstancesField { #[derive(Deserialize, Serialize, PartialEq)] #[allow(non_snake_case)] struct SharedConfigInstance { + #[serde(rename = "@id")] id: String, + #[serde(rename = "@address")] address: String, } diff --git a/proxy_agent/src/proxy/proxy_connection.rs b/proxy_agent/src/proxy/proxy_connection.rs index 807d1da7..e037bb8b 100644 --- a/proxy_agent/src/proxy/proxy_connection.rs +++ b/proxy_agent/src/proxy/proxy_connection.rs @@ -4,8 +4,8 @@ //! This module contains the connection context struct for the proxy listener, and write proxy processing logs to local file. use crate::common::error::{Error, HyperErrorType}; -use crate::common::hyper_client; use crate::common::result::Result; +use crate::common::{config, hyper_client}; use crate::proxy::Claims; use crate::redirector::{self, AuditEntry}; use crate::shared_state::proxy_server_wrapper::ProxyServerSharedState; @@ -309,7 +309,10 @@ impl ConnectionLogger { } } - if logger_level > logger_manager::get_logger_level() { + if logger_level > logger_manager::get_max_logger_level() + || config::get_logs_dir() == std::path::PathBuf::from("") + { + // If the logger level is higher than the max logger level or logs directory is not set, skip logging return; } diff --git a/proxy_agent/src/proxy/proxy_server.rs b/proxy_agent/src/proxy/proxy_server.rs index 0f765aaf..968773b6 100644 --- a/proxy_agent/src/proxy/proxy_server.rs +++ b/proxy_agent/src/proxy/proxy_server.rs @@ -794,7 +794,6 @@ impl ProxyServer { errorDetails: error_details, }; if let Ok(json) = serde_json::to_string(&summary) { - logger::write_console_log(json.to_string()); event_logger::write_event( LoggerLevel::Info, json, diff --git a/proxy_agent/src/service.rs b/proxy_agent/src/service.rs index 65fec2e1..7d07d965 100644 --- a/proxy_agent/src/service.rs +++ b/proxy_agent/src/service.rs @@ -27,11 +27,13 @@ use std::time::Duration; /// service::start_service(shared_state).await; /// ``` pub async fn start_service(shared_state: SharedState) { + if let Some(max_log_level) = config::get_file_log_level_for_system_events() { + logger_manager::set_system_logger(max_log_level, constants::PROXY_AGENT_SERVICE_NAME); + } + let log_folder = config::get_logs_dir(); if log_folder == PathBuf::from("") { - logger::write_console_log( - "The log folder is not set, skip write to GPA managed file log.".to_string(), - ); + println!("The log folder is not set, skip write to GPA managed file log."); } else { setup_loggers(log_folder, config::get_file_log_level()); } @@ -78,8 +80,6 @@ pub async fn start_service(shared_state: SharedState) { } fn setup_loggers(log_folder: PathBuf, max_logger_level: LoggerLevel) { - logger_manager::set_logger_level(max_logger_level); - let agent_logger = RollingLogger::create_new( log_folder.clone(), "ProxyAgent.log".to_string(), @@ -98,7 +98,11 @@ fn setup_loggers(log_folder: PathBuf, max_logger_level: LoggerLevel) { ConnectionLogger::CONNECTION_LOGGER_KEY.to_string(), connection_logger, ); - logger_manager::set_loggers(loggers, logger::AGENT_LOGGER_KEY.to_string()); + logger_manager::set_loggers( + loggers, + logger::AGENT_LOGGER_KEY.to_string(), + max_logger_level, + ); } /// Start the service and wait until the service is stopped. diff --git a/proxy_agent_extension/src/logger.rs b/proxy_agent_extension/src/logger.rs index bc4d3a1e..70c71c70 100644 --- a/proxy_agent_extension/src/logger.rs +++ b/proxy_agent_extension/src/logger.rs @@ -19,7 +19,7 @@ pub fn init_logger(log_folder: String, log_name: &str) { ); let mut loggers = std::collections::HashMap::new(); loggers.insert(log_name.to_string(), logger); - logger_manager::set_loggers(loggers, log_name.to_string()); + logger_manager::set_loggers(loggers, log_name.to_string(), LoggerLevel::Trace); if !LOGGER_KEY.initialized() { if let Err(e) = LOGGER_KEY.set(log_name.to_string()) { diff --git a/proxy_agent_setup/src/logger.rs b/proxy_agent_setup/src/logger.rs index 91c72dc7..11b7404c 100644 --- a/proxy_agent_setup/src/logger.rs +++ b/proxy_agent_setup/src/logger.rs @@ -15,7 +15,7 @@ fn force_init_logger(log_folder: PathBuf, log_name: &str) { let logger = RollingLogger::create_new(log_folder, log_name.to_string(), 20 * 1024 * 1024, 30); let mut loggers = std::collections::HashMap::new(); loggers.insert(log_name.to_string(), logger); - logger_manager::set_loggers(loggers, log_name.to_string()); + logger_manager::set_loggers(loggers, log_name.to_string(), LoggerLevel::Trace); } pub fn write(message: String) { diff --git a/proxy_agent_shared/Cargo.toml b/proxy_agent_shared/Cargo.toml index ef217730..4de75911 100644 --- a/proxy_agent_shared/Cargo.toml +++ b/proxy_agent_shared/Cargo.toml @@ -23,6 +23,8 @@ backtrace = "0.3" # used for get the caller module and function name [target.'cfg(windows)'.dependencies] windows-service = "0.7.0" # windows NT service winreg = "0.11.0" # windows reg read/write +serde-xml-rs = "0.8.1" # xml Deserializer with xml attribute +chrono = "0.4.41" # parse date time string [target.'cfg(windows)'.dependencies.windows-sys] version = "0.52.0" @@ -31,6 +33,7 @@ features = [ "Win32_Networking_WinSock", "Win32_System_IO", "Win32_Security", + "Win32_System_EventLog", "Win32_System_WindowsProgramming", "Win32_Security_Authentication_Identity", "Win32_System_Diagnostics_Debug", diff --git a/proxy_agent_shared/src/etw.rs b/proxy_agent_shared/src/etw.rs new file mode 100644 index 00000000..7ad87c14 --- /dev/null +++ b/proxy_agent_shared/src/etw.rs @@ -0,0 +1,5 @@ +// Copyright (c) Microsoft Corporation +// SPDX-License-Identifier: MIT +//! This module provides functionality for ETW (Event Tracing for Windows) logging. + +pub mod application; diff --git a/proxy_agent_shared/src/etw/application.rs b/proxy_agent_shared/src/etw/application.rs new file mode 100644 index 00000000..22221e7d --- /dev/null +++ b/proxy_agent_shared/src/etw/application.rs @@ -0,0 +1,463 @@ +// Copyright (c) Microsoft Corporation +// SPDX-License-Identifier: MIT +//! This module provides functionality for Windows Application event +//! // logging using the Windows Event Log API. +//! // It allows registering an event source, writing logs to the Application Event Log. + +use crate::error::Error; +use crate::logger::LoggerLevel; +use crate::result::Result; +use std::ffi::OsStr; +use std::iter::once; +use std::os::windows::ffi::OsStrExt; +use windows_sys::core::PWSTR; +use windows_sys::Win32::Foundation::HANDLE; +use windows_sys::Win32::System::EventLog::{ + DeregisterEventSource, RegisterEventSourceW, ReportEventW, +}; // advapi32.dll +use windows_sys::Win32::System::EventLog::{ + EVENTLOG_ERROR_TYPE, EVENTLOG_INFORMATION_TYPE, EVENTLOG_WARNING_TYPE, REPORT_EVENT_TYPE, +}; + +/// Converts a string to a wide character vector (u16). +/// This is used to convert Rust strings to the format required by Windows API functions. +fn to_wide(s: &str) -> Vec { + OsStr::new(s).encode_wide().chain(once(0)).collect() +} + +/// Converts a `LoggerLevel` to a `REPORT_EVENT_TYPE`. +/// This function maps the logging levels to the corresponding Windows Event Log types. +fn to_event_level(level: LoggerLevel) -> REPORT_EVENT_TYPE { + match level { + LoggerLevel::Trace => EVENTLOG_INFORMATION_TYPE, + LoggerLevel::Debug => EVENTLOG_INFORMATION_TYPE, + LoggerLevel::Info => EVENTLOG_INFORMATION_TYPE, + LoggerLevel::Warn => EVENTLOG_WARNING_TYPE, + LoggerLevel::Error => EVENTLOG_ERROR_TYPE, + } +} + +/// A struct for writing application events to the Windows Event Log. +/// It registers an event source and provides a method to write logs. +/// It also ensures that the event source is deregistered when the struct is dropped. +pub struct ApplicationEventWritter { + event_source: HANDLE, +} + +impl ApplicationEventWritter { + pub fn new(source_name: &str) -> Result { + let source_name_wide = to_wide(source_name); + let event_source = + unsafe { RegisterEventSourceW(std::ptr::null(), source_name_wide.as_ptr()) }; + if event_source == 0 { + return Err(Error::WindowsApi( + "RegisterEventSourceW".to_string(), + std::io::Error::last_os_error(), + )); + } + + // register event source in the Windows Registry + // `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Application\{source_name}` + let key_name = format!( + r"SYSTEM\CurrentControlSet\Services\EventLog\Application\{}", + source_name + ); + let value = crate::misc_helpers::resolve_env_variables( + r"%SystemRoot%\Microsoft.NET\Framework64\v4.0.30319\EventLogMessages.dll", + )?; + crate::windows::set_reg_string(&key_name, "EventMessageFile", value)?; + + Ok(ApplicationEventWritter { event_source }) + } + + pub fn write(&self, log_level: LoggerLevel, message: String) { + let wide_message = to_wide(&message); + let wide_message_ptrs: [PWSTR; 1] = [wide_message.as_ptr() as PWSTR]; + + unsafe { + ReportEventW( + self.event_source, + to_event_level(log_level), + 0, + 0, + std::ptr::null_mut(), + 1, + 0, + wide_message_ptrs.as_ptr() as *const *const u16, + std::ptr::null(), + ); + } + } +} + +impl Drop for ApplicationEventWritter { + fn drop(&mut self) { + unsafe { + DeregisterEventSource(self.event_source); + } + } +} + +#[cfg(test)] +mod tests { + + /// etw_reader test module is used to read ETW events from the Windows Event Log. + mod etw_reader { + + use crate::error::Error; + use crate::result::Result; + use chrono::DateTime; + use serde_derive::{Deserialize, Serialize}; + use std::ffi::OsString; + use std::os::windows::ffi::OsStringExt; + use windows_sys::Win32::Foundation::GetLastError; + use windows_sys::Win32::Foundation::ERROR_NO_MORE_ITEMS; + use windows_sys::Win32::System::EventLog::{ + EvtClose, EvtNext, EvtQuery, EvtRender, EVT_HANDLE, + }; // wevtapi.dll + use windows_sys::Win32::System::EventLog::{EvtQueryReverseDirection, EvtRenderEventXml}; + + /// Represents an ETW event structure + /// as defined in the XML schema. + /// The structure is used to deserialize ETW events from XML format. + /// The `Event` struct contains a `System` and `EventData` field, + /// which hold the metadata and data of the event respectively. + #[derive(Debug, Deserialize, Serialize)] + #[serde(rename = "Event")] + pub struct Event { + #[serde(rename = "System")] + pub system: System, + #[serde(rename = "EventData", skip_serializing_if = "Option::is_none")] + pub event_data: Option, + } + + #[derive(Debug, Deserialize, Serialize)] + pub struct System { + #[serde(rename = "Provider")] + pub provider: Provider, + #[serde(rename = "EventID")] + pub event_id: u32, + #[serde(rename = "Version")] + pub version: u8, + #[serde(rename = "Level")] + pub level: u8, + #[serde(rename = "Task")] + pub task: u8, + #[serde(rename = "Opcode")] + pub opcode: u8, + #[serde(rename = "Keywords")] + pub keywords: String, + #[serde(rename = "TimeCreated")] + pub time_created: TimeCreated, + #[serde(rename = "EventRecordID")] + pub event_record_id: u64, + #[serde(rename = "Execution")] + pub execution: Execution, + #[serde(rename = "Channel")] + pub channel: String, + #[serde(rename = "Computer")] + pub computer: String, + } + + #[derive(Debug, Deserialize, Serialize)] + pub struct Provider { + #[serde(rename = "@Name", skip_serializing_if = "Option::is_none")] + pub name: Option, + #[serde(rename = "@EventSourceName", skip_serializing_if = "Option::is_none")] + pub event_source_name: Option, + } + + #[derive(Debug, Deserialize, Serialize)] + pub struct TimeCreated { + #[serde(rename = "@SystemTime", skip_serializing_if = "Option::is_none")] + pub system_time: Option, + } + + #[derive(Debug, Deserialize, Serialize)] + pub struct Execution { + #[serde(rename = "@ProcessID")] + pub process_id: u32, + #[serde(rename = "@ThreadID")] + pub thread_id: u32, + } + + #[derive(Debug, Deserialize, Serialize)] + pub struct EventData { + #[serde(rename = "Data")] + pub data: Option>, + } + + pub struct WindowsEventReader { + query_handle: EVT_HANDLE, + current_event: EVT_HANDLE, + source_name: String, + start_time: Option>, + end_time: Option>, + } + + impl WindowsEventReader { + pub fn new( + event_name: &str, + source_name: &str, + start_time: Option>, + end_time: Option>, + ) -> Result { + let event_name_wide = crate::etw::application::to_wide(event_name); + let h_query = unsafe { + EvtQuery( + 0, + event_name_wide.as_ptr(), + std::ptr::null(), + EvtQueryReverseDirection, + ) + }; + if h_query == 0 { + return Err(Error::WindowsApi( + "EvtQuery".to_string(), + std::io::Error::last_os_error(), + )); + } + + Ok(WindowsEventReader { + query_handle: h_query, + current_event: 0, + source_name: source_name.to_string(), + start_time, + end_time, + }) + } + // Additional methods for reading events can be implemented here + } + + impl Drop for WindowsEventReader { + fn drop(&mut self) { + // Close the query handle and current event handle if they are open + unsafe { + EvtClose(self.query_handle); + EvtClose(self.current_event); + } + } + } + + impl Iterator for WindowsEventReader { + type Item = Result; + + fn next(&mut self) -> Option { + let mut returned: u32 = 0; + + if unsafe { + EvtNext( + self.query_handle, + 1, + &mut self.current_event, + 0, + 0, + &mut returned, + ) + } == 0 + { + let error_code = unsafe { GetLastError() }; + if error_code == ERROR_NO_MORE_ITEMS { + // No more items to read + return None; + } else { + return Some(Err(Error::WindowsApi( + "EvtNext".to_string(), + std::io::Error::from_raw_os_error(error_code as i32), + ))); + } + } + + if returned == 0 { + return None; // No events read + } + + // First call to get buffer size + let mut buffer_used = 0; + let mut property_count = 0; + let status = unsafe { + EvtRender( + 0, + self.current_event, + EvtRenderEventXml, + 0, + std::ptr::null_mut(), + &mut buffer_used, + &mut property_count, + ) + }; + if status != 0 || buffer_used == 0 { + return Some(Err(Error::WindowsApi( + "EvtRender_Buffer_Size".to_string(), + std::io::Error::last_os_error(), + ))); + } + // Allocate buffer for rendering + let mut buffer: Vec = vec![0; buffer_used as usize / 2]; + if unsafe { + EvtRender( + 0, + self.current_event, + EvtRenderEventXml, + buffer_used, + buffer.as_mut_ptr() as *mut _, + &mut buffer_used, + &mut property_count, + ) + } == 0 + { + return Some(Err(Error::WindowsApi( + "EvtRender".to_string(), + std::io::Error::last_os_error(), + ))); + } + + // Convert the buffer to a xml string + let xml = OsString::from_wide(&buffer) + .to_string_lossy() + .trim_end_matches('\0') + .to_string(); + + // Parse the XML string into an Event struct + match serde_xml_rs::from_str::(&xml) { + Ok(event) => { + let mut skip_event = false; + // Check if the event is from the specified source + if event.system.provider.name == Some(self.source_name.clone()) { + // Check if the event is within the specified time range + let time_created = event.system.time_created.system_time.clone(); + if let Some(start_time) = self.start_time { + match time_created.clone() { + Some(time) => { + if let Ok(event_time) = + time.parse::>() + { + if event_time < start_time { + skip_event = true; // Skip this event + } + } + } + None => skip_event = true, // Skip this event if time is not available + } + } + if let Some(end_time) = self.end_time { + match time_created { + Some(time) => { + if let Ok(event_time) = + time.parse::>() + { + if event_time > end_time { + skip_event = true; // Skip this event + } + } + } + None => skip_event = true, // Skip this event if time is not available + } + } + } else { + skip_event = true; // Skip this event + } + + if skip_event { + self.next() // Skip to the next event + } else { + Some(Ok(event)) // Return the event + } + } + Err(e) => Some(Err(Error::Io(std::io::Error::new( + std::io::ErrorKind::InvalidData, + format!("Failed to parse event XML: {}", e), + )))), + } + } + } + } + + use chrono::DateTime; + + #[test] + fn write_event_log_test() { + use super::ApplicationEventWritter; + use crate::logger::LoggerLevel; + + let start_time = chrono::Utc::now(); + let end_time = start_time + chrono::Duration::seconds(60); + + let source_name = "GuestProxyAgent_TestApplication"; + let message = "This is a test log message"; + let event_writer = ApplicationEventWritter::new(source_name).unwrap(); + event_writer.write(LoggerLevel::Info, message.to_string()); + + println!("Verifying event log for source: {}", source_name); + let data = query_application_event(source_name, None, None); + assert_eq!( + data, message, + "Event log data does not match the expected message" + ); + + println!( + "Verifying event log for source: {} after {}", + source_name, start_time + ); + let data = query_application_event(source_name, Some(start_time), None); + assert_eq!( + data, message, + "Event log data does not match the expected message" + ); + + println!( + "Verifying event log for source: {} before {}", + source_name, end_time + ); + let data = query_application_event(source_name, None, Some(end_time)); + assert_eq!( + data, message, + "Event log data does not match the expected message" + ); + + println!( + "Verifying event log for source: {} between {} and {}", + source_name, start_time, end_time + ); + let data = query_application_event(source_name, Some(start_time), Some(end_time)); + assert_eq!( + data, message, + "Event log data does not match the expected message" + ); + + // Clean up: Remove the event source from the Windows Registry + let key_name = format!( + r"SYSTEM\CurrentControlSet\Services\EventLog\Application\{}", + source_name + ); + if let Err(e) = crate::windows::remove_reg_key(&key_name) { + eprintln!("Failed to remove event source from registry: {}", e); + } + } + + fn query_application_event( + source_name: &str, + start_time: Option>, + end_time: Option>, + ) -> String { + let mut reader = + etw_reader::WindowsEventReader::new("Application", source_name, start_time, end_time) + .unwrap(); + let data = reader + .next() + .map(|event| { + event + .unwrap() + .event_data + .unwrap() + .data + .unwrap() + .iter() + .map(|d| d.to_string()) + .collect::>() + }) + .unwrap_or_else(|| vec!["No data found".to_string()]); + + return data.join("\n"); + } +} diff --git a/proxy_agent_shared/src/lib.rs b/proxy_agent_shared/src/lib.rs index 4ba2f5bb..27a01e6a 100644 --- a/proxy_agent_shared/src/lib.rs +++ b/proxy_agent_shared/src/lib.rs @@ -2,6 +2,8 @@ // SPDX-License-Identifier: MIT pub mod error; +#[cfg(windows)] +pub mod etw; pub mod logger; pub mod misc_helpers; pub mod proxy_agent_aggregate_status; diff --git a/proxy_agent_shared/src/logger/logger_manager.rs b/proxy_agent_shared/src/logger/logger_manager.rs index 97784746..61dff8bb 100644 --- a/proxy_agent_shared/src/logger/logger_manager.rs +++ b/proxy_agent_shared/src/logger/logger_manager.rs @@ -1,22 +1,50 @@ // Copyright (c) Microsoft Corporation // SPDX-License-Identifier: MIT +//! This module manages the loggers for the application. +//! It provides functionality to set up loggers, write logs, and manage log levels. +//! It uses a static `OnceCell` to ensure that the loggers are initialized only once. use super::rolling_logger::RollingLogger; -use log::Level; +#[cfg(windows)] +use crate::etw::application::ApplicationEventWritter; +use crate::logger::LoggerLevel; use std::collections::HashMap; +// The loggers are stored in a static `OnceCell` to ensure they are initialized only once. static LOGGERS: tokio::sync::OnceCell> = tokio::sync::OnceCell::const_new(); +// The `DEFAULT_LOGGER_KEY` is used to specify which rolling logger should be used by default when no key is provided. static DEFAULT_LOGGER_KEY: tokio::sync::OnceCell = tokio::sync::OnceCell::const_new(); -static MAX_LOG_LEVEL: tokio::sync::OnceCell = tokio::sync::OnceCell::const_new(); +// The `MAX_LOG_LEVEL` is used to set the maximum log level for the loggers. +static MAX_LOG_LEVEL: tokio::sync::OnceCell = tokio::sync::OnceCell::const_new(); +// The `MAX_SYSTEM_LOG_LEVEL` is used to set the maximum log level for system logs. +static MAX_SYSTEM_LOG_LEVEL: tokio::sync::OnceCell = + tokio::sync::OnceCell::const_new(); +#[cfg(windows)] +static WINDOWS_ETW_APPLICATION_LOGGER: tokio::sync::OnceCell = + tokio::sync::OnceCell::const_new(); /// Setup the loggers and set the default logger key /// # Arguments /// * `loggers` - A hashmap of loggers /// * `default_logger_key` - The default logger key +/// * `max_log_level` - The maximum log level for file logging /// # Panics /// * If the default logger key is not found in the loggers hashmap -pub fn set_loggers(loggers: HashMap, default_logger_key: String) { +pub fn set_loggers( + loggers: HashMap, + default_logger_key: String, + max_log_level: LoggerLevel, +) { + if !MAX_LOG_LEVEL.initialized() { + if let Err(e) = MAX_LOG_LEVEL.set(max_log_level) { + write_system_log( + LoggerLevel::Error, + format!("Failed to set logger level: {}", e), + ); + } + } + if LOGGERS.initialized() { return; } @@ -26,21 +54,54 @@ pub fn set_loggers(loggers: HashMap, default_logger_key: } // set the loggers once - LOGGERS.set(loggers).unwrap(); - DEFAULT_LOGGER_KEY.set(default_logger_key).unwrap(); + if let Err(e) = LOGGERS.set(loggers) { + write_system_log(LoggerLevel::Error, format!("Failed to set loggers: {}", e)); + }; + if let Err(e) = DEFAULT_LOGGER_KEY.set(default_logger_key) { + write_system_log( + LoggerLevel::Error, + format!("Failed to set default logger key: {}", e), + ); + } } -pub fn set_logger_level(log_level: Level) { - if MAX_LOG_LEVEL.initialized() { - return; +pub fn set_system_logger(max_log_level: LoggerLevel, _service_name: &str) { + #[cfg(windows)] + { + if !WINDOWS_ETW_APPLICATION_LOGGER.initialized() { + match ApplicationEventWritter::new(_service_name) { + Ok(logger) => { + if let Err(e) = WINDOWS_ETW_APPLICATION_LOGGER.set(logger) { + write_system_log( + LoggerLevel::Error, + format!("Failed to set Windows Application ETW logger: {}", e), + ); + } + } + Err(e) => { + write_system_log( + LoggerLevel::Error, + format!("Failed to create Windows Application ETW logger: {}", e), + ); + } + } + } + } + + if !MAX_SYSTEM_LOG_LEVEL.initialized() { + if let Err(e) = MAX_SYSTEM_LOG_LEVEL.set(max_log_level) { + write_system_log( + LoggerLevel::Error, + format!("Failed to set system logger level: {}", e), + ); + } } - MAX_LOG_LEVEL.set(log_level).unwrap(); } -pub fn get_logger_level() -> Level { +pub fn get_max_logger_level() -> LoggerLevel { let level = match MAX_LOG_LEVEL.get() { Some(l) => *l, // No need to use `clone` on type `Level` which implements the `Copy` trait - None => Level::Trace, + None => LoggerLevel::Trace, }; level } @@ -56,44 +117,40 @@ fn get_logger(logger_key: Option) -> Option<&'static RollingLogger> { None } -pub fn log(logger_key: String, log_level: Level, message: String) { - if log_level > get_logger_level() { +fn internal_log(logger_key: Option, log_level: LoggerLevel, message: String) { + // By default, we write the log to the system log + // This is useful for debugging and monitoring purposes. + write_system_log(log_level, message.clone()); + + if log_level > get_max_logger_level() { return; } - if let Some(logger) = get_logger(Some(logger_key)) { + if let Some(logger) = get_logger(logger_key) { if let Err(e) = logger.write(log_level, message) { eprintln!("Error writing to log: {}", e); } } } -pub fn write_log(log_level: Level, message: String) { - let level = match MAX_LOG_LEVEL.get() { - Some(l) => *l, // No need to use `clone` on type `Level` which implements the `Copy` trait - None => Level::Trace, - }; - if log_level > level { - return; - } +pub fn log(logger_key: String, log_level: LoggerLevel, message: String) { + internal_log(Some(logger_key), log_level, message); +} - if let Some(logger) = get_logger(None) { - if let Err(e) = logger.write(log_level, message) { - eprintln!("Error writing to log: {}", e); - } - } +pub fn write_log(log_level: LoggerLevel, message: String) { + internal_log(None, log_level, message); } pub fn write_info(message: String) { - write_log(Level::Info, message); + write_log(LoggerLevel::Info, message); } pub fn write_warn(message: String) { - write_log(Level::Warn, message); + write_log(LoggerLevel::Warn, message); } pub fn write_err(message: String) { - write_log(Level::Error, message); + write_log(LoggerLevel::Error, message); } pub fn write_many(logger_key: Option, messages: Vec) { @@ -104,11 +161,41 @@ pub fn write_many(logger_key: Option, messages: Vec) { } } +fn write_system_log(log_level: LoggerLevel, message: String) { + if log_level > get_max_system_logger_level() { + return; + } + + // Linux automatically captures console logs to syslog. + if log_level == LoggerLevel::Error { + eprintln!("{}", message); + } else { + println!("{}", message); + } + + #[cfg(windows)] + { + if let Some(logger) = WINDOWS_ETW_APPLICATION_LOGGER.get() { + logger.write(log_level, message); + } else { + eprintln!("Windows ETW Application logger is not initialized."); + } + } +} + +fn get_max_system_logger_level() -> LoggerLevel { + let level = match MAX_SYSTEM_LOG_LEVEL.get() { + Some(l) => *l, // No need to use `clone` on type `Level` which implements the `Copy` trait + None => LoggerLevel::Error, + }; + level +} + #[cfg(test)] mod tests { + use crate::logger::LoggerLevel; use crate::misc_helpers; use ctor::{ctor, dtor}; - use log::Level; use std::env; use std::fs; @@ -131,7 +218,11 @@ mod tests { ); let mut loggers = std::collections::HashMap::new(); loggers.insert(TEST_LOGGER_KEY.to_string(), logger); - crate::logger::logger_manager::set_loggers(loggers, TEST_LOGGER_KEY.to_string()); + crate::logger::logger_manager::set_loggers( + loggers, + TEST_LOGGER_KEY.to_string(), + LoggerLevel::Trace, + ); } #[dtor] @@ -144,16 +235,16 @@ mod tests { fn logger_manager_test() { for _ in [0; 20] { super::write_log( - Level::Trace, + LoggerLevel::Trace, String::from("This is a test message This is a test message"), ); super::write_log( - Level::Debug, + LoggerLevel::Debug, String::from("This is a test message This is a test message"), ); - super::write_log(Level::Info, "message from write_info".to_string()); - super::write_log(Level::Warn, "message from write_warn".to_string()); - super::write_log(Level::Error, "message from write_err".to_string()); + super::write_log(LoggerLevel::Info, "message from write_info".to_string()); + super::write_log(LoggerLevel::Warn, "message from write_warn".to_string()); + super::write_log(LoggerLevel::Error, "message from write_err".to_string()); } let file_count = misc_helpers::get_files(&get_temp_test_dir()).unwrap(); diff --git a/proxy_agent_shared/src/windows.rs b/proxy_agent_shared/src/windows.rs index c9e1fb14..aa35ede6 100644 --- a/proxy_agent_shared/src/windows.rs +++ b/proxy_agent_shared/src/windows.rs @@ -49,6 +49,19 @@ fn read_reg_string(key_name: &str, value_name: &str, default_value: String) -> S default_value } +pub fn set_reg_string(key_name: &str, value_name: &str, value: String) -> Result<()> { + let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); + let (key, _) = hklm.create_subkey(key_name)?; + key.set_value(value_name, &value)?; + Ok(()) +} + +pub fn remove_reg_key(key_name: &str) -> Result<()> { + let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); + hklm.delete_subkey_all(key_name)?; + Ok(()) +} + const OS_VERSION_REGISTRY_KEY: &str = "Software\\Microsoft\\Windows NT\\CurrentVersion"; const PRODUCT_NAME_VAL_STRING: &str = "ProductName"; const CURRENT_MAJOR_VERSION_NUMBER_STRING: &str = "CurrentMajorVersionNumber"; @@ -369,4 +382,21 @@ mod tests { println!("kernel32.dll File product version: {}", version); assert_eq!(version.major, 10, "major version mismatch"); } + + #[test] + fn reg_set_test() { + let key_name = "Software\\TestKey"; + let value_name = "TestValue"; + let value = "TestValueData".to_string(); + + // Set the registry value + super::set_reg_string(key_name, value_name, value.clone()).unwrap(); + + // Read the registry value + let read_value = super::read_reg_string(key_name, value_name, "".to_string()); + assert_eq!(value, read_value, "Registry value mismatch"); + + // Clean up + super::remove_reg_key(key_name).unwrap(); + } } From a397b9676ea183edb99cfab7ece8288712c613b1 Mon Sep 17 00:00:00 2001 From: shahneerali <131208062+shahneerali@users.noreply.github.com> Date: Mon, 23 Jun 2025 15:43:48 -0700 Subject: [PATCH 05/12] Check if Events Folder Path Exists Before Writing Logs (#247) * add events folder path check * linter * update UT coverage --- proxy_agent_extension/src/common.rs | 80 ++++++++++++++++++++++------ proxy_agent_extension/src/structs.rs | 2 +- 2 files changed, 65 insertions(+), 17 deletions(-) diff --git a/proxy_agent_extension/src/common.rs b/proxy_agent_extension/src/common.rs index 1c9ef83f..cf50129c 100644 --- a/proxy_agent_extension/src/common.rs +++ b/proxy_agent_extension/src/common.rs @@ -225,11 +225,29 @@ pub async fn start_event_logger() { logger::write("starting event logger".to_string()); tokio::spawn({ async move { - let interval: std::time::Duration = std::time::Duration::from_secs(60); + let interval = std::time::Duration::from_secs(60); let max_event_file_count: usize = 50; let exe_path = misc_helpers::get_current_exe_dir(); - let event_folder = - PathBuf::from(get_handler_environment(&exe_path).eventsFolder.to_string()); + // Get the events folder from the handler environment + let events_folder_str = match get_handler_environment(&exe_path).eventsFolder { + Some(folder) => folder, + None => { + logger::write( + "No events folder specified, skipping event logger start.".to_string(), + ); + return; + } + }; + let event_folder = PathBuf::from(events_folder_str.clone()); + // Check if the events folder exists + if !event_folder.exists() { + logger::write(format!( + "Events folder does not exist: {:?}. Skipping event logger start.", + event_folder + )); + return; + } + telemetry::event_logger::start(event_folder, interval, max_event_file_count, |_| { async { // do nothing @@ -337,10 +355,9 @@ mod tests { _ = fs::remove_dir_all(&temp_test_path); _ = misc_helpers::try_create_folder(&temp_test_path); - //Add HandlerEnvironment.json in the temp directory let handler_env_file = temp_test_path.to_path_buf().join("HandlerEnvironment.json"); - //Create raw handler environment json string + // Case 1: eventsFolder exists let json_handler_linux: &str = r#"[{ "version": 1.0, "handlerEnvironment": { @@ -352,22 +369,53 @@ mod tests { } }]"#; - //Deserialize handler environment json string let handler_env_obj: Vec = serde_json::from_str(json_handler_linux).unwrap(); + _ = misc_helpers::json_write_to_file(&handler_env_obj, &handler_env_file); + + let events_folder = temp_test_path.join("test_kusto"); + _ = misc_helpers::try_create_folder(&events_folder); + assert!(events_folder.exists(), "Events folder should exist"); + + let handler_env = super::get_handler_environment(&temp_test_path); + assert_eq!(handler_env.eventsFolder, Some("test_kusto".to_string())); + + // Case 2: eventsFolder does NOT exist + _ = fs::remove_dir_all(&events_folder); + assert!(!events_folder.exists(), "Events folder should NOT exist"); + let handler_env = super::get_handler_environment(&temp_test_path); + assert_eq!(handler_env.eventsFolder, Some("test_kusto".to_string())); - //Write the deserialized json object to HandlerEnvironment.json file + // Case 3: eventsFolder is not specified (None) + let json_handler_no_events: &str = r#"[{ + "version": 1.0, + "handlerEnvironment": { + "logFolder": "log", + "configFolder": "config", + "statusFolder": "status", + "heartbeatFile": "heartbeat.json" + } + }]"#; + let handler_env_obj: Vec = serde_json::from_str(json_handler_no_events).unwrap(); _ = misc_helpers::json_write_to_file(&handler_env_obj, &handler_env_file); + let handler_env = super::get_handler_environment(&temp_test_path); + assert_eq!(handler_env.eventsFolder, None); + // Case 4: eventsFolder is an empty string + let json_handler_empty_events: &str = r#"[{ + "version": 1.0, + "handlerEnvironment": { + "logFolder": "log", + "configFolder": "config", + "statusFolder": "status", + "heartbeatFile": "heartbeat.json", + "eventsFolder": "" + } + }]"#; + let handler_env_obj: Vec = + serde_json::from_str(json_handler_empty_events).unwrap(); + _ = misc_helpers::json_write_to_file(&handler_env_obj, &handler_env_file); let handler_env = super::get_handler_environment(&temp_test_path); - assert_eq!(handler_env.logFolder, "log".to_string()); - assert_eq!(handler_env.configFolder, "config".to_string()); - assert_eq!(handler_env.statusFolder, "status".to_string()); - assert_eq!(handler_env.heartbeatFile, "heartbeat.json".to_string()); - assert_eq!(handler_env.eventsFolder, "test_kusto".to_string()); - assert_eq!(handler_env.deploymentid, None); - assert_eq!(handler_env.rolename, None); - assert_eq!(handler_env.instance, None); - assert_eq!(handler_env.hostResolverAddress, None); + assert_eq!(handler_env.eventsFolder, Some("".to_string())); _ = fs::remove_dir_all(&temp_test_path); } diff --git a/proxy_agent_extension/src/structs.rs b/proxy_agent_extension/src/structs.rs index 599ce238..bae1f39a 100644 --- a/proxy_agent_extension/src/structs.rs +++ b/proxy_agent_extension/src/structs.rs @@ -13,7 +13,7 @@ pub struct HandlerEnvironment { pub rolename: Option, pub instance: Option, pub hostResolverAddress: Option, - pub eventsFolder: String, + pub eventsFolder: Option, } impl Clone for HandlerEnvironment { fn clone(&self) -> Self { From 901bb68f7112a92e847e6906c8fff32c159d88c9 Mon Sep 17 00:00:00 2001 From: Zhidong Peng Date: Mon, 30 Jun 2025 10:06:16 -0700 Subject: [PATCH 06/12] Fix clippy error uninlined_format_args (#249) * Fix clippy error uninlined_format_args * Continue fix on windwos * revert * add log * Adjust the query start time --- proxy_agent/src/acl/linux_acl.rs | 15 ++-- proxy_agent/src/acl/windows_acl.rs | 22 ++---- proxy_agent/src/common/helpers.rs | 2 +- proxy_agent/src/common/hyper_client.rs | 21 +++--- proxy_agent/src/common/logger.rs | 4 +- .../src/host_clients/wire_server_client.rs | 7 +- proxy_agent/src/key_keeper.rs | 74 ++++++++----------- proxy_agent/src/key_keeper/key.rs | 11 ++- proxy_agent/src/main.rs | 4 +- proxy_agent/src/provision.rs | 5 +- proxy_agent/src/proxy.rs | 6 +- proxy_agent/src/proxy/authorization_rules.rs | 17 ++--- proxy_agent/src/proxy/proxy_authorizer.rs | 7 +- proxy_agent/src/proxy/proxy_connection.rs | 17 ++--- proxy_agent/src/proxy/proxy_server.rs | 69 ++++++++--------- proxy_agent/src/proxy/windows.rs | 16 ++-- proxy_agent/src/proxy_agent_status.rs | 17 ++--- proxy_agent/src/redirector.rs | 11 +-- proxy_agent/src/redirector/linux.rs | 19 ++--- proxy_agent/src/redirector/windows.rs | 12 +-- proxy_agent/src/redirector/windows/bpf_api.rs | 10 +-- .../src/redirector/windows/bpf_prog.rs | 49 ++++++------ proxy_agent/src/service/windows.rs | 3 +- .../src/shared_state/agent_status_wrapper.rs | 47 +++++------- .../src/shared_state/key_keeper_wrapper.rs | 24 ++---- .../src/shared_state/provision_wrapper.rs | 15 ++-- .../src/shared_state/proxy_server_wrapper.rs | 4 +- .../src/shared_state/redirector_wrapper.rs | 6 +- .../src/shared_state/telemetry_wrapper.rs | 6 +- proxy_agent/src/telemetry/event_reader.rs | 15 ++-- proxy_agent_extension/src/common.rs | 24 +++--- proxy_agent_extension/src/handler_main.rs | 46 ++++++------ proxy_agent_extension/src/logger.rs | 2 +- proxy_agent_extension/src/main.rs | 4 +- proxy_agent_extension/src/service_main.rs | 31 ++++---- .../src/service_main/windows_main.rs | 2 +- proxy_agent_setup/src/args.rs | 4 +- proxy_agent_setup/src/linux.rs | 20 ++--- proxy_agent_setup/src/logger.rs | 2 +- proxy_agent_setup/src/main.rs | 53 +++++-------- proxy_agent_setup/src/running.rs | 9 +-- proxy_agent_shared/src/etw/application.rs | 14 ++-- proxy_agent_shared/src/linux.rs | 6 +- .../src/logger/logger_manager.rs | 20 ++--- proxy_agent_shared/src/misc_helpers.rs | 4 +- proxy_agent_shared/src/service.rs | 19 ++--- .../src/service/linux_service.rs | 2 +- .../src/service/windows_service.rs | 26 +++---- .../src/telemetry/event_logger.rs | 11 ++- proxy_agent_shared/src/version.rs | 6 +- proxy_agent_shared/src/windows.rs | 13 ++-- 51 files changed, 357 insertions(+), 496 deletions(-) diff --git a/proxy_agent/src/acl/linux_acl.rs b/proxy_agent/src/acl/linux_acl.rs index d49440f3..d588c3d9 100644 --- a/proxy_agent/src/acl/linux_acl.rs +++ b/proxy_agent/src/acl/linux_acl.rs @@ -10,19 +10,16 @@ use std::path::PathBuf; pub fn acl_directory(dir_to_acl: PathBuf) -> Result<()> { let dir_str = misc_helpers::path_to_string(&dir_to_acl); logger::write(format!( - "acl_directory: start to set root-only permission to folder {}.", - dir_str + "acl_directory: start to set root-only permission to folder {dir_str}." )); match chown(&dir_to_acl, Some(Uid::from_raw(0)), Some(Gid::from_raw(0))) { Ok(_) => logger::write(format!( - "acl_directory: successfully set root-only permission to folder {}.", - dir_str + "acl_directory: successfully set root-only permission to folder {dir_str}." )), Err(e) => { logger::write(format!( - "acl_directory: failed to set root-only permission to folder {}. Error: {:?}", - dir_str, e + "acl_directory: failed to set root-only permission to folder {dir_str}. Error: {e:?}" )); } } @@ -31,13 +28,11 @@ pub fn acl_directory(dir_to_acl: PathBuf) -> Result<()> { let permissions = fs::Permissions::from_mode(0o700); match fs::set_permissions(dir_to_acl, permissions) { Ok(_) => logger::write(format!( - "acl_directory: successfully set root-only permission to folder {}.", - dir_str + "acl_directory: successfully set root-only permission to folder {dir_str}." )), Err(e) => { logger::write(format!( - "acl_directory: failed to set root-only permission to folder {}. Error: {:?}", - dir_str, e + "acl_directory: failed to set root-only permission to folder {dir_str}. Error: {e:?}" )); } } diff --git a/proxy_agent/src/acl/windows_acl.rs b/proxy_agent/src/acl/windows_acl.rs index 532a2893..eb63a896 100644 --- a/proxy_agent/src/acl/windows_acl.rs +++ b/proxy_agent/src/acl/windows_acl.rs @@ -31,16 +31,14 @@ pub fn acl_directory(dir_to_acl: PathBuf) -> Result<()> { .map_err(|e| Error::Acl(AclErrorType::Sid(BUILDIN_ADMIN_SID.to_string()), e))?; logger::write(format!( - "acl_directory: removing all the remaining access rules for folder {}.", - dir_str + "acl_directory: removing all the remaining access rules for folder {dir_str}." )); match acl.all() { Ok(entries) => { logger::write(format!( - "acl_directory: get '{}' access rules for folder {}.", - entries.len(), - dir_str + "acl_directory: get '{len}' access rules for folder {dir_str}.", + len = entries.len() )); for entry in entries { match entry.sid { @@ -55,12 +53,11 @@ pub fn acl_directory(dir_to_acl: PathBuf) -> Result<()> { None, // remove all, including inherited permissions ) { Ok(r) => { - logger::write(format!("acl_directory: removed '{}' entry.", r)); + logger::write(format!("acl_directory: removed '{r}' entry.")); } Err(e) => { logger::write_warning(format!( - "acl_directory: remove_entry failed with error '{}' entry.", - e + "acl_directory: remove_entry failed with error '{e}' entry.", )); } } @@ -77,8 +74,7 @@ pub fn acl_directory(dir_to_acl: PathBuf) -> Result<()> { } logger::write(format!( - "acl_directory: Adding new access rules for the target directory {}.", - dir_str + "acl_directory: Adding new access rules for the target directory {dir_str}." )); let flags = (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE) as u8; let mask = FULL_CONTROL; @@ -90,8 +86,7 @@ pub fn acl_directory(dir_to_acl: PathBuf) -> Result<()> { ) { Ok(r) => { logger::write(format!( - "acl_directory: Adding new access rules for sid {} with result {}.", - LOCAL_SYSTEM_SID, r + "acl_directory: Adding new access rules for sid {LOCAL_SYSTEM_SID} with result {r}.", )); } Err(e) => { @@ -109,8 +104,7 @@ pub fn acl_directory(dir_to_acl: PathBuf) -> Result<()> { ) { Ok(r) => { logger::write(format!( - "acl_directory: Adding new access rules for sid {} with result {}.", - BUILDIN_ADMIN_SID, r + "acl_directory: Adding new access rules for sid {BUILDIN_ADMIN_SID} with result {r}." )); } Err(e) => { diff --git a/proxy_agent/src/common/helpers.rs b/proxy_agent/src/common/helpers.rs index c945e9ea..112c957a 100644 --- a/proxy_agent/src/common/helpers.rs +++ b/proxy_agent/src/common/helpers.rs @@ -18,7 +18,7 @@ static CURRENT_SYS_INFO: Lazy<(u64, usize)> = Lazy::new(|| { let ram_in_mb = match windows::get_memory_in_mb() { Ok(ram) => ram, Err(e) => { - logger::write_error(format!("get_memory_in_mb failed: {}", e)); + logger::write_error(format!("get_memory_in_mb failed: {e}")); 0 } }; diff --git a/proxy_agent/src/common/hyper_client.rs b/proxy_agent/src/common/hyper_client.rs index 9eea2cbc..bc52c375 100644 --- a/proxy_agent/src/common/hyper_client.rs +++ b/proxy_agent/src/common/hyper_client.rs @@ -166,8 +166,7 @@ where Err(e) => Err(Error::Hyper( HyperErrorType::Deserialize( format!( - "Failed to xml deserialize response body with content_type {} from: {} with error {}", - content_type, body_string, e + "Failed to xml deserialize response body with content_type {content_type} from: {body_string} with error {e}" ) ), )), @@ -178,8 +177,7 @@ where Err(e) => Err(Error::Hyper( HyperErrorType::Deserialize( format!( - "Failed to json deserialize response body with {} from: {} with error {}", - content_type, body_string, e + "Failed to json deserialize response body with {content_type} from: {body_string} with error {e}" ) ), )), @@ -246,8 +244,7 @@ pub fn build_request( match request_builder.body(boxed_body) { Ok(r) => Ok(r), Err(e) => Err(Error::Hyper(HyperErrorType::RequestBuilder(format!( - "Failed to build request body: {}", - e + "Failed to build request body: {e}" )))), } } @@ -268,7 +265,7 @@ where let mut sender = build_http_sender(host, port, log_fun).await?; sender.send_request(request).await.map_err(|e| { Error::Hyper(HyperErrorType::Custom( - format!("Failed to send request to {}", full_url), + format!("Failed to send request to {full_url}"), e, )) }) @@ -285,12 +282,12 @@ where B::Error: Into>, F: FnMut(String) + Send + 'static, { - let addr = format!("{}:{}", host, port); + let addr = format!("{host}:{port}"); let stream = match TcpStream::connect(addr.to_string()).await { Ok(tcp_stream) => tcp_stream, Err(e) => { return Err(Error::Io( - format!("Failed to open TCP connection to {}", addr), + format!("Failed to open TCP connection to {addr}"), e, )) } @@ -301,13 +298,13 @@ where .await .map_err(|e| { Error::Hyper(HyperErrorType::Custom( - format!("Failed to establish connection to {}", addr), + format!("Failed to establish connection to {addr}"), e, )) })?; tokio::task::spawn(async move { if let Err(err) = conn.await { - log_fun(format!("Connection failed: {:?}", err)); + log_fun(format!("Connection failed: {err:?}")); } }); @@ -428,7 +425,7 @@ fn get_path_and_canonicalized_parameters(url: &Uri) -> (String, String) { pairs.insert( // add the query parameter value for sorting, // just in case of duplicate keys by value lexicographically in ascending order. - format!("{}{}", key, value), + format!("{key}{value}"), (key.to_lowercase(), value.to_string()), ); } diff --git a/proxy_agent/src/common/logger.rs b/proxy_agent/src/common/logger.rs index 87432231..a3e06819 100644 --- a/proxy_agent/src/common/logger.rs +++ b/proxy_agent/src/common/logger.rs @@ -64,11 +64,11 @@ pub fn write_serial_console_log(message: String) { { Ok(mut serial_console) => { if serial_console.write_all(message.as_bytes()).is_err() { - eprintln!("Failed to write to serial console: {}", message); + eprintln!("Failed to write to serial console: {message}"); } } Err(e) => { - eprintln!("Failed to open serial console: {}", e); + eprintln!("Failed to open serial console: {e}"); } } } diff --git a/proxy_agent/src/host_clients/wire_server_client.rs b/proxy_agent/src/host_clients/wire_server_client.rs index 252b1a7f..ced98348 100644 --- a/proxy_agent/src/host_clients/wire_server_client.rs +++ b/proxy_agent/src/host_clients/wire_server_client.rs @@ -82,7 +82,7 @@ impl WireServerClient { Err(e) => { return Err(Error::WireServer( WireServerErrorType::Telemetry, - format!("Failed to send request {}", e), + format!("Failed to send request {e}"), )) } }; @@ -91,10 +91,7 @@ impl WireServerClient { if !status.is_success() { return Err(Error::WireServer( WireServerErrorType::Telemetry, - format!( - "Failed to get response from {}, status code: {}", - url, status - ), + format!("Failed to get response from {url}, status code: {status}"), )); } diff --git a/proxy_agent/src/key_keeper.rs b/proxy_agent/src/key_keeper.rs index 11d939df..81e5b177 100644 --- a/proxy_agent/src/key_keeper.rs +++ b/proxy_agent/src/key_keeper.rs @@ -175,7 +175,7 @@ impl KeyKeeper { let notify = match self.key_keeper_shared_state.get_notify().await { Ok(notify) => notify, Err(e) => { - logger::write_error(format!("Failed to get notify: {}", e)); + logger::write_error(format!("Failed to get notify: {e}")); return; } }; @@ -187,8 +187,7 @@ impl KeyKeeper { .await { logger::write_error(format!( - "Failed to set key_keeper module state to 'Running' with error: {} ", - e + "Failed to set key_keeper module state to 'Running' with error: {e} " )); } @@ -205,8 +204,7 @@ impl KeyKeeper { Ok(state) => state, Err(e) => { logger::write_warning(format!( - "Failed to get current secure channel state: {}", - e + "Failed to get current secure channel state: {e}" )); UNKNOWN_STATE.to_string() } @@ -229,10 +227,10 @@ impl KeyKeeper { // this is to handle quicker response to the secure channel state change during VM provisioning. _ = notify.notified() => { if current_state == DISABLE_STATE || current_state == UNKNOWN_STATE { - logger::write_warning(format!("poll_secure_channel_status task notified and secure channel state is '{}', reset states and start poll status now.", current_state)); + logger::write_warning(format!("poll_secure_channel_status task notified and secure channel state is '{current_state}', reset states and start poll status now.")); provision::key_latch_ready_state_reset(self.provision_shared_state.clone()).await; if let Err(e) = self.key_keeper_shared_state.update_current_secure_channel_state(UNKNOWN_STATE.to_string()).await{ - logger::write_warning(format!("Failed to update secure channel state to 'Unknown': {}", e)); + logger::write_warning(format!("Failed to update secure channel state to 'Unknown': {e}")); } if start.elapsed().as_millis() > PROVISION_TIMEUP_IN_MILLISECONDS { @@ -253,7 +251,7 @@ impl KeyKeeper { let continue_sleep = sleep.as_millis() - slept_time_in_millisec; if continue_sleep > 0 { let continue_sleep = Duration::from_millis(continue_sleep as u64); - let message = format!("poll_secure_channel_status task notified but secure channel state is '{}', continue with sleep wait for {:?}.", current_state, continue_sleep); + let message = format!("poll_secure_channel_status task notified but secure channel state is '{current_state}', continue with sleep wait for {continue_sleep:?}."); logger::write_warning(message); tokio::time::sleep(continue_sleep).await; } @@ -292,12 +290,12 @@ impl KeyKeeper { let status = match key::get_status(&self.base_url).await { Ok(s) => s, Err(e) => { - self.update_status_message(format!("Failed to get key status - {}", e), true) + self.update_status_message(format!("Failed to get key status - {e}"), true) .await; continue; } }; - self.update_status_message(format!("Got key status successfully: {}.", status), true) + self.update_status_message(format!("Got key status successfully: {status}."), true) .await; let mut access_control_rules_changed = false; @@ -313,21 +311,20 @@ impl KeyKeeper { Ok((updated, old_wire_server_rule_id)) => { if updated { logger::write_warning(format!( - "Wireserver rule id changed from '{}' to '{}'.", - old_wire_server_rule_id, wireserver_rule_id + "Wireserver rule id changed from '{old_wire_server_rule_id}' to '{wireserver_rule_id}'." )); if let Err(e) = self .key_keeper_shared_state .set_wireserver_rules(status.get_wireserver_rules()) .await { - logger::write_error(format!("Failed to set wireserver rules: {}", e)); + logger::write_error(format!("Failed to set wireserver rules: {e}")); } access_control_rules_changed = true; } } Err(e) => { - logger::write_warning(format!("Failed to update wireserver rule id: {}", e)); + logger::write_warning(format!("Failed to update wireserver rule id: {e}")); } } @@ -339,21 +336,20 @@ impl KeyKeeper { Ok((updated, old_imds_rule_id)) => { if updated { logger::write_warning(format!( - "IMDS rule id changed from '{}' to '{}'.", - old_imds_rule_id, imds_rule_id + "IMDS rule id changed from '{old_imds_rule_id}' to '{imds_rule_id}'." )); if let Err(e) = self .key_keeper_shared_state .set_imds_rules(status.get_imds_rules()) .await { - logger::write_error(format!("Failed to set imds rules: {}", e)); + logger::write_error(format!("Failed to set imds rules: {e}")); } access_control_rules_changed = true; } } Err(e) => { - logger::write_warning(format!("Failed to update imds rule id: {}", e)); + logger::write_warning(format!("Failed to update imds rule id: {e}")); } } @@ -365,21 +361,20 @@ impl KeyKeeper { Ok((updated, old_hostga_rule_id)) => { if updated { logger::write_warning(format!( - "HostGA rule id changed from '{}' to '{}'.", - old_hostga_rule_id, hostga_rule_id + "HostGA rule id changed from '{old_hostga_rule_id}' to '{hostga_rule_id}'." )); if let Err(e) = self .key_keeper_shared_state .set_hostga_rules(status.get_hostga_rules()) .await { - logger::write_error(format!("Failed to set HostGA rules: {}", e)); + logger::write_error(format!("Failed to set HostGA rules: {e}")); } access_control_rules_changed = true; } } Err(e) => { - logger::write_warning(format!("Failed to update HostGA rule id: {}", e)); + logger::write_warning(format!("Failed to update HostGA rule id: {e}")); } } @@ -416,7 +411,7 @@ impl KeyKeeper { if let Err(e) = self.key_keeper_shared_state.update_key(key.clone()).await { - logger::write_warning(format!("Failed to update key: {}", e)); + logger::write_warning(format!("Failed to update key: {e}")); } let message = helpers::write_startup_event( @@ -440,7 +435,7 @@ impl KeyKeeper { Err(e) => { event_logger::write_event( LoggerLevel::Info, - format!("Failed to fetch local key details with error: {:?}. Will try acquire the key details from Server.", e), + format!("Failed to fetch local key details with error: {e:?}. Will try acquire the key details from Server."), "poll_secure_channel_status", "key_keeper", logger::AGENT_LOGGER_KEY, @@ -458,7 +453,7 @@ impl KeyKeeper { Ok(k) => k, Err(e) => { self.update_status_message( - format!("Failed to acquire key details: {:?}", e), + format!("Failed to acquire key details: {e:?}"), true, ) .await; @@ -471,11 +466,11 @@ impl KeyKeeper { match Self::store_key(&self.key_dir, &key) { Ok(()) => { logger::write_information(format!( - "Successfully acquired the key '{}' details from server and saved locally.", guid)); + "Successfully acquired the key '{guid}' details from server and saved locally.")); } Err(e) => { self.update_status_message( - format!("Failed to save key details to file: {:?}", e), + format!("Failed to save key details to file: {e:?}"), true, ) .await; @@ -487,8 +482,7 @@ impl KeyKeeper { if let Err(e) = Self::check_key(&self.key_dir, &key) { self.update_status_message( format!( - "Failed to check the key '{}' details saved locally: {:?}.", - guid, e + "Failed to check the key '{guid}' details saved locally: {e:?}." ), true, ) @@ -501,7 +495,7 @@ impl KeyKeeper { if let Err(e) = self.key_keeper_shared_state.update_key(key.clone()).await { - logger::write_warning(format!("Failed to update key: {}", e)); + logger::write_warning(format!("Failed to update key: {e}")); } let message = helpers::write_startup_event( @@ -521,7 +515,7 @@ impl KeyKeeper { .await; } Err(e) => { - logger::write_warning(format!("Failed to attest the key: {:?}", e)); + logger::write_warning(format!("Failed to attest the key: {e:?}")); continue; } } @@ -567,7 +561,7 @@ impl KeyKeeper { // clear key in memory for disabled state if let Err(e) = self.key_keeper_shared_state.clear_key().await { - logger::write_warning(format!("Failed to clear key: {}", e)); + logger::write_warning(format!("Failed to clear key: {e}")); } provision::key_latched( self.cancellation_token.clone(), @@ -581,7 +575,7 @@ impl KeyKeeper { } } Err(e) => { - logger::write_warning(format!("Failed to update secure channel state: {}", e)); + logger::write_warning(format!("Failed to update secure channel state: {e}")); } } } @@ -600,7 +594,7 @@ impl KeyKeeper { } } Err(e) => { - logger::write_warning(format!("Failed to set module status message: {}", e)); + logger::write_warning(format!("Failed to set module status message: {e}")); } } } @@ -616,8 +610,7 @@ impl KeyKeeper { &key_file, serde_json::to_string(&key).map_err(|e| { Error::Key(KeyErrorType::StoreLocalKey(format!( - "serialize key error: {:?} ", - e + "serialize key error: {e:?} " ))) })?, ) @@ -690,8 +683,7 @@ impl KeyKeeper { serde_json::from_str::(&key_data).map_err(|e| { Error::Key(crate::common::error::KeyErrorType::FetchLocalKey(format!( - "Parse key data with error: {}", - e + "Parse key data with error: {e}" ))) }) } @@ -704,8 +696,7 @@ impl KeyKeeper { #[cfg(windows)] { logger::write_information(format!( - "Failed to fetch .encrypted file with error: {}. Fallback to fetch .key file for windows platform.", - _e + "Failed to fetch .encrypted file with error: {_e}. Fallback to fetch .key file for windows platform." )); } @@ -760,8 +751,7 @@ impl KeyKeeper { .await { logger::write_warning(format!( - "Failed to set key_keeper module state to 'Stopped' with error: {} ", - e + "Failed to set key_keeper module state to 'Stopped' with error: {e} " )); } } diff --git a/proxy_agent/src/key_keeper/key.rs b/proxy_agent/src/key_keeper/key.rs index 9adcd118..bf8ba5ac 100644 --- a/proxy_agent/src/key_keeper/key.rs +++ b/proxy_agent/src/key_keeper/key.rs @@ -419,8 +419,7 @@ impl KeyStatus { && key_delivery_method != constants::KEY_DELIVERY_METHOD_VTPM { validate_message.push_str(&format!( - "keyDeliveryMethod '{}' is invalid; ", - key_delivery_method + "keyDeliveryMethod '{key_delivery_method}' is invalid; " )); } @@ -444,7 +443,7 @@ impl KeyStatus { && state != super::MUST_SIG_WIRESERVER_IMDS { validate_message - .push_str(&format!("secureChannelState '{}' is invalid; ", state)); + .push_str(&format!("secureChannelState '{state}' is invalid; ")); validate_result = false; } } @@ -528,7 +527,7 @@ impl KeyStatus { None => return super::DISABLE_STATE.to_string(), } - format!("{} - {} - {}", wireserver, imds, hostga) + format!("{wireserver} - {imds} - {hostga}") } else { super::DISABLE_STATE.to_string() } @@ -720,7 +719,7 @@ const KEY_URL: &str = "/secure-channel/key"; pub async fn get_status(base_url: &Uri) -> Result { let (host, port) = hyper_client::host_port_from_uri(base_url)?; - let url = format!("http://{}:{}{}", host, port, STATUS_URL); + let url = format!("http://{host}:{port}{STATUS_URL}"); let url: Uri = url.parse().map_err(|e| { Error::Key(KeyErrorType::ParseKeyUrl( base_url.to_string(), @@ -739,7 +738,7 @@ pub async fn get_status(base_url: &Uri) -> Result { pub async fn acquire_key(base_url: &Uri) -> Result { let (host, port) = hyper_client::host_port_from_uri(base_url)?; - let url = format!("http://{}:{}{}", host, port, KEY_URL); + let url = format!("http://{host}:{port}{KEY_URL}"); let url: Uri = url.parse().map_err(|e| { Error::Key(KeyErrorType::ParseKeyUrl( base_url.to_string(), diff --git a/proxy_agent/src/main.rs b/proxy_agent/src/main.rs index 63ae8657..74940119 100644 --- a/proxy_agent/src/main.rs +++ b/proxy_agent/src/main.rs @@ -97,7 +97,7 @@ async fn main() { match service_dispatcher::start(constants::PROXY_AGENT_SERVICE_NAME, ffi_service_main) { Ok(_) => {} Err(e) => { - logger::write_error(format!("Error in starting the service dispatcher: {}", e)); + logger::write_error(format!("Error in starting the service dispatcher: {e}")); } } } @@ -121,7 +121,7 @@ fn proxy_agent_windows_service_main(_args: Vec) { .expect("You must provide the Tokio runtime handle before this function is called"); handle.block_on(async { if let Err(e) = windows::run_service().await { - logger::write_error(format!("Error in running the service: {}", e)); + logger::write_error(format!("Error in running the service: {e}")); } }); } diff --git a/proxy_agent/src/provision.rs b/proxy_agent/src/provision.rs index 806fa0ad..bec9c783 100644 --- a/proxy_agent/src/provision.rs +++ b/proxy_agent/src/provision.rs @@ -596,10 +596,7 @@ pub mod provision_query { let state = match self.get_current_provision_status(first_loop).await { Ok(state) => state, Err(e) => { - println!( - "Failed to query the current provision state with error: {}.", - e - ); + println!("Failed to query the current provision state with error: {e}."); ProvisionState::new(false, String::new()) } }; diff --git a/proxy_agent/src/proxy.rs b/proxy_agent/src/proxy.rs index 31de00a9..19be4655 100644 --- a/proxy_agent/src/proxy.rs +++ b/proxy_agent/src/proxy.rs @@ -91,7 +91,7 @@ async fn get_user( } else { let user = User::from_logon_id(logon_id)?; if let Err(e) = proxy_server_shared_state.add_user(user.clone()).await { - println!("Failed to add user: {} to cache", e); + println!("Failed to add user: {e} to cache"); } Ok(user) } @@ -166,7 +166,7 @@ impl Process { #[cfg(windows)] { let handler = windows::get_process_handler(pid).unwrap_or_else(|e| { - println!("Failed to get process handler: {}", e); + println!("Failed to get process handler: {e}"); 0 }); let base_info = windows::query_basic_process_info(handler); @@ -178,7 +178,7 @@ impl Process { Err(e) => { process_full_path = PathBuf::default(); cmd = UNDEFINED.to_string(); - println!("Failed to query basic process info: {}", e); + println!("Failed to query basic process info: {e}"); } } } diff --git a/proxy_agent/src/proxy/authorization_rules.rs b/proxy_agent/src/proxy/authorization_rules.rs index 6d4805b6..27ef84fa 100644 --- a/proxy_agent/src/proxy/authorization_rules.rs +++ b/proxy_agent/src/proxy/authorization_rules.rs @@ -52,7 +52,7 @@ impl std::str::FromStr for AuthorizationMode { "disabled" => Ok(AuthorizationMode::Disabled), "audit" => Ok(AuthorizationMode::Audit), "enforce" => Ok(AuthorizationMode::Enforce), - _ => Err(format!("Invalid AuthorizationMode: {}", s)), + _ => Err(format!("Invalid AuthorizationMode: {s}")), } } } @@ -84,7 +84,7 @@ impl ComputedAuthorizationItem { Ok(mode) => mode, Err(err) => { // This should not happen, log the error and set the mode to disabled - logger::write_error(format!("Failed to parse authorization mode: {}", err)); + logger::write_error(format!("Failed to parse authorization mode: {err}")); AuthorizationMode::Disabled } }; @@ -184,7 +184,7 @@ impl ComputedAuthorizationItem { any_privilege_matched = true; logger.write( LoggerLevel::Trace, - format!("Request matched privilege '{}'.", privilege_name), + format!("Request matched privilege '{privilege_name}'."), ); if let Some(assignments) = self.privilegeAssignments.get(privilege_name) { @@ -195,8 +195,7 @@ impl ComputedAuthorizationItem { logger.write( LoggerLevel::Trace, format!( - "Request matched privilege '{}' and identity '{}'.", - privilege_name, identity_name + "Request matched privilege '{privilege_name}' and identity '{identity_name}'." ), ); return true; @@ -206,23 +205,21 @@ impl ComputedAuthorizationItem { logger.write( LoggerLevel::Trace, format!( - "Request matched privilege '{}' but no identity matched.", - privilege_name + "Request matched privilege '{privilege_name}' but no identity matched." ), ); } else { logger.write( LoggerLevel::Trace, format!( - "Request matched privilege '{}' but no identity assigned.", - privilege_name + "Request matched privilege '{privilege_name}' but no identity assigned." ), ); } } else { logger.write( LoggerLevel::Trace, - format!("Request does not match privilege '{}'.", privilege_name), + format!("Request does not match privilege '{privilege_name}'."), ); } } diff --git a/proxy_agent/src/proxy/proxy_authorizer.rs b/proxy_agent/src/proxy/proxy_authorizer.rs index 8e113616..cbe575f7 100644 --- a/proxy_agent/src/proxy/proxy_authorizer.rs +++ b/proxy_agent/src/proxy/proxy_authorizer.rs @@ -66,7 +66,7 @@ impl Authorizer for WireServer { } else { if rules.mode == AuthorizationMode::Audit { logger.write( - LoggerLevel::Info, format!("WireServer request {} denied in audit mode, continue forward the request", request_url)); + LoggerLevel::Info, format!("WireServer request {request_url} denied in audit mode, continue forward the request")); return AuthorizeResult::OkWithAudit; } return AuthorizeResult::Forbidden; @@ -104,8 +104,7 @@ impl Authorizer for Imds { logger.write( LoggerLevel::Info, format!( - "IMDS request {} denied in audit mode, continue forward the request", - request_url + "IMDS request {request_url} denied in audit mode, continue forward the request" ), ); return AuthorizeResult::OkWithAudit; @@ -143,7 +142,7 @@ impl Authorizer for GAPlugin { } else { if rules.mode == AuthorizationMode::Audit { logger.write( - LoggerLevel::Info, format!("HostGAPlugin request {} denied in audit mode, continue forward the request", request_url)); + LoggerLevel::Info, format!("HostGAPlugin request {request_url} denied in audit mode, continue forward the request")); return AuthorizeResult::OkWithAudit; } return AuthorizeResult::Forbidden; diff --git a/proxy_agent/src/proxy/proxy_connection.rs b/proxy_agent/src/proxy/proxy_connection.rs index e037bb8b..806057cf 100644 --- a/proxy_agent/src/proxy/proxy_connection.rs +++ b/proxy_agent/src/proxy/proxy_connection.rs @@ -39,7 +39,7 @@ impl Client { let full_url = req.uri().to_string(); self.sender.send_request(req).await.map_err(|e| { Error::Hyper(HyperErrorType::Custom( - format!("Failed to send request to {}", full_url), + format!("Failed to send request to {full_url}"), e, )) }) @@ -91,7 +91,7 @@ impl TcpConnectionContext { Err(e) => { logger.write( LoggerLevel::Error, - format!("Failed to get claims from audit entry: {}", e), + format!("Failed to get claims from audit entry: {e}"), ); // return None for claims None @@ -154,22 +154,20 @@ impl TcpConnectionContext { logger.write( LoggerLevel::Trace, format!( - "Found audit entry with client_source_port '{}' successfully", - client_source_port + "Found audit entry with client_source_port '{client_source_port}' successfully" ), ); match redirector::remove_audit(client_source_port, redirector_shared_state).await { Ok(_) => logger.write( LoggerLevel::Trace, format!( - "Removed audit entry with client_source_port '{}' successfully", - client_source_port + "Removed audit entry with client_source_port '{client_source_port}' successfully" ), ), Err(e) => { logger.write( LoggerLevel::Warn, - format!("Failed to remove audit entry: {}", e), + format!("Failed to remove audit entry: {e}"), ); } } @@ -178,8 +176,7 @@ impl TcpConnectionContext { } Err(e) => { let message = format!( - "Failed to find audit entry with client_source_port '{}' with error: {}", - client_source_port, e + "Failed to find audit entry with client_source_port '{client_source_port}' with error: {e}" ); logger.write(LoggerLevel::Warn, message.clone()); @@ -206,7 +203,7 @@ impl TcpConnectionContext { Err(e) => { logger.write( LoggerLevel::Warn, - format!("Failed to get lookup_audit_from_stream with error: {}", e), + format!("Failed to get lookup_audit_from_stream with error: {e}"), ); Err(Error::FindAuditEntryError(message)) } diff --git a/proxy_agent/src/proxy/proxy_server.rs b/proxy_agent/src/proxy/proxy_server.rs index 968773b6..1fe378bc 100644 --- a/proxy_agent/src/proxy/proxy_server.rs +++ b/proxy_agent/src/proxy/proxy_server.rs @@ -111,10 +111,7 @@ impl ProxyServer { } _ => { // other error, return it - return Err(Error::Io( - format!("Failed to bind TcpListener '{}'", addr), - e, - )); + return Err(Error::Io(format!("Failed to bind TcpListener '{addr}'"), e)); } }, } @@ -123,7 +120,7 @@ impl ProxyServer { // one more effort try bind to the addr TcpListener::bind(addr) .await - .map_err(|e| Error::Io(format!("Failed to bind TcpListener '{}'", addr), e)) + .map_err(|e| Error::Io(format!("Failed to bind TcpListener '{addr}'"), e)) } pub async fn start(&self) { @@ -145,14 +142,14 @@ impl ProxyServer { .set_module_status_message(message.to_string(), AgentStatusModule::ProxyServer) .await { - logger::write_warning(format!("Failed to set module status message: {}", e)); + logger::write_warning(format!("Failed to set module status message: {e}")); } if let Err(e) = self .agent_status_shared_state .set_module_state(ModuleState::STOPPED, AgentStatusModule::ProxyServer) .await { - logger::write_warning(format!("Failed to set module state: {}", e)); + logger::write_warning(format!("Failed to set module state: {e}")); } // send this critical error to event logger @@ -179,14 +176,14 @@ impl ProxyServer { .set_module_status_message(message.to_string(), AgentStatusModule::ProxyServer) .await { - logger::write_warning(format!("Failed to set module status message: {}", e)); + logger::write_warning(format!("Failed to set module status message: {e}")); } if let Err(e) = self .agent_status_shared_state .set_module_state(ModuleState::RUNNING, AgentStatusModule::ProxyServer) .await { - logger::write_warning(format!("Failed to set module state: {}", e)); + logger::write_warning(format!("Failed to set module state: {e}")); } provision::listener_started( self.cancellation_token.clone(), @@ -213,7 +210,7 @@ impl ProxyServer { self.handle_new_tcp_connection(stream, client_addr).await; }, Err(e) => { - logger::write_error(format!("Failed to accept connection: {}", e)); + logger::write_error(format!("Failed to accept connection: {e}")); } } } @@ -235,7 +232,7 @@ impl ProxyServer { Err(e) => { ConnectionLogger::new(0, 0).write( LoggerLevel::Error, - format!("Failed to increase tcp connection count: {}", e), + format!("Failed to increase tcp connection count: {e}"), ); return; } @@ -243,7 +240,7 @@ impl ProxyServer { let mut tcp_connection_logger = ConnectionLogger::new(tcp_connection_id, 0); tcp_connection_logger.write( LoggerLevel::Trace, - format!("Accepted new tcp connection [{}].", tcp_connection_id), + format!("Accepted new tcp connection [{tcp_connection_id}]."), ); tokio::spawn({ @@ -255,7 +252,7 @@ impl ProxyServer { Err(e) => { tcp_connection_logger.write( LoggerLevel::Error, - format!("Failed to set stream read timeout: {}", e), + format!("Failed to set stream read timeout: {e}"), ); return; } @@ -312,7 +309,7 @@ impl ProxyServer { { tcp_connection_logger.write( LoggerLevel::Warn, - format!("ProxyListener serve_connection error: {}", e), + format!("ProxyListener serve_connection error: {e}"), ); } } @@ -342,7 +339,7 @@ impl ProxyServer { if let Err(e) = std_stream.set_read_timeout(Some(std::time::Duration::from_secs(10))) { connection_logger.write( LoggerLevel::Warn, - format!("Failed to set read timeout: {}", e), + format!("Failed to set read timeout: {e}"), ); } @@ -376,7 +373,7 @@ impl ProxyServer { Err(e) => { tcp_connection_context.log( LoggerLevel::Error, - format!("Failed to increase connection count: {}", e), + format!("Failed to increase connection count: {e}"), ); return Ok(Self::empty_response(StatusCode::INTERNAL_SERVER_ERROR)); } @@ -455,7 +452,7 @@ impl ProxyServer { &mut http_connection_context, StatusCode::MISDIRECTED_REQUEST, false, - format!("Failed to get claims json string: {}", e), + format!("Failed to get claims json string: {e}"), ) .await; return Ok(Self::empty_response(StatusCode::MISDIRECTED_REQUEST)); @@ -477,7 +474,7 @@ impl ProxyServer { &mut http_connection_context, StatusCode::INTERNAL_SERVER_ERROR, false, - format!("Failed to get access control rules: {}", e), + format!("Failed to get access control rules: {e}"), ) .await; return Ok(Self::empty_response(StatusCode::INTERNAL_SERVER_ERROR)); @@ -505,7 +502,7 @@ impl ProxyServer { &mut http_connection_context, StatusCode::FORBIDDEN, false, - format!("Block unauthorized request: {}", claim_details), + format!("Block unauthorized request: {claim_details}"), ) .await; return Ok(Self::empty_response(StatusCode::FORBIDDEN)); @@ -528,10 +525,7 @@ impl ProxyServer { Err(e) => { http_connection_context.log( LoggerLevel::Error, - format!( - "Failed to add claims header: {} with error: {}", - host_claims, e - ), + format!("Failed to add claims header: {host_claims} with error: {e}"), ); return Ok(Self::empty_response(StatusCode::BAD_GATEWAY)); } @@ -544,7 +538,7 @@ impl ProxyServer { Err(e) => { http_connection_context.log( LoggerLevel::Error, - format!("Failed to add date header with error: {}", e), + format!("Failed to add date header with error: {e}"), ); return Ok(Self::empty_response(StatusCode::BAD_GATEWAY)); } @@ -571,7 +565,7 @@ impl ProxyServer { Err(e) => { http_connection_context.log( LoggerLevel::Error, - format!("Failed to convert request: {}", e), + format!("Failed to convert request: {e}"), ); return Ok(Self::empty_response(StatusCode::BAD_REQUEST)); } @@ -624,7 +618,7 @@ impl ProxyServer { Err(e) => { logger.write( LoggerLevel::Warn, - format!("Failed to parse time_tick header: {}", e), + format!("Failed to parse time_tick header: {e}"), ); 0 } @@ -652,7 +646,7 @@ impl ProxyServer { if let Err(e) = self.key_keeper_shared_state.notify().await { logger.write( LoggerLevel::Warn, - format!("Failed to notify key_keeper: {}", e), + format!("Failed to notify key_keeper: {e}"), ); } } @@ -663,7 +657,7 @@ impl ProxyServer { ); match serde_json::to_string(&provision_state) { Ok(json) => { - logger.write(LoggerLevel::Info, format!("Provision state: {}", json)); + logger.write(LoggerLevel::Info, format!("Provision state: {json}")); let mut response = Response::new(hyper_client::full_body(json.as_bytes().to_vec())); response.headers_mut().insert( hyper::header::CONTENT_TYPE, @@ -672,7 +666,7 @@ impl ProxyServer { Ok(response) } Err(e) => { - let error = format!("Failed to get provision state: {}", e); + let error = format!("Failed to get provision state: {e}"); logger.write(LoggerLevel::Warn, error.to_string()); let mut response = Response::new(hyper_client::full_body(error.as_bytes().to_vec())); @@ -698,7 +692,7 @@ impl ProxyServer { &mut http_connection_context, http_status_code, false, - format!("Failed to send request to host: {}", e), + format!("Failed to send request to host: {e}"), ) .await; return Ok(Self::empty_response(http_status_code)); @@ -713,7 +707,7 @@ impl ProxyServer { Err(e) => { logger.write( LoggerLevel::Error, - format!("Failed to get frame data: {:?}", e), + format!("Failed to get frame data: {e:?}"), ); Bytes::new() } @@ -810,7 +804,7 @@ impl ProxyServer { { http_connection_context.log( LoggerLevel::Warn, - format!("Failed to add failed connection summary: {}", e), + format!("Failed to add failed connection summary: {e}"), ); } } else if let Err(e) = self @@ -820,7 +814,7 @@ impl ProxyServer { { http_connection_context.log( LoggerLevel::Warn, - format!("Failed to add connection summary: {}", e), + format!("Failed to add connection summary: {e}"), ); } } @@ -845,7 +839,7 @@ impl ProxyServer { Err(e) => { http_connection_context.log( LoggerLevel::Error, - format!("Failed to receive the request body: {}", e), + format!("Failed to receive the request body: {e}"), ); return Ok(Self::empty_response(StatusCode::BAD_REQUEST)); } @@ -890,8 +884,7 @@ impl ProxyServer { http_connection_context.log( LoggerLevel::Error, format!( - "Failed to add authorization header: {} with error: {}", - authorization_value, e + "Failed to add authorization header: {authorization_value} with error: {e}" ), ); return Ok(Self::empty_response(StatusCode::BAD_GATEWAY)); @@ -901,13 +894,13 @@ impl ProxyServer { http_connection_context.log( LoggerLevel::Trace, - format!("Added authorization header {}", authorization_value), + format!("Added authorization header {authorization_value}"), ) } Err(e) => { http_connection_context.log( LoggerLevel::Error, - format!("compute_signature failed with error: {}", e), + format!("compute_signature failed with error: {e}"), ); } } diff --git a/proxy_agent/src/proxy/windows.rs b/proxy_agent/src/proxy/windows.rs index c75869d4..74085f59 100644 --- a/proxy_agent/src/proxy/windows.rs +++ b/proxy_agent/src/proxy/windows.rs @@ -41,8 +41,8 @@ fn load_netapi32_dll() -> Library { match unsafe { Library::new(dll_name) } { Ok(lib) => lib, Err(e) => { - logger::write_error(format!("Loading {} failed with error: {}.", dll_name, e)); - panic!("Loading {} failed with error: {}", dll_name, e); + logger::write_error(format!("Loading {dll_name} failed with error: {e}.")); + panic!("Loading {dll_name} failed with error: {e}"); } } } @@ -115,7 +115,7 @@ pub fn get_user(logon_id: u64) -> Result<(String, Vec)> { if status != 0 { let e = std::io::Error::from_raw_os_error(status as i32); return Err(Error::WindowsApi( - WindowsApiErrorType::LsaGetLogonSessionData(format!("failed with os error: {}", e)), + WindowsApiErrorType::LsaGetLogonSessionData(format!("failed with os error: {e}")), )); } @@ -127,8 +127,7 @@ pub fn get_user(logon_id: u64) -> Result<(String, Vec)> { // but finding that SECURITY_LOGON_SESSION_DATA->UserName.Length is 0, // it typically means that the logon session exists but does not have an associated username. logger::write_warning(format!( - "LsaGetLogonSessionData with login'{}' success, but user name is empty.", - logon_id + "LsaGetLogonSessionData with logon id '{logon_id}' success, but user name is empty." )); // return OK with UNDEFINED user name and empty groups return Ok((super::UNDEFINED.to_string(), Vec::new())); @@ -171,8 +170,7 @@ pub fn get_user(logon_id: u64) -> Result<(String, Vec)> { } else { let e = std::io::Error::from_raw_os_error(status as i32); logger::write_warning(format!( - "NetUserGetLocalGroups '{}' failed ({}) with os error: {}", - domain_user_name, status, e + "NetUserGetLocalGroups '{domain_user_name}' failed ({status}) with os error: {e}" )); } @@ -296,7 +294,7 @@ pub fn get_process_cmd(handler: isize) -> Result { std::io::Error::from_raw_os_error(status), ))); } - println!("return_length: {}", return_length); + println!("return_length: {return_length}"); let buf_len = (return_length as usize) / 2; let mut buffer: Vec = vec![0; buf_len + 1]; @@ -310,7 +308,7 @@ pub fn get_process_cmd(handler: isize) -> Result { &mut return_length as *mut _, ); if status < 0 { - eprintln!("NtQueryInformationProcess failed with status: {}", status); + eprintln!("NtQueryInformationProcess failed with status: {status}"); return Err(Error::WindowsApi(WindowsApiErrorType::WindowsOsError( std::io::Error::from_raw_os_error(status), ))); diff --git a/proxy_agent/src/proxy_agent_status.rs b/proxy_agent/src/proxy_agent_status.rs index 6496b308..777c1620 100644 --- a/proxy_agent/src/proxy_agent_status.rs +++ b/proxy_agent/src/proxy_agent_status.rs @@ -92,7 +92,7 @@ impl ProxyAgentStatusTask { .set_module_status_message(status_message, AgentStatusModule::ProxyAgentStatus) .await { - logger::write_error(format!("Error updating agent status message: {}", e)); + logger::write_error(format!("Error updating agent status message: {e}")); } } @@ -104,7 +104,7 @@ impl ProxyAgentStatusTask { { Ok(message) => message, Err(e) => { - let message = format!("Error getting agent status message: {}", e); + let message = format!("Error getting agent status message: {e}"); logger::write_error(message.clone()); message } @@ -131,7 +131,7 @@ impl ProxyAgentStatusTask { if status_report_time.elapsed() >= status_report_duration { let status = match serde_json::to_string(&aggregate_status.proxyAgentStatus) { Ok(status) => status, - Err(e) => format!("Error serializing proxy agent status: {}", e), + Err(e) => format!("Error serializing proxy agent status: {e}"), }; event_logger::write_event( LoggerLevel::Info, @@ -152,7 +152,7 @@ impl ProxyAgentStatusTask { .to_string(), ); if let Err(e) = self.agent_status_shared_state.clear_all_summary().await { - logger::write_error(format!("Error clearing the connection summary map and failed authenticate summary map: {}", e)); + logger::write_error(format!("Error clearing the connection summary map and failed authenticate summary map: {e}")); } start_time = Instant::now(); } @@ -249,7 +249,7 @@ impl ProxyAgentStatusTask { { Ok(count) => count, Err(e) => { - logger::write_error(format!("Error getting connection count: {}", e)); + logger::write_error(format!("Error getting connection count: {e}")); 0 } }, @@ -267,7 +267,7 @@ impl ProxyAgentStatusTask { { Ok(summary) => summary, Err(e) => { - logger::write_error(format!("Error getting connection summary: {}", e)); + logger::write_error(format!("Error getting connection summary: {e}")); vec![] } }, @@ -278,7 +278,7 @@ impl ProxyAgentStatusTask { { Ok(summary) => summary, Err(e) => { - logger::write_error(format!("Error getting failed connection summary: {}", e)); + logger::write_error(format!("Error getting failed connection summary: {e}")); vec![] } }, @@ -289,8 +289,7 @@ impl ProxyAgentStatusTask { let full_file_path = self.status_dir.join("status.json"); if let Err(e) = misc_helpers::json_write_to_file(&status, &full_file_path) { self.update_agent_status_message(format!( - "Error writing aggregate status to status file: {}", - e + "Error writing aggregate status to status file: {e}" )) .await; } else { diff --git a/proxy_agent/src/redirector.rs b/proxy_agent/src/redirector.rs index 6b71fa47..07a33433 100644 --- a/proxy_agent/src/redirector.rs +++ b/proxy_agent/src/redirector.rs @@ -138,8 +138,7 @@ impl Redirector { .await { logger::write_error(format!( - "Failed to set error status '{}' for redirector: {}", - message, e + "Failed to set error status '{message}' for redirector: {e}" )); } @@ -299,8 +298,7 @@ impl Redirector { .await { logger::write_error(format!( - "Failed to set error status '{}' for redirector: {}", - message, e + "Failed to set error status '{message}' for redirector: {e}" )); } } @@ -339,7 +337,7 @@ pub fn ip_to_string(ip: u32) -> String { pub fn string_to_ip(ip_str: &str) -> u32 { let ip_str_seg: Vec<&str> = ip_str.split('.').collect(); if ip_str_seg.len() != 4 { - logger::write_warning(format!("string_to_ip:: ip_str {} is invalid", ip_str)); + logger::write_warning(format!("string_to_ip:: ip_str {ip_str} is invalid")); return 0; } @@ -353,8 +351,7 @@ pub fn string_to_ip(ip_str: &str) -> u32 { } Err(e) => { logger::write_warning(format!( - "string_to_ip:: error parsing ip segment {} with error: {}", - ip_str, e + "string_to_ip:: error parsing ip segment {ip_str} with error: {e}" )); return 0; } diff --git a/proxy_agent/src/redirector/linux.rs b/proxy_agent/src/redirector/linux.rs index 6676ba39..f973428e 100644 --- a/proxy_agent/src/redirector/linux.rs +++ b/proxy_agent/src/redirector/linux.rs @@ -66,11 +66,11 @@ impl BpfObject { let key = sock_addr_skip_process_entry::from_pid(pid); let value = sock_addr_skip_process_entry::from_pid(pid); match skip_process_map.insert(key.to_array(), value.to_array(), 0) { - Ok(_) => logger::write(format!("skip_process_map updated with {}", pid)), + Ok(_) => logger::write(format!("skip_process_map updated with {pid}")), Err(err) => { return Err(Error::Bpf(BpfErrorType::UpdateBpfMapHashMap( skip_process_map_name.to_string(), - format!("insert pid: {}", pid), + format!("insert pid: {pid}"), err.to_string(), ))); } @@ -156,8 +156,7 @@ impl BpfObject { match program.attach(cgroup, CgroupAttachMode::Single) { Ok(link_id) => { logger::write(format!( - "connect4 program attached with id {:?}.", - link_id + "connect4 program attached with id {link_id:?}." )); } Err(err) => { @@ -211,8 +210,7 @@ impl BpfObject { match program.attach("tcp_connect", 0) { Ok(link_id) => { logger::write(format!( - "tcp_v4_connect program attached with id {:?}.", - link_id + "tcp_v4_connect program attached with id {link_id:?}." )); } Err(err) => { @@ -340,8 +338,7 @@ impl BpfObject { } Err(err) => { logger::write(format!( - "Failed to load HashMap 'policy_map' with error: {}", - err + "Failed to load HashMap 'policy_map' with error: {err}" )); } }, @@ -360,7 +357,7 @@ impl BpfObject { audit_map.remove(&key.to_array()).map_err(|err| { Error::Bpf(BpfErrorType::MapDeleteElem( source_port.to_string(), - format!("Error: {}", err), + format!("Error: {err}"), )) })?; } @@ -402,7 +399,7 @@ impl super::Redirector { Err(e) => { event_logger::write_event( LoggerLevel::Warn, - format!("Failed to get the cgroup2 mount path {}, fallback to use the cgroup2 path from config file.", e), + format!("Failed to get the cgroup2 mount path {e}, fallback to use the cgroup2 path from config file."), "start", "redirector/linux", logger::AGENT_LOGGER_KEY, @@ -411,7 +408,7 @@ impl super::Redirector { } }; if let Err(e) = bpf_object.attach_cgroup_program(cgroup2_path) { - let message = format!("Failed to attach cgroup program for redirection. {}", e); + let message = format!("Failed to attach cgroup program for redirection. {e}"); event_logger::write_event( LoggerLevel::Warn, message.to_string(), diff --git a/proxy_agent/src/redirector/windows.rs b/proxy_agent/src/redirector/windows.rs index 7daf8092..cf23a3b8 100644 --- a/proxy_agent/src/redirector/windows.rs +++ b/proxy_agent/src/redirector/windows.rs @@ -122,8 +122,7 @@ pub fn get_audit_from_redirect_context(raw_socket_id: usize) -> Result Result bool { if let Err(e) = EBPF_API.set(ebpf_api) { event_logger::write_event( LoggerLevel::Error, - format!("{}", e), + format!("{e}"), "try_load_ebpf_api", "redirector", logger::AGENT_LOGGER_KEY, @@ -61,7 +61,7 @@ fn init_ebpf_lib() -> Option { if let Err(e) = EBPF_API_VERSION.set(v) { event_logger::write_event( LoggerLevel::Error, - format!("{}", e), + format!("{e}"), "EBPF_API_VERSION.set", "redirector", logger::AGENT_LOGGER_KEY, @@ -71,7 +71,7 @@ fn init_ebpf_lib() -> Option { Err(e) => { event_logger::write_event( LoggerLevel::Warn, - format!("{}", e), + format!("{e}"), "get_file_product_version", "redirector", logger::AGENT_LOGGER_KEY, @@ -85,7 +85,7 @@ fn init_ebpf_lib() -> Option { Err(e) => { event_logger::write_event( LoggerLevel::Warn, - format!("{}", e), + format!("{e}"), "load_ebpf_api", "redirector", logger::AGENT_LOGGER_KEY, @@ -101,7 +101,7 @@ fn init_ebpf_lib() -> Option { Err(e) => { event_logger::write_event( LoggerLevel::Warn, - format!("{}", e), + format!("{e}"), "load_ebpf_api", "redirector", logger::AGENT_LOGGER_KEY, diff --git a/proxy_agent/src/redirector/windows/bpf_prog.rs b/proxy_agent/src/redirector/windows/bpf_prog.rs index 27b6c8f8..71e51968 100644 --- a/proxy_agent/src/redirector/windows/bpf_prog.rs +++ b/proxy_agent/src/redirector/windows/bpf_prog.rs @@ -60,10 +60,7 @@ impl BpfObject { let error_code = libbpf_get_error()?; return Err(Error::Bpf(BpfErrorType::OpenBpfObject( bpf_file_path.display().to_string(), - format!( - "bpf_object__open return null pointer with error code '{}'", - error_code - ), + format!("bpf_object__open return null pointer with error code '{error_code}'",), ))); } @@ -84,7 +81,7 @@ impl BpfObject { } else { return Err(Error::Bpf(BpfErrorType::LoadBpfObject( bpf_file_path.display().to_string(), - format!("bpf_object__load return with error code '{}'", result), + format!("bpf_object__load return with error code '{result}'"), ))); } @@ -109,7 +106,7 @@ impl BpfObject { let program_name = "authorize_connect4"; let connect4_program = match bpf_object__find_program_by_name(self.0, program_name) { Ok(p) => { - logger::write_information(format!("Found {} program.", program_name)); + logger::write_information(format!("Found {program_name} program.")); p } Err(e) => { @@ -141,7 +138,7 @@ impl BpfObject { if r != 0 { return Err(Error::Bpf(BpfErrorType::AttachBpfProgram( program_name.to_string(), - format!("ebpf_prog_attach return with error code '{}'", r), + format!("ebpf_prog_attach return with error code '{r}'"), ))); } logger::write_information( @@ -157,7 +154,7 @@ impl BpfObject { if r != 0 { return Err(Error::Bpf(BpfErrorType::AttachBpfProgram( program_name.to_string(), - format!("bpf_link_destroy return with error code '{}'", r), + format!("bpf_link_destroy return with error code '{r}'"), ))); } logger::write_information("Success destroyed link.".to_string()); @@ -165,7 +162,7 @@ impl BpfObject { Err(e) => { return Err(Error::Bpf(BpfErrorType::AttachBpfProgram( program_name.to_string(), - format!("bpf_link_destroy return with error '{}'", e), + format!("bpf_link_destroy return with error '{e}'"), ))); } } @@ -173,7 +170,7 @@ impl BpfObject { Err(e) => { return Err(Error::Bpf(BpfErrorType::AttachBpfProgram( program_name.to_string(), - format!("bpf_link_disconnect return with error '{}'", e), + format!("bpf_link_disconnect return with error '{e}'"), ))); } } @@ -181,7 +178,7 @@ impl BpfObject { Err(e) => { return Err(Error::Bpf(BpfErrorType::AttachBpfProgram( program_name.to_string(), - format!("ebpf_prog_attach return with error '{}'", e), + format!("ebpf_prog_attach return with error '{e}'"), ))); } } @@ -231,14 +228,14 @@ impl BpfObject { Error::Bpf(BpfErrorType::UpdateBpfMapHashMap( map_name.to_string(), endpoint_name.to_string(), - format!("bpf_map_update_elem returned error {}", e), + format!("bpf_map_update_elem returned error {e}"), )) })?; if result != 0 { return Err(Error::Bpf(BpfErrorType::UpdateBpfMapHashMap( map_name.to_string(), endpoint_name.to_string(), - format!("bpf_map_update_elem returned error code {}", result), + format!("bpf_map_update_elem returned error code {result}"), ))); } @@ -260,7 +257,7 @@ impl BpfObject { return; } if let Err(e) = bpf_object__close(self.0) { - logger::write_error(format!("bpf_object__close with error: {}", e)); + logger::write_error(format!("bpf_object__close with error: {e}")); } self.0 = std::ptr::null::().cast_mut(); @@ -297,14 +294,14 @@ impl BpfObject { .map_err(|e| { Error::Bpf(BpfErrorType::MapLookupElem( source_port.to_string(), - format!("Error: {}", e), + format!("Error: {e}"), )) })?; if result != 0 { return Err(Error::Bpf(BpfErrorType::MapLookupElem( source_port.to_string(), - format!("Result: {}", result), + format!("Result: {result}"), ))); } @@ -341,15 +338,15 @@ impl BpfObject { .map_err(|e| { Error::Bpf(BpfErrorType::UpdateBpfMapHashMap( map_name.to_string(), - format!("insert pid: {}", pid), - format!("bpf_map_update_elem returned error {}", e), + format!("insert pid: {pid}"), + format!("bpf_map_update_elem returned error {e}"), )) })?; if result != 0 { return Err(Error::Bpf(BpfErrorType::UpdateBpfMapHashMap( map_name.to_string(), - format!("insert pid: {}", pid), - format!("bpf_map_update_elem returned error code {}", result), + format!("insert pid: {pid}"), + format!("bpf_map_update_elem returned error code {result}"), ))); } @@ -374,14 +371,14 @@ impl BpfObject { bpf_map_delete_elem(map_fd, &key as *const destination_entry_t as *const c_void) .map_err(|e| { Error::Bpf(BpfErrorType::MapDeleteElem( - format!("dest_ipv4: {}, dest_port: {}", dest_ipv4, dest_port), - format!("Error: {}", e), + format!("dest_ipv4: {dest_ipv4}, dest_port: {dest_port}"), + format!("Error: {e}"), )) })?; if result != 0 { return Err(Error::Bpf(BpfErrorType::MapDeleteElem( - format!("dest_ipv4: {}, dest_port: {}", dest_ipv4, dest_port), - format!("Result: {}", result), + format!("dest_ipv4: {dest_ipv4}, dest_port: {dest_port}"), + format!("Result: {result}"), ))); } @@ -400,14 +397,14 @@ impl BpfObject { .map_err(|e| { Error::Bpf(BpfErrorType::MapDeleteElem( source_port.to_string(), - format!("Error: {}", e), + format!("Error: {e}"), )) })?; if result != 0 { return Err(Error::Bpf(BpfErrorType::MapDeleteElem( source_port.to_string(), - format!("Result: {}", result), + format!("Result: {result}"), ))); } diff --git a/proxy_agent/src/service/windows.rs b/proxy_agent/src/service/windows.rs index 1a44323b..d62170c3 100644 --- a/proxy_agent/src/service/windows.rs +++ b/proxy_agent/src/service/windows.rs @@ -40,8 +40,7 @@ pub async fn run_service() -> Result<()> { }; if let Err(e) = status_handle.set_service_status(stop_state) { logger::write_error(format!( - "Failed to set service status to Stopped: {}", - e + "Failed to set service status to Stopped: {e}" )); } } else { diff --git a/proxy_agent/src/shared_state/agent_status_wrapper.rs b/proxy_agent/src/shared_state/agent_status_wrapper.rs index bfffaab0..f540c4e5 100644 --- a/proxy_agent/src/shared_state/agent_status_wrapper.rs +++ b/proxy_agent/src/shared_state/agent_status_wrapper.rs @@ -207,7 +207,7 @@ impl AgentStatusSharedState { } } if response.send(updated).is_err() { - logger::write_warning(format!("Failed to send response to AgentStatusAction::SetStatusMessage for module {:?}", module)); + logger::write_warning(format!("Failed to send response to AgentStatusAction::SetStatusMessage for module {module:?}")); } } AgentStatusAction::GetStatusMessage { module, response } => { @@ -227,8 +227,7 @@ impl AgentStatusSharedState { }; if let Err(message) = response.send(message) { logger::write_warning(format!( - "Failed to send response to AgentStatusAction::GetStatusMessage for module '{:?}' with message '{:?}'", - module,message + "Failed to send response to AgentStatusAction::GetStatusMessage for module '{module:?}' with message '{message:?}'" )); } } @@ -258,7 +257,7 @@ impl AgentStatusSharedState { } } if let Err(state) = response.send(state) { - logger::write_warning(format!("Failed to send response to AgentStatusAction::SetState '{:?}' for module '{:?}'", state, module)); + logger::write_warning(format!("Failed to send response to AgentStatusAction::SetState '{state:?}' for module '{module:?}'")); } } AgentStatusAction::GetState { module, response } => { @@ -272,8 +271,7 @@ impl AgentStatusSharedState { }; if let Err(state) = response.send(state) { logger::write_warning(format!( - "Failed to send response to AgentStatusAction::GetState for module '{:?}' with state '{:?}'", - module,state + "Failed to send response to AgentStatusAction::GetState for module '{module:?}' with state '{state:?}'" )); } } @@ -342,8 +340,7 @@ impl AgentStatusSharedState { AgentStatusAction::GetConnectionCount { response } => { if let Err(count) = response.send(http_connection_count) { logger::write_warning(format!( - "Failed to send response to AgentStatusAction::GetConnectionCount with count '{:?}'", - count + "Failed to send response to AgentStatusAction::GetConnectionCount with count '{count:?}'" )); } } @@ -352,8 +349,7 @@ impl AgentStatusSharedState { http_connection_count = http_connection_count.overflowing_add(1).0; if let Err(count) = response.send(http_connection_count) { logger::write_warning(format!( - "Failed to send response to AgentStatusAction::IncreaseConnectionCount with count '{:?}'", - count + "Failed to send response to AgentStatusAction::IncreaseConnectionCount with count '{count:?}'" )); } } @@ -362,8 +358,7 @@ impl AgentStatusSharedState { tcp_connection_count = tcp_connection_count.overflowing_add(1).0; if let Err(count) = response.send(tcp_connection_count) { logger::write_warning(format!( - "Failed to send response to AgentStatusAction::IncreaseTcpConnectionCount with count '{:?}'", - count + "Failed to send response to AgentStatusAction::IncreaseTcpConnectionCount with count '{count:?}'" )); } } @@ -483,13 +478,13 @@ impl AgentStatusSharedState { .await .map_err(|e| { Error::SendError( - format!("AgentStatusAction::GetState ({:?})", module), + format!("AgentStatusAction::GetState ({module:?})"), e.to_string(), ) })?; response_rx .await - .map_err(|e| Error::RecvError(format!("AgentStatusAction::GetState ({:?})", module), e)) + .map_err(|e| Error::RecvError(format!("AgentStatusAction::GetState ({module:?})"), e)) } pub async fn set_module_state( @@ -507,13 +502,13 @@ impl AgentStatusSharedState { .await .map_err(|e| { Error::SendError( - format!("AgentStatusAction::SetState ({:?})", module), + format!("AgentStatusAction::SetState ({module:?})"), e.to_string(), ) })?; response_rx .await - .map_err(|e| Error::RecvError(format!("AgentStatusAction::SetState ({:?})", module), e)) + .map_err(|e| Error::RecvError(format!("AgentStatusAction::SetState ({module:?})"), e)) } pub async fn get_module_status_message(&self, module: AgentStatusModule) -> Result { @@ -526,13 +521,13 @@ impl AgentStatusSharedState { .await .map_err(|e| { Error::SendError( - format!("AgentStatusAction::GetStatusMessage ({:?})", module), + format!("AgentStatusAction::GetStatusMessage ({module:?})"), e.to_string(), ) })?; response_rx.await.map_err(|e| { Error::RecvError( - format!("AgentStatusAction::GetStatusMessage ({:?})", module), + format!("AgentStatusAction::GetStatusMessage ({module:?})"), e, ) }) @@ -560,13 +555,13 @@ impl AgentStatusSharedState { .await .map_err(|e| { Error::SendError( - format!("AgentStatusAction::SetStatusMessage ({:?})", module), + format!("AgentStatusAction::SetStatusMessage ({module:?})"), e.to_string(), ) })?; let update = response_rx.await.map_err(|e| { Error::RecvError( - format!("AgentStatusAction::SetStatusMessage ({:?})", module), + format!("AgentStatusAction::SetStatusMessage ({module:?})"), e, ) })?; @@ -577,7 +572,7 @@ impl AgentStatusSharedState { LoggerLevel::Warn, message, "set_module_status_message", - &format!("{:?}", module), + &format!("{module:?}"), logger::AGENT_LOGGER_KEY, ); } @@ -588,7 +583,7 @@ impl AgentStatusSharedState { let state = match self.get_module_state(module.clone()).await { Ok(state) => state, Err(e) => { - logger::write_warning(format!("Error getting module '{:?}' status: {}", module, e)); + logger::write_warning(format!("Error getting module '{module:?}' status: {e}")); ModuleState::UNKNOWN } }; @@ -596,8 +591,7 @@ impl AgentStatusSharedState { Ok(message) => message, Err(e) => { logger::write_warning(format!( - "Error getting module '{:?}' status message: {}", - module, e + "Error getting module '{module:?}' status message: {e}" )); super::UNKNOWN_STATUS_MESSAGE.to_string() } @@ -606,11 +600,10 @@ impl AgentStatusSharedState { event_logger::write_event( LoggerLevel::Warn, format!( - "Status message is too long, truncating to {} characters. Message: {}", - MAX_STATUS_MESSAGE_LENGTH, message + "Status message is too long, truncating to {MAX_STATUS_MESSAGE_LENGTH} characters. Message: {message}" ), "get_status", - &format!("{:?}", module), + &format!("{state:?}"), logger::AGENT_LOGGER_KEY, ); message = format!("{}...", &message[0..MAX_STATUS_MESSAGE_LENGTH]); diff --git a/proxy_agent/src/shared_state/key_keeper_wrapper.rs b/proxy_agent/src/shared_state/key_keeper_wrapper.rs index c7eed7e9..649b15e6 100644 --- a/proxy_agent/src/shared_state/key_keeper_wrapper.rs +++ b/proxy_agent/src/shared_state/key_keeper_wrapper.rs @@ -160,16 +160,14 @@ impl KeyKeeperSharedState { current_secure_channel_state = state.to_string(); if response.send(()).is_err() { logger::write_warning(format!( - "Failed to send response to KeyKeeperAction::SetSecureChannelState '{}' ", - state + "Failed to send response to KeyKeeperAction::SetSecureChannelState '{state}' " )); } } Some(KeyKeeperAction::GetSecureChannelState { response }) => { if let Err(state) = response.send(current_secure_channel_state.clone()) { logger::write_warning(format!( - "Failed to send response to KeyKeeperAction::GetSecureChannelState '{}'", - state + "Failed to send response to KeyKeeperAction::GetSecureChannelState '{state}'" )); } } @@ -177,16 +175,14 @@ impl KeyKeeperSharedState { wireserver_rule_id = rule_id.to_string(); if response.send(()).is_err() { logger::write_warning(format!( - "Failed to send response to KeyKeeperAction::SetWireServerRuleId '{}'", - rule_id + "Failed to send response to KeyKeeperAction::SetWireServerRuleId '{rule_id}'" )); } } Some(KeyKeeperAction::GetWireServerRuleId { response }) => { if let Err(rule_id) = response.send(wireserver_rule_id.clone()) { logger::write_warning(format!( - "Failed to send response to KeyKeeperAction::GetWireServerRuleId '{}'", - rule_id + "Failed to send response to KeyKeeperAction::GetWireServerRuleId '{rule_id}'" )); } } @@ -194,24 +190,21 @@ impl KeyKeeperSharedState { imds_rule_id = rule_id.to_string(); if response.send(()).is_err() { logger::write_warning(format!( - "Failed to send response to KeyKeeperAction::SetImdsRuleId '{}'", - rule_id + "Failed to send response to KeyKeeperAction::SetImdsRuleId '{rule_id}'" )); } } Some(KeyKeeperAction::GetImdsRuleId { response }) => { if let Err(rule_id) = response.send(imds_rule_id.clone()) { logger::write_warning(format!( - "Failed to send response to KeyKeeperAction::GetImdsRuleId '{}'", - rule_id + "Failed to send response to KeyKeeperAction::GetImdsRuleId '{rule_id}'" )); } } Some(KeyKeeperAction::GetHostGARuleId { response }) => { if let Err(rule_id) = response.send(hostga_rule_id.clone()) { logger::write_warning(format!( - "Failed to send response to KeyKeeperAction::GetHostGARuleId '{}'", - rule_id + "Failed to send response to KeyKeeperAction::GetHostGARuleId '{rule_id}'" )); } } @@ -219,8 +212,7 @@ impl KeyKeeperSharedState { hostga_rule_id = rule_id.to_string(); if response.send(()).is_err() { logger::write_warning(format!( - "Failed to send response to KeyKeeperAction::SetHostGARuleId '{}'", - rule_id + "Failed to send response to KeyKeeperAction::SetHostGARuleId '{rule_id}'" )); } } diff --git a/proxy_agent/src/shared_state/provision_wrapper.rs b/proxy_agent/src/shared_state/provision_wrapper.rs index e3cc1696..e9e92609 100644 --- a/proxy_agent/src/shared_state/provision_wrapper.rs +++ b/proxy_agent/src/shared_state/provision_wrapper.rs @@ -81,8 +81,7 @@ impl ProvisionSharedState { provision_state |= state; if let Err(new_state) = response.send(provision_state.clone()) { logger::write_warning(format!( - "Failed to send response to ProvisionAction::UpdateState with new state '{:?}'", - new_state + "Failed to send response to ProvisionAction::UpdateState with new state '{new_state:?}'" )); } } @@ -90,16 +89,14 @@ impl ProvisionSharedState { provision_state &= !state; if let Err(new_state) = response.send(provision_state.clone()) { logger::write_warning(format!( - "Failed to send response to ProvisionAction::ResetState with new state '{:?}'", - new_state + "Failed to send response to ProvisionAction::ResetState with new state '{new_state:?}'" )); } } ProvisionAction::GetState { response } => { if let Err(state) = response.send(provision_state.clone()) { logger::write_warning(format!( - "Failed to send response to ProvisionAction::GetState with state '{:?}'", - state + "Failed to send response to ProvisionAction::GetState with state '{state:?}'" )); } } @@ -114,8 +111,7 @@ impl ProvisionSharedState { response.send(provision_event_log_threads_initialized) { logger::write_warning(format!( - "Failed to send response to ProvisionAction::GetEventLogsThreadsInitialized with initialized '{:?}'", - initialized + "Failed to send response to ProvisionAction::GetEventLogsThreadsInitialized with initialized '{initialized:?}'" )); } } @@ -135,8 +131,7 @@ impl ProvisionSharedState { ProvisionAction::GetProvisionFinished { response } => { if let Err(finished) = response.send(provision_finished_time_tick) { logger::write_warning(format!( - "Failed to send response to ProvisionAction::GetProvisionFinished with finished '{:?}'", - finished + "Failed to send response to ProvisionAction::GetProvisionFinished with finished '{finished:?}'" )); } } diff --git a/proxy_agent/src/shared_state/proxy_server_wrapper.rs b/proxy_agent/src/shared_state/proxy_server_wrapper.rs index ce50c452..e9ef02a2 100644 --- a/proxy_agent/src/shared_state/proxy_server_wrapper.rs +++ b/proxy_agent/src/shared_state/proxy_server_wrapper.rs @@ -55,13 +55,13 @@ impl ProxyServerSharedState { let id = user.logon_id; users.insert(id, user); if response.send(()).is_err() { - logger::write_warning(format!("Failed to send response to ProxyServerAction::AddUser with id '{}'", id)); + logger::write_warning(format!("Failed to send response to ProxyServerAction::AddUser with id '{id}'")); } } ProxyServerAction::GetUser { user_id, response } => { let user = users.get(&user_id).cloned(); if response.send(user).is_err() { - logger::write_warning(format!("Failed to send response to ProxyServerAction::GetUser with id '{}'", user_id)); + logger::write_warning(format!("Failed to send response to ProxyServerAction::GetUser with id '{user_id}'")); } } #[cfg(test)] diff --git a/proxy_agent/src/shared_state/redirector_wrapper.rs b/proxy_agent/src/shared_state/redirector_wrapper.rs index 0f63d9b2..a1e9d2dd 100644 --- a/proxy_agent/src/shared_state/redirector_wrapper.rs +++ b/proxy_agent/src/shared_state/redirector_wrapper.rs @@ -61,16 +61,14 @@ impl RedirectorSharedState { local_port = new_local_port; if response.send(()).is_err() { logger::write_warning(format!( - "Failed to send response to RedirectorAction::SetLocalPort '{}'", - new_local_port + "Failed to send response to RedirectorAction::SetLocalPort '{new_local_port}'" )); } } RedirectorAction::GetLocalPort { response } => { if let Err(port) = response.send(local_port) { logger::write_warning(format!( - "Failed to send response to RedirectorAction::GetLocalPort '{}'", - port + "Failed to send response to RedirectorAction::GetLocalPort '{port}'" )); } } diff --git a/proxy_agent/src/shared_state/telemetry_wrapper.rs b/proxy_agent/src/shared_state/telemetry_wrapper.rs index c18211ac..f386de37 100644 --- a/proxy_agent/src/shared_state/telemetry_wrapper.rs +++ b/proxy_agent/src/shared_state/telemetry_wrapper.rs @@ -46,16 +46,14 @@ impl TelemetrySharedState { vm_meta_data = meta_data.clone(); if response.send(()).is_err() { logger::write_warning(format!( - "Failed to send response to TelemetryAction::SetVmMetaData '{:?}'", - meta_data, + "Failed to send response to TelemetryAction::SetVmMetaData '{meta_data:?}'" )); } } Some(TelemetryAction::GetVmMetaData { response }) => { if let Err(meta_data) = response.send(vm_meta_data.clone()) { logger::write_warning(format!( - "Failed to send response to TelemetryAction::GetVmMetaData '{:?}'", - meta_data, + "Failed to send response to TelemetryAction::GetVmMetaData '{meta_data:?}'" )); } } diff --git a/proxy_agent/src/telemetry/event_reader.rs b/proxy_agent/src/telemetry/event_reader.rs index 5d1dbc2d..06baadc7 100644 --- a/proxy_agent/src/telemetry/event_reader.rs +++ b/proxy_agent/src/telemetry/event_reader.rs @@ -171,7 +171,7 @@ impl EventReader { logger::write("success updated the vm metadata.".to_string()); } Err(e) => { - logger::write_warning(format!("Failed to read vm metadata with error {}.", e)); + logger::write_warning(format!("Failed to read vm metadata with error {e}.")); } } @@ -198,8 +198,7 @@ impl EventReader { .process_events_and_clean(files, wire_server_client, vm_meta_data) .await; let message = format!( - "Telemetry event reader sent {} events from {} files", - event_count, file_count + "Telemetry event reader sent {event_count} events from {file_count} files" ); logger::write(message); } @@ -248,7 +247,7 @@ impl EventReader { .set_vm_meta_data(Some(vm_meta_data.clone())) .await?; - logger::write(format!("Updated VM Metadata: {:?}", vm_meta_data)); + logger::write(format!("Updated VM Metadata: {vm_meta_data:?}")); Ok(()) } @@ -301,9 +300,8 @@ impl EventReader { match serde_json::to_string(&event) { Ok(json) => { logger::write_warning(format!( - "Event data too large. Not sending to wire-server. Event: {}.", - json - )); + "Event data too large. Not sending to wire-server. Event: {json}.", + )); } Err(_) => { logger::write_warning( @@ -345,8 +343,7 @@ impl EventReader { } Err(e) => { logger::write_warning(format!( - "Failed to send telemetry data to host with error: {}", - e + "Failed to send telemetry data to host with error: {e}" )); // wait 15 seconds and retry tokio::time::sleep(Duration::from_secs(15)).await; diff --git a/proxy_agent_extension/src/common.rs b/proxy_agent_extension/src/common.rs index cf50129c..fea6c0b5 100644 --- a/proxy_agent_extension/src/common.rs +++ b/proxy_agent_extension/src/common.rs @@ -61,7 +61,7 @@ pub fn report_heartbeat(heartbeat_file_path: PathBuf, heartbeat_obj: structs::He )); } Err(e) => { - logger::write(format!("Error in creating HeartBeat file: {:?}", e)); + logger::write(format!("Error in creating HeartBeat file: {e:?}")); } } } @@ -69,7 +69,7 @@ pub fn report_heartbeat(heartbeat_file_path: PathBuf, heartbeat_obj: structs::He pub fn get_file_path(status_folder: PathBuf, config_seq_no: &str, file_extension: &str) -> PathBuf { let mut file: PathBuf = status_folder; if let Err(e) = misc_helpers::try_create_folder(&file) { - logger::write(format!("Error in creating folder: {:?}", e)); + logger::write(format!("Error in creating folder: {e:?}")); } file.push(config_seq_no); file.set_extension(file_extension); @@ -107,10 +107,10 @@ pub fn report_status( // TODO: retry if write failed match fs::write(&status_file, root_status) { Ok(_) => { - logger::write(format!("Status file created: {:?}", status_file)); + logger::write(format!("Status file created: {status_file:?}")); } Err(e) => { - logger::write(format!("Error in creating status file: {:?}", e)); + logger::write(format!("Error in creating status file: {e:?}")); } } } @@ -128,12 +128,9 @@ pub fn update_current_seq_no(config_seq_no: &str, exe_path: &Path) -> Result { if seq_no != *config_seq_no { - logger::write(format!( - "updating seq no from {} to {}", - seq_no, config_seq_no - )); + logger::write(format!("updating seq no from {seq_no} to {config_seq_no}")); if let Err(e) = fs::write(¤t_seq_no_stored_file, config_seq_no) { - logger::write(format!("Error in writing seq no to file: {:?}", e)); + logger::write(format!("Error in writing seq no to file: {e:?}")); return Err(Error::Io(e)); } } else { @@ -148,7 +145,7 @@ pub fn update_current_seq_no(config_seq_no: &str, exe_path: &Path) -> Result String { let current_seq_no_stored_file: PathBuf = exe_path.join(constants::CURRENT_SEQ_NO_FILE); match fs::read_to_string(current_seq_no_stored_file) { Ok(seq_no) => { - logger::write(format!("Current seq no: {}", seq_no)); + logger::write(format!("Current seq no: {seq_no}")); seq_no } Err(e) => { - logger::write(format!("Error reading current seq no file: {:?}", e)); + logger::write(format!("Error reading current seq no file: {e:?}")); "".to_string() } } @@ -242,8 +239,7 @@ pub async fn start_event_logger() { // Check if the events folder exists if !event_folder.exists() { logger::write(format!( - "Events folder does not exist: {:?}. Skipping event logger start.", - event_folder + "Events folder does not exist: {event_folder:?}. Skipping event logger start." )); return; } diff --git a/proxy_agent_extension/src/handler_main.rs b/proxy_agent_extension/src/handler_main.rs index afa375a1..57918166 100644 --- a/proxy_agent_extension/src/handler_main.rs +++ b/proxy_agent_extension/src/handler_main.rs @@ -58,7 +58,7 @@ pub async fn program_start(command: ExtensionCommand, config_seq_no: String) { fn check_windows_os_version(version: Version) -> bool { match version.build { Some(build) => { - logger::write(format!("OS build version: {}", build)); + logger::write(format!("OS build version: {build}")); build >= constants::MIN_SUPPORTED_OS_BUILD } None => false, @@ -144,12 +144,11 @@ fn get_update_tag_file() -> PathBuf { fn update_tag_file_exists() -> bool { let update_tag_file = get_update_tag_file(); if update_tag_file.exists() { - logger::write(format!("update tag file exists: {:?}", update_tag_file)); + logger::write(format!("update tag file exists: {update_tag_file:?}")); true } else { logger::write(format!( - "update tag file does not exist: {:?}", - update_tag_file + "update tag file does not exist: {update_tag_file:?}" )); false } @@ -165,12 +164,12 @@ fn get_exe_parent() -> PathBuf { Path::new("") } }; - logger::write(format!("exe parent: {:?}", exe_parent)); + logger::write(format!("exe parent: {exe_parent:?}")); exe_parent.to_path_buf() } async fn handle_command(command: ExtensionCommand, config_seq_no: String) { - logger::write(format!("entering handle command: {:?}", command)); + logger::write(format!("entering handle command: {command:?}")); let status_folder = HANDLER_ENVIRONMENT.statusFolder.to_string(); let status_folder_path: PathBuf = PathBuf::from(&status_folder); match command { @@ -200,28 +199,26 @@ fn uninstall_handler() { match str::from_utf8(&output.stdout) { Ok(output_string) => { logger::write(format!( - "uninstalling GuestProxyAgent, output: {}", - output_string + "uninstalling GuestProxyAgent, output: {output_string}" )); } Err(e) => { - logger::write(format!("error in uninstalling GuestProxyAgent: {:?}", e)); + logger::write(format!("error in uninstalling GuestProxyAgent: {e:?}")); } } match str::from_utf8(&output.stderr) { Ok(output_string) => { logger::write(format!( - "output stderr for uninstall GuestProxyAgent: {}", - output_string + "output stderr for uninstall GuestProxyAgent: {output_string}" )); } Err(e) => { - logger::write(format!("error in uninstalling GuestProxyAgent: {:?}", e)); + logger::write(format!("error in uninstalling GuestProxyAgent: {e:?}")); } } } Err(e) => { - logger::write(format!("error in uninstalling GuestProxyAgent: {:?}", e)); + logger::write(format!("error in uninstalling GuestProxyAgent: {e:?}")); } } } @@ -240,7 +237,7 @@ async fn enable_handler(status_folder: PathBuf, config_seq_no: String) { } } Err(e) => { - logger::write(format!("error in updating current seq no: {:?}", e)); + logger::write(format!("error in updating current seq no: {e:?}")); process::exit(constants::EXIT_CODE_WRITE_CURRENT_SEQ_NO_ERROR); } } @@ -273,13 +270,12 @@ async fn enable_handler(status_folder: PathBuf, config_seq_no: String) { Ok(child) => { let pid = child.id(); logger::write(format!( - "ProxyAgentExt started with pid: {}, do not start new one.", - pid + "ProxyAgentExt started with pid: {pid}, do not start new one." )); break; } Err(e) => { - logger::write(format!("error in starting ProxyAgentExt: {:?}", e)); + logger::write(format!("error in starting ProxyAgentExt: {e:?}")); } } } @@ -294,7 +290,7 @@ async fn enable_handler(status_folder: PathBuf, config_seq_no: String) { "update tag file removed: {:?}", update_tag_file.to_path_buf() )), - Err(e) => logger::write(format!("error in removing update tag file: {:?}", e)), + Err(e) => logger::write(format!("error in removing update tag file: {e:?}")), } } } @@ -312,7 +308,7 @@ fn get_linux_extension_long_running_process() -> Option { for p in system.processes_by_exact_name(constants::EXTENSION_PROCESS_NAME) { let cmd = p.cmd(); - logger::write(format!("cmd: {:?}", cmd)); + logger::write(format!("cmd: {cmd:?}")); if cmd.len() == 1 { logger::write(format!("ProxyAgentExt running with pid: {}", p.pid())); return Some(p.pid().as_u32() as i32); @@ -334,10 +330,10 @@ async fn disable_handler() { let p = NixPid::from_raw(pid); match kill(p, SIGKILL) { Ok(_) => { - logger::write(format!("ProxyAgentExt process with pid: {} killed", pid)); + logger::write(format!("ProxyAgentExt process with pid: {pid} killed")); } Err(e) => { - logger::write(format!("error in killing ProxyAgentExt process: {:?}", e)); + logger::write(format!("error in killing ProxyAgentExt process: {e:?}")); } } } @@ -357,14 +353,14 @@ fn reset_handler() { "update tag file removed: {:?}", update_tag_file.to_path_buf() )), - Err(e) => logger::write(format!("error in removing update tag file: {:?}", e)), + Err(e) => logger::write(format!("error in removing update tag file: {e:?}")), } match fs::remove_file(&seq_no_file) { Ok(_) => logger::write(format!( "seq no file removed: {:?}", seq_no_file.to_path_buf() )), - Err(e) => logger::write(format!("error in removing seq no file: {:?}", e)), + Err(e) => logger::write(format!("error in removing seq no file: {e:?}")), } } @@ -374,7 +370,7 @@ async fn update_handler() { let version = match std::env::var("VERSION") { Ok(ver) => ver, Err(e) => { - logger::write(format!("error in getting VERSION from env::var: {:?}", e)); + logger::write(format!("error in getting VERSION from env::var: {e:?}")); process::exit(constants::EXIT_CODE_UPDATE_TO_VERSION_ENV_VAR_NOTFOUND); } }; @@ -403,7 +399,7 @@ async fn update_handler() { break; } Err(e) => { - logger::write(format!("error in creating update tag file: {:?}", e)); + logger::write(format!("error in creating update tag file: {e:?}")); } } } diff --git a/proxy_agent_extension/src/logger.rs b/proxy_agent_extension/src/logger.rs index 70c71c70..f12cec8e 100644 --- a/proxy_agent_extension/src/logger.rs +++ b/proxy_agent_extension/src/logger.rs @@ -23,7 +23,7 @@ pub fn init_logger(log_folder: String, log_name: &str) { if !LOGGER_KEY.initialized() { if let Err(e) = LOGGER_KEY.set(log_name.to_string()) { - eprintln!("Failed to set logger key: {}", e); + eprintln!("Failed to set logger key: {e}"); }; } } diff --git a/proxy_agent_extension/src/main.rs b/proxy_agent_extension/src/main.rs index d51bc835..0093e49b 100644 --- a/proxy_agent_extension/src/main.rs +++ b/proxy_agent_extension/src/main.rs @@ -86,7 +86,7 @@ async fn main() { #[cfg(windows)] { if let Err(e) = service_dispatcher::start(constants::PLUGIN_NAME, ffi_service_main) { - logger::write(format!("Failed to start the service: {}", e)); + logger::write(format!("Failed to start the service: {e}")); } } #[cfg(not(windows))] @@ -104,7 +104,7 @@ fn proxy_agent_extension_windows_service_main(args: Vec) { .expect("You must provide the Tokio runtime handle before this function is called"); handle.block_on(async { if let Err(e) = service_main::windows_main::run_service(args).await { - logger::write(format!("Failed to start the service: {}", e)); + logger::write(format!("Failed to start the service: {e}")); } }); } diff --git a/proxy_agent_extension/src/service_main.rs b/proxy_agent_extension/src/service_main.rs index 7bfe1763..2a28c9cb 100644 --- a/proxy_agent_extension/src/service_main.rs +++ b/proxy_agent_extension/src/service_main.rs @@ -99,8 +99,7 @@ async fn monitor_thread() { telemetry::event_logger::write_event( LoggerLevel::Info, format!( - "Current seq_no: {} does not match cached seq no {}", - current_seq_no, cache_seq_no + "Current seq_no: {current_seq_no} does not match cached seq no {cache_seq_no}" ), "monitor_thread", "service_main", @@ -125,9 +124,8 @@ async fn monitor_thread() { // Call setup tool to install or update proxy agent service telemetry::event_logger::write_event( LoggerLevel::Info, - format!("Version mismatch between file versions. ProxyAgentService File Version: {}, ProxyAgent in Extension File Version: {}", - proxyagent_service_file_version, - proxyagent_file_version_in_extension), + format!("Version mismatch between file versions. ProxyAgentService File Version: {proxyagent_service_file_version}, ProxyAgent in Extension File Version: {proxyagent_file_version_in_extension}" + ), "monitor_thread", "service_main", logger_key, @@ -301,7 +299,7 @@ fn backup_proxyagent(setup_tool: &String) { Err(e) => { telemetry::event_logger::write_event( LoggerLevel::Info, - format!("Error in running Backup Proxy Agent command: {}", e), + format!("Error in running Backup Proxy Agent command: {e}"), "backup_proxyagent", "service_main", &logger::get_logger_key(), @@ -345,8 +343,7 @@ fn report_proxy_agent_aggregate_status( ); } Err(e) => { - let error_message = - format!("Error in reading proxy agent aggregate status file: {}", e); + let error_message = format!("Error in reading proxy agent aggregate status file: {e}"); write_state_event( constants::STATE_KEY_READ_PROXY_AGENT_STATUS_FILE, constants::ERROR_STATUS, @@ -409,7 +406,7 @@ fn extension_substatus( proxy_agent_aggregate_status_obj.version.to_string(); if proxy_agent_aggregate_status_file_version != *proxyagent_file_version_in_extension { status.status = status_state_obj.update_state(false); - let version_mismatch_message = format!("Proxy agent aggregate status file version {} does not match proxy agent file version in extension {}", proxy_agent_aggregate_status_file_version, proxyagent_file_version_in_extension); + let version_mismatch_message = format!("Proxy agent aggregate status file version {proxy_agent_aggregate_status_file_version} does not match proxy agent file version in extension {proxyagent_file_version_in_extension}"); write_state_event( constants::STATE_KEY_FILE_VERSION, constants::ERROR_STATUS, @@ -459,7 +456,7 @@ fn extension_substatus( Ok(proxy_agent_aggregate_status) => proxy_agent_aggregate_status, Err(e) => { let error_message = - format!("Error in serializing proxy agent aggregate status: {}", e); + format!("Error in serializing proxy agent aggregate status: {e}"); logger::write(error_message.to_string()); error_message } @@ -482,8 +479,7 @@ fn extension_substatus( } Err(e) => { let error_message = format!( - "Error in serializing proxy agent aggregate connection status: {}", - e + "Error in serializing proxy agent aggregate connection status: {e}" ); logger::write(error_message.to_string()); substatus_proxy_agent_connection_message = error_message; @@ -511,8 +507,7 @@ fn extension_substatus( } Err(e) => { let error_message = format!( - "Error in serializing proxy agent aggregate failed auth status: {}", - e + "Error in serializing proxy agent aggregate failed auth status: {e}" ); logger::write(error_message.to_string()); substatus_failed_auth_message = error_message; @@ -631,7 +626,7 @@ fn restore_purge_proxyagent(status: &mut StatusObj) -> bool { Err(e) => { telemetry::event_logger::write_event( LoggerLevel::Info, - format!("Error in running Restore Proxy Agent command: {}", e), + format!("Error in running Restore Proxy Agent command: {e}"), "restore_purge_proxyagent", "service_main", &logger::get_logger_key(), @@ -663,7 +658,7 @@ fn restore_purge_proxyagent(status: &mut StatusObj) -> bool { Err(e) => { telemetry::event_logger::write_event( LoggerLevel::Info, - format!("Error in running Purge Proxy Agent command: {}", e), + format!("Error in running Purge Proxy Agent command: {e}"), "restore_purge_proxyagent", "service_main", &logger::get_logger_key(), @@ -724,7 +719,7 @@ fn report_proxy_agent_service_status( Err(e) => { telemetry::event_logger::write_event( LoggerLevel::Info, - format!("Error in running Update Proxy Agent command: {}", e), + format!("Error in running Update Proxy Agent command: {e}"), "report_proxy_agent_service_status", "service_main", &logger::get_logger_key(), @@ -734,7 +729,7 @@ fn report_proxy_agent_service_status( status.code = constants::STATUS_CODE_NOT_OK; status.status = status_state_obj.update_state(false); status.formattedMessage.message = - format!("Update Proxy Agent command failed with error: {}", e); + format!("Update Proxy Agent command failed with error: {e}"); status.substatus = Default::default(); common::report_status(status_folder, seq_no, status); } diff --git a/proxy_agent_extension/src/service_main/windows_main.rs b/proxy_agent_extension/src/service_main/windows_main.rs index 9441eb6a..a793cf72 100644 --- a/proxy_agent_extension/src/service_main/windows_main.rs +++ b/proxy_agent_extension/src/service_main/windows_main.rs @@ -36,7 +36,7 @@ pub async fn run_service(_args: Vec) -> Result<()> { process_id: None, }; if let Err(e) = status_handle.set_service_status(stop_state) { - logger::write(format!("Failed to set service status to Stopped: {}", e)); + logger::write(format!("Failed to set service status to Stopped: {e}")); } } else { // workaround to stop the service by exiting the process diff --git a/proxy_agent_setup/src/args.rs b/proxy_agent_setup/src/args.rs index 8ab2a66c..16cdfcce 100644 --- a/proxy_agent_setup/src/args.rs +++ b/proxy_agent_setup/src/args.rs @@ -48,9 +48,9 @@ impl Display for Command { match self { Command::Backup => write!(f, "backup"), Command::Restore { delete_backup } => { - write!(f, "restore delete_backup={}", delete_backup) + write!(f, "restore delete_backup={delete_backup}") } - Command::Uninstall { uninstall_mode } => write!(f, "uninstall {}", uninstall_mode), + Command::Uninstall { uninstall_mode } => write!(f, "uninstall {uninstall_mode}"), Command::Install => write!(f, "install"), Command::Purge => write!(f, "purge"), } diff --git a/proxy_agent_setup/src/linux.rs b/proxy_agent_setup/src/linux.rs index ea71de3d..70921167 100644 --- a/proxy_agent_setup/src/linux.rs +++ b/proxy_agent_setup/src/linux.rs @@ -17,7 +17,7 @@ pub fn setup_service(service_name: &str, service_file_dir: PathBuf) -> Result Result { - let service_config_name = format!("{}.service", service_name); + let service_config_name = format!("{service_name}.service"); let src_config_file_path = service_file_dir.join(&service_config_name); let dst_config_file_path = PathBuf::from(proxy_agent_shared::linux::SERVICE_CONFIG_FOLDER_PATH) .join(&service_config_name); @@ -33,14 +33,12 @@ fn backup_service_config_file(backup_folder: PathBuf) { ) { Ok(_) => { logger::write(format!( - "Copied service config file to {:?}", - backup_service_file + "Copied service config file to {backup_service_file:?}" )); } Err(e) => { logger::write(format!( - "Failed to copy service config file to {:?}, error: {:?}", - backup_service_file, e + "Failed to copy service config file to {backup_service_file:?}, error: {e:?}" )); } } @@ -49,17 +47,16 @@ fn backup_service_config_file(backup_folder: PathBuf) { fn copy_file(src_file: PathBuf, dst_file: PathBuf) { if let Some(p) = dst_file.parent() { if let Err(e) = misc_helpers::try_create_folder(p) { - logger::write(format!("Failed to create folder {:?}, error: {:?}", p, e)); + logger::write(format!("Failed to create folder {p:?}, error: {e:?}")); } } match fs::copy(&src_file, &dst_file) { Ok(_) => { - logger::write(format!("Copied file {:?} to {:?}", src_file, dst_file)); + logger::write(format!("Copied file {src_file:?} to {dst_file:?}")); } Err(e) => { logger::write(format!( - "Failed to copy file {:?} to {:?}, error: {:?}", - src_file, dst_file, e + "Failed to copy file {src_file:?} to {dst_file:?}, error: {e:?}" )); } } @@ -68,12 +65,11 @@ fn copy_file(src_file: PathBuf, dst_file: PathBuf) { fn delete_file(file_to_be_delete: PathBuf) { match fs::remove_file(&file_to_be_delete) { Ok(_) => { - logger::write(format!("Deleted file {:?}", file_to_be_delete)); + logger::write(format!("Deleted file {file_to_be_delete:?}")); } Err(e) => { logger::write(format!( - "Failed to delete file {:?}, error: {:?}", - file_to_be_delete, e + "Failed to delete file {file_to_be_delete:?}, error: {e:?}" )); } } diff --git a/proxy_agent_setup/src/logger.rs b/proxy_agent_setup/src/logger.rs index 11b7404c..7c870ec6 100644 --- a/proxy_agent_setup/src/logger.rs +++ b/proxy_agent_setup/src/logger.rs @@ -19,6 +19,6 @@ fn force_init_logger(log_folder: PathBuf, log_name: &str) { } pub fn write(message: String) { - println!("{}", message); + println!("{message}"); logger_manager::log(LOGGER_KEY.to_string(), LoggerLevel::Info, message); } diff --git a/proxy_agent_setup/src/main.rs b/proxy_agent_setup/src/main.rs index 02707190..17cdac12 100644 --- a/proxy_agent_setup/src/main.rs +++ b/proxy_agent_setup/src/main.rs @@ -127,8 +127,7 @@ fn copy_proxy_agent_files(src_folder: PathBuf, dst_folder: PathBuf) { Ok(_) => {} Err(e) => { logger::write(format!( - "Failed to create folder {:?}, error: {:?}", - dst_folder, e + "Failed to create folder {dst_folder:?}, error: {e:?}" )); } } @@ -139,12 +138,11 @@ fn copy_proxy_agent_files(src_folder: PathBuf, dst_folder: PathBuf) { let dst_file = dst_folder.join(&file_name); match fs::copy(&file, &dst_file) { Ok(_) => { - logger::write(format!("Copied {:?} to {:?}", file, dst_file)); + logger::write(format!("Copied {file:?} to {dst_file:?}")); } Err(e) => { logger::write(format!( - "Failed to copy {:?} to {:?}, error: {:?}", - file, dst_file, e + "Failed to copy {file:?} to {dst_file:?}, error: {e:?}" )); } } @@ -152,8 +150,7 @@ fn copy_proxy_agent_files(src_folder: PathBuf, dst_folder: PathBuf) { } Err(e) => { logger::write(format!( - "Failed to get files from {:?}, error: {:?}", - src_folder, e + "Failed to get files from {src_folder:?}, error: {e:?}" )); } } @@ -162,12 +159,11 @@ fn copy_proxy_agent_files(src_folder: PathBuf, dst_folder: PathBuf) { async fn stop_service() { match service::stop_service(SERVICE_NAME).await { Ok(_) => { - logger::write(format!("Stopped service {} successfully", SERVICE_NAME)); + logger::write(format!("Stopped service {SERVICE_NAME} successfully")); } Err(e) => { logger::write(format!( - "Stopped service {} failed, error: {:?}", - SERVICE_NAME, e + "Stopped service {SERVICE_NAME} failed, error: {e:?}" )); } } @@ -188,13 +184,10 @@ async fn setup_service(proxy_agent_target_folder: PathBuf, _service_config_folde { match linux::setup_service(SERVICE_NAME, _service_config_folder_path) { Ok(_) => { - logger::write(format!("Setup service {} successfully", SERVICE_NAME)); + logger::write(format!("Setup service {SERVICE_NAME} successfully")); } Err(e) => { - logger::write(format!( - "Setup service {} failed, error: {:?}", - SERVICE_NAME, e - )); + logger::write(format!("Setup service {SERVICE_NAME} failed, error: {e:?}")); process::exit(1); } } @@ -207,12 +200,11 @@ async fn setup_service(proxy_agent_target_folder: PathBuf, _service_config_folde setup::proxy_agent_exe_path(&proxy_agent_target_folder), ) { Ok(_) => { - logger::write(format!("Install service {} successfully", SERVICE_NAME)); + logger::write(format!("Install service {SERVICE_NAME} successfully")); } Err(e) => { logger::write(format!( - "Install service {} failed, error: {:?}", - SERVICE_NAME, e + "Install service {SERVICE_NAME} failed, error: {e:?}", )); process::exit(1); } @@ -243,8 +235,7 @@ async fn setup_service(proxy_agent_target_folder: PathBuf, _service_config_folde } Err(e) => { logger::write(format!( - "ebpf_setup: failed to invoke script file '{}', error: '{:?}'.", - setup_script_file_str, e + "ebpf_setup: failed to invoke script file '{setup_script_file_str}', error: '{e:?}'." )); } } @@ -253,25 +244,21 @@ async fn setup_service(proxy_agent_target_folder: PathBuf, _service_config_folde match service::start_service(SERVICE_NAME, 5, Duration::from_secs(15)).await { Ok(_) => { - logger::write(format!("Service {} start successfully", SERVICE_NAME)); + logger::write(format!("Service {SERVICE_NAME} start successfully")); } Err(e) => { - logger::write(format!( - "Service {} start failed, error: {:?}", - SERVICE_NAME, e - )); + logger::write(format!("Service {SERVICE_NAME} start failed, error: {e:?}")); process::exit(1); } } - logger::write(format!("Service {} start successfully", SERVICE_NAME)); + logger::write(format!("Service {SERVICE_NAME} start successfully")); } fn check_backup_exists() -> bool { let proxy_agent_exe = setup::proxy_agent_exe_path(&backup::proxy_agent_backup_package_folder()); if !proxy_agent_exe.exists() { logger::write(format!( - "GuestProxyAgent ({:?}) does not exists.", - proxy_agent_exe + "GuestProxyAgent ({proxy_agent_exe:?}) does not exists." )); return false; } @@ -284,12 +271,11 @@ async fn uninstall_service() -> PathBuf { match service::stop_and_delete_service(SERVICE_NAME).await { Ok(_) => { - logger::write(format!("Uninstall service {} successfully", SERVICE_NAME)); + logger::write(format!("Uninstall service {SERVICE_NAME} successfully")); } Err(e) => { logger::write(format!( - "Uninstall service {} failed, error: {:?}", - SERVICE_NAME, e + "Uninstall service {SERVICE_NAME} failed, error: {e:?}" )); process::exit(1); } @@ -312,12 +298,11 @@ fn delete_package(_proxy_agent_running_folder: PathBuf) { fn delete_folder(folder_to_be_delete: PathBuf) { match fs::remove_dir_all(&folder_to_be_delete) { Ok(_) => { - logger::write(format!("Deleted folder {:?}", folder_to_be_delete)); + logger::write(format!("Deleted folder {folder_to_be_delete:?}")); } Err(e) => { logger::write(format!( - "Failed to delete folder {:?}, error: {:?}", - folder_to_be_delete, e + "Failed to delete folder {folder_to_be_delete:?}, error: {e:?}" )); } } diff --git a/proxy_agent_setup/src/running.rs b/proxy_agent_setup/src/running.rs index ee0ca188..93905cb8 100644 --- a/proxy_agent_setup/src/running.rs +++ b/proxy_agent_setup/src/running.rs @@ -41,18 +41,15 @@ pub fn proxy_agent_version_target_folder(proxy_agent_exe: &Path) -> PathBuf { Ok(v) => v, Err(e) => { // This should not happen, if failed to get version, we should not proceed - logger::write(format!( - "Failed to get proxy agent version with error: {}", - e - )); - panic!("Failed to get proxy agent version with error: {}", e); + logger::write(format!("Failed to get proxy agent version with error: {e}")); + panic!("Failed to get proxy agent version with error: {e}"); } }; logger::write(format!("Proxy agent version: {}", &proxy_agent_version)); #[cfg(windows)] { let path = proxy_agent_parent_folder(); - path.join(format!("Package_{}", proxy_agent_version)) + path.join(format!("Package_{proxy_agent_version}")) } #[cfg(not(windows))] { diff --git a/proxy_agent_shared/src/etw/application.rs b/proxy_agent_shared/src/etw/application.rs index 22221e7d..364e4ff7 100644 --- a/proxy_agent_shared/src/etw/application.rs +++ b/proxy_agent_shared/src/etw/application.rs @@ -58,10 +58,8 @@ impl ApplicationEventWritter { // register event source in the Windows Registry // `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Application\{source_name}` - let key_name = format!( - r"SYSTEM\CurrentControlSet\Services\EventLog\Application\{}", - source_name - ); + let key_name = + format!(r"SYSTEM\CurrentControlSet\Services\EventLog\Application\{source_name}"); let value = crate::misc_helpers::resolve_env_variables( r"%SystemRoot%\Microsoft.NET\Framework64\v4.0.30319\EventLogMessages.dll", )?; @@ -326,6 +324,10 @@ mod tests { if event.system.provider.name == Some(self.source_name.clone()) { // Check if the event is within the specified time range let time_created = event.system.time_created.system_time.clone(); + println!( + "Event '{}' Time Created: {:?}", + self.source_name, time_created + ); if let Some(start_time) = self.start_time { match time_created.clone() { Some(time) => { @@ -380,7 +382,9 @@ mod tests { use super::ApplicationEventWritter; use crate::logger::LoggerLevel; - let start_time = chrono::Utc::now(); + // According to the test log, it indicates that Windows Container may have few milliseconds difference against its current host time. + // Therefore, we set the start time to 1 second before the current time. + let start_time = chrono::Utc::now() - chrono::Duration::seconds(1); let end_time = start_time + chrono::Duration::seconds(60); let source_name = "GuestProxyAgent_TestApplication"; diff --git a/proxy_agent_shared/src/linux.rs b/proxy_agent_shared/src/linux.rs index ac75187e..138d8782 100644 --- a/proxy_agent_shared/src/linux.rs +++ b/proxy_agent_shared/src/linux.rs @@ -47,8 +47,7 @@ pub fn get_os_version() -> String { } Err(e) => { let message = format!( - "Failed to read os-release file in get_os_version(): {} with error: {}", - OS_RELEASE_PATH, e + "Failed to read os-release file in get_os_version(): {OS_RELEASE_PATH} with error: {e}", ); logger_manager::write_warn(message); return "Unknown".to_string(); @@ -78,8 +77,7 @@ pub fn get_os_type() -> String { } Err(e) => { let message = format!( - "Failed to read os-release file in get_os_type(): {} with error: {}", - OS_RELEASE_PATH, e + "Failed to read os-release file in get_os_type(): {OS_RELEASE_PATH} with error: {e}", ); logger_manager::write_warn(message); return "Unknown".to_string(); diff --git a/proxy_agent_shared/src/logger/logger_manager.rs b/proxy_agent_shared/src/logger/logger_manager.rs index 61dff8bb..a989a4a6 100644 --- a/proxy_agent_shared/src/logger/logger_manager.rs +++ b/proxy_agent_shared/src/logger/logger_manager.rs @@ -40,7 +40,7 @@ pub fn set_loggers( if let Err(e) = MAX_LOG_LEVEL.set(max_log_level) { write_system_log( LoggerLevel::Error, - format!("Failed to set logger level: {}", e), + format!("Failed to set logger level: {e}"), ); } } @@ -55,12 +55,12 @@ pub fn set_loggers( // set the loggers once if let Err(e) = LOGGERS.set(loggers) { - write_system_log(LoggerLevel::Error, format!("Failed to set loggers: {}", e)); + write_system_log(LoggerLevel::Error, format!("Failed to set loggers: {e}")); }; if let Err(e) = DEFAULT_LOGGER_KEY.set(default_logger_key) { write_system_log( LoggerLevel::Error, - format!("Failed to set default logger key: {}", e), + format!("Failed to set default logger key: {e}"), ); } } @@ -74,14 +74,14 @@ pub fn set_system_logger(max_log_level: LoggerLevel, _service_name: &str) { if let Err(e) = WINDOWS_ETW_APPLICATION_LOGGER.set(logger) { write_system_log( LoggerLevel::Error, - format!("Failed to set Windows Application ETW logger: {}", e), + format!("Failed to set Windows Application ETW logger: {e}"), ); } } Err(e) => { write_system_log( LoggerLevel::Error, - format!("Failed to create Windows Application ETW logger: {}", e), + format!("Failed to create Windows Application ETW logger: {e}"), ); } } @@ -92,7 +92,7 @@ pub fn set_system_logger(max_log_level: LoggerLevel, _service_name: &str) { if let Err(e) = MAX_SYSTEM_LOG_LEVEL.set(max_log_level) { write_system_log( LoggerLevel::Error, - format!("Failed to set system logger level: {}", e), + format!("Failed to set system logger level: {e}"), ); } } @@ -128,7 +128,7 @@ fn internal_log(logger_key: Option, log_level: LoggerLevel, message: Str if let Some(logger) = get_logger(logger_key) { if let Err(e) = logger.write(log_level, message) { - eprintln!("Error writing to log: {}", e); + eprintln!("Error writing to log: {e}"); } } } @@ -156,7 +156,7 @@ pub fn write_err(message: String) { pub fn write_many(logger_key: Option, messages: Vec) { if let Some(logger) = get_logger(logger_key) { if let Err(e) = logger.write_many(messages) { - eprintln!("Error writing to log: {}", e); + eprintln!("Error writing to log: {e}"); } } } @@ -168,9 +168,9 @@ fn write_system_log(log_level: LoggerLevel, message: String) { // Linux automatically captures console logs to syslog. if log_level == LoggerLevel::Error { - eprintln!("{}", message); + eprintln!("{message}",); } else { - println!("{}", message); + println!("{message}",); } #[cfg(windows)] diff --git a/proxy_agent_shared/src/misc_helpers.rs b/proxy_agent_shared/src/misc_helpers.rs index fd304656..149b2188 100644 --- a/proxy_agent_shared/src/misc_helpers.rs +++ b/proxy_agent_shared/src/misc_helpers.rs @@ -268,13 +268,13 @@ pub fn get_proxy_agent_version(proxy_agent_exe: &Path) -> Result { if !proxy_agent_exe.exists() { return Err(Error::Io(std::io::Error::new( std::io::ErrorKind::NotFound, - format!("File '{}' does not found", proxy_agent_exe_str), + format!("File '{proxy_agent_exe_str}' does not found"), ))); } if !proxy_agent_exe.is_file() { return Err(Error::Io(std::io::Error::new( std::io::ErrorKind::InvalidInput, - format!("'{}' is not a file", proxy_agent_exe_str), + format!("'{proxy_agent_exe_str}' is not a file"), ))); } diff --git a/proxy_agent_shared/src/service.rs b/proxy_agent_shared/src/service.rs index 0cd0f1b1..5ca4b892 100644 --- a/proxy_agent_shared/src/service.rs +++ b/proxy_agent_shared/src/service.rs @@ -99,18 +99,14 @@ pub fn query_service_executable_path(_service_name: &str) -> PathBuf { { match windows_service::query_service_config(_service_name) { Ok(service_config) => { - logger_manager::write_info(format!( - "Service {} successfully queried", - _service_name - )); + logger_manager::write_info( + format!("Service {_service_name} successfully queried",), + ); service_config.executable_path.to_path_buf() } Err(e) => { - logger_manager::write_info(format!( - "Service {} query failed: {}", - _service_name, e - )); - eprintln!("Service {} query failed: {}", _service_name, e); + logger_manager::write_info(format!("Service {_service_name} query failed: {e}",)); + eprintln!("Service {_service_name} query failed: {e}"); PathBuf::new() } } @@ -129,14 +125,13 @@ pub fn check_service_installed(_service_name: &str) -> (bool, String) { match windows_service::query_service_config(_service_name) { Ok(_service_config) => { message = format!( - "check_service_installed: Ebpf Driver: {} successfully queried.", - _service_name + "check_service_installed: Ebpf Driver: {_service_name} successfully queried.", ); (true, message) } Err(e) => { message = format!( - "check_service_installed: Ebpf Driver: {} unsuccessfully queried with error: {}.", _service_name, e + "check_service_installed: Ebpf Driver: {_service_name} unsuccessfully queried with error: {e}" ); (false, message) } diff --git a/proxy_agent_shared/src/service/linux_service.rs b/proxy_agent_shared/src/service/linux_service.rs index a27144b1..84efd3e8 100644 --- a/proxy_agent_shared/src/service/linux_service.rs +++ b/proxy_agent_shared/src/service/linux_service.rs @@ -79,7 +79,7 @@ fn enable_service(service_name: &str) -> Result<()> { fn delete_service_config_file(service_name: &str) -> Result<()> { let config_file_path = - PathBuf::from(linux::SERVICE_CONFIG_FOLDER_PATH).join(format!("{}.service", service_name)); + PathBuf::from(linux::SERVICE_CONFIG_FOLDER_PATH).join(format!("{service_name}.service")); match fs::remove_file(&config_file_path) { Ok(_) => { reload_systemd_daemon()?; diff --git a/proxy_agent_shared/src/service/windows_service.rs b/proxy_agent_shared/src/service/windows_service.rs index fcdef742..975e7803 100644 --- a/proxy_agent_shared/src/service/windows_service.rs +++ b/proxy_agent_shared/src/service/windows_service.rs @@ -21,14 +21,13 @@ pub async fn start_service_with_retry( duration: std::time::Duration, ) -> Result<()> { for i in 0..retry_count { - logger_manager::write_info(format!("Starting service {} attempt {}", service_name, i)); + logger_manager::write_info(format!("Starting service '{service_name}' attempt {i}")); match start_service_once(service_name).await { Ok(service) => { if service.current_state == ServiceState::Running { logger_manager::write_info(format!( - "Service {} is at Running state", - service_name + "Service '{service_name}' is at Running state" )); return Ok(()); } @@ -43,19 +42,13 @@ pub async fn start_service_with_retry( } Err(e) => { logger_manager::write_warn( - format!( - "Extension service {} start failed with error: {}", - service_name, e - ) - .to_string(), + format!("Extension service '{service_name}' start failed with error: {e}") + .to_string(), ); if (i + 1) == retry_count { logger_manager::write_err( - format!( - "Service {} failed to start after {} attempts", - service_name, i - ) - .to_string(), + format!("Service '{service_name}' failed to start after {i} attempts") + .to_string(), ); return Err(e); } @@ -70,10 +63,10 @@ async fn start_service_once(service_name: &str) -> Result { // Start service if it already isn't running let service = query_service_status(service_name)?; if service.current_state == ServiceState::Running { - logger_manager::write_info(format!("Service '{}' is already running", service_name)); + logger_manager::write_info(format!("Service '{service_name}' is already running")); Ok(service) } else { - logger_manager::write_info(format!("Starting service '{}'", service_name)); + logger_manager::write_info(format!("Starting service '{service_name}'")); let service_manager: ServiceManager = ServiceManager::local_computer(None::<&str>, ServiceManagerAccess::CONNECT) .map_err(|e| Error::WindowsService(e, std::io::Error::last_os_error()))?; @@ -122,8 +115,7 @@ pub async fn stop_service(service_name: &str) -> Result { } Err(e) => { logger_manager::write_info(format!( - "Stopped service {} failed, error: {:?}", - service_name, e + "Stopped service {service_name} failed, error: {e:?}" )); } } diff --git a/proxy_agent_shared/src/telemetry/event_logger.rs b/proxy_agent_shared/src/telemetry/event_logger.rs index 3af4d8ef..6d7ea3a9 100644 --- a/proxy_agent_shared/src/telemetry/event_logger.rs +++ b/proxy_agent_shared/src/telemetry/event_logger.rs @@ -33,7 +33,7 @@ pub async fn start( logger_manager::write_log(Level::Info, message.to_string()); if let Err(e) = misc_helpers::try_create_folder(&event_dir) { - let message = format!("Failed to create event folder with error: {}", e); + let message = format!("Failed to create event folder with error: {e}"); set_status_fn(message.to_string()); } @@ -75,9 +75,8 @@ pub async fn start( match misc_helpers::get_files(&event_dir) { Ok(files) => { if files.len() >= max_event_file_count { - logger_manager::write_log( Level::Warn,format!( - "Event files exceed the max file count {}, drop and skip the write to disk.", - max_event_file_count + logger_manager::write_log(Level::Warn, format!( + "Event files exceed the max file count {max_event_file_count}, drop and skip the write to disk." )); continue; } @@ -85,7 +84,7 @@ pub async fn start( Err(e) => { logger_manager::write_log( Level::Warn, - format!("Failed to get event files with error: {}", e), + format!("Failed to get event files with error: {e}"), ); } } @@ -150,7 +149,7 @@ pub fn write_event_only(level: Level, message: String, method_name: &str, module Err(e) => { logger_manager::write_log( Level::Warn, - format!("Failed to push event to the queue with error: {}", e), + format!("Failed to push event to the queue with error: {e}"), ); } }; diff --git a/proxy_agent_shared/src/version.rs b/proxy_agent_shared/src/version.rs index 2d543116..f01c5388 100644 --- a/proxy_agent_shared/src/version.rs +++ b/proxy_agent_shared/src/version.rs @@ -85,14 +85,14 @@ impl Display for Version { let mut ver = format!("{}.{}", self.major, self.minor); if let Some(b) = self.build { - ver = format!("{}.{}", ver, b); + ver = format!("{ver}.{b}"); if let Some(r) = self.revision { - ver = format!("{}.{}", ver, r); + ver = format!("{ver}.{r}"); } } - write!(f, "{}", ver) + write!(f, "{ver}") } } diff --git a/proxy_agent_shared/src/windows.rs b/proxy_agent_shared/src/windows.rs index aa35ede6..83eb9171 100644 --- a/proxy_agent_shared/src/windows.rs +++ b/proxy_agent_shared/src/windows.rs @@ -26,11 +26,11 @@ fn read_reg_int(key_name: &str, value_name: &str, default_value: Option) -> Ok(key) => match key.get_value(value_name) { Ok(val) => return Some(val), Err(e) => { - print!("{}", e); + print!("{e}"); } }, Err(e) => { - print!("{}", e); + print!("{e}"); } } @@ -87,7 +87,7 @@ pub fn get_os_version() -> Result { Ok(u) => major = u, Err(_) => { return Err(Error::ParseVersion(ParseVersionErrorType::MajorBuild( - format!("{} ({})", major_str, CURRENT_MAJOR_VERSION_NUMBER_STRING), + format!("{major_str} ({CURRENT_MAJOR_VERSION_NUMBER_STRING})"), ))); } } @@ -111,7 +111,7 @@ pub fn get_os_version() -> Result { Ok(u) => minor = u, Err(_) => { return Err(Error::ParseVersion(ParseVersionErrorType::MinorBuild( - format!("{} ({})", major_str, CURRENT_MINOR_VERSION_NUMBER_STRING), + format!("{major_str} ({CURRENT_MINOR_VERSION_NUMBER_STRING})"), ))); } } @@ -315,10 +315,7 @@ pub fn get_file_product_version(file_path: &Path) -> Result { } if fixed_file_info_size != std::mem::size_of::() as u32 { return Err(Error::ParseVersion(ParseVersionErrorType::InvalidString( - format!( - "Invalid VS_FIXEDFILEINFO size '{}' returned", - fixed_file_info_size - ), + format!("Invalid VS_FIXEDFILEINFO size '{fixed_file_info_size}' returned"), ))); } From 1773966a3e60b8907350ebeb5d020b7067ef0e4a Mon Sep 17 00:00:00 2001 From: Zhidong Peng Date: Wed, 2 Jul 2025 10:02:10 -0700 Subject: [PATCH 07/12] GPA writes windows events to 'Windows Azure' instead of 'Application'. (#248) * GPA writes windows events to 'Windows Azure' instead of 'Application'. * fix formatting --- .github/actions/spelling/expect.txt | 2 + cargo-clippy.cmd | 24 + cargo-clippy.sh | 26 + proxy_agent/src/common/constants.rs | 1 + proxy_agent/src/service.rs | 6 +- proxy_agent_shared/src/etw.rs | 17 +- proxy_agent_shared/src/etw/application.rs | 467 ------------------ proxy_agent_shared/src/etw/etw_reader.rs | 273 ++++++++++ proxy_agent_shared/src/etw/etw_writter.rs | 200 ++++++++ .../src/logger/logger_manager.rs | 18 +- 10 files changed, 556 insertions(+), 478 deletions(-) create mode 100644 cargo-clippy.cmd create mode 100755 cargo-clippy.sh delete mode 100644 proxy_agent_shared/src/etw/application.rs create mode 100644 proxy_agent_shared/src/etw/etw_reader.rs create mode 100644 proxy_agent_shared/src/etw/etw_writter.rs diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index a04c71c9..6142f860 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -222,6 +222,7 @@ RDFE redhat Redist refcnt +registereventsourcew registrykey relativeurl resf @@ -331,6 +332,7 @@ westus wevtapi WFP winapi +winbase windowsazureguestagent winget winmgmts diff --git a/cargo-clippy.cmd b/cargo-clippy.cmd new file mode 100644 index 00000000..d5a88cac --- /dev/null +++ b/cargo-clippy.cmd @@ -0,0 +1,24 @@ +REM Copyright (c) Microsoft Corporation +REM SPDX-License-Identifier: MIT + +@echo off + +REM This script is used to set the default toolchain for the current directory and run cargo clippy and cargo fmt. + +echo ======= rustup default stable +echo rustup update stable +rustup update stable +echo rustup override unset +rustup override unset + +echo ======= cargo fmt and clippy +echo call rustup component add rustfmt clippy +call rustup component add rustfmt clippy +echo call cargo fmt --all +cargo fmt --all +echo call cargo clippy -- -D warnings +cargo clippy -- -D warnings +if %ERRORLEVEL% NEQ 0 ( + echo cargo clippy failed with exit-code: %errorlevel% + exit /b %errorlevel% +) diff --git a/cargo-clippy.sh b/cargo-clippy.sh new file mode 100755 index 00000000..a4fed8c3 --- /dev/null +++ b/cargo-clippy.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# Copyright (c) Microsoft Corporation +# SPDX-License-Identifier: MIT + +# Prints then runs the command based on: https://stackoverflow.com/questions/31656645/how-do-i-echo-directly-on-standard-output-inside-a-shell-function +runthis(){ + echo "$@" + ## Run the command and redirect its error output + "$@" >&2 +} + +# This script is used to set the default toolchain for the current directory and run cargo clippy and cargo fmt. +rustup update stable +rustup override unset + +echo "======= cargo fmt & clippy" +runthis rustup component add rustfmt clippy +runthis cargo fmt --all +runthis cargo clippy -- -D warnings +error_code=$? +if [ $error_code -ne 0 ] +then + echo "cargo clippy with exit-code: $error_code" + exit $error_code +fi \ No newline at end of file diff --git a/proxy_agent/src/common/constants.rs b/proxy_agent/src/common/constants.rs index 230f6aa3..19824849 100644 --- a/proxy_agent/src/common/constants.rs +++ b/proxy_agent/src/common/constants.rs @@ -7,6 +7,7 @@ pub const GA_PLUGIN_PORT: u16 = 32526u16; pub const IMDS_IP: &str = "169.254.169.254"; pub const IMDS_PORT: u16 = 80u16; +pub const WINDOWS_AZURE: &str = "Windows Azure"; pub const PROXY_AGENT_SERVICE_NAME: &str = "GuestProxyAgent"; pub const PROXY_AGENT_IP: &str = "127.0.0.1"; pub const PROXY_AGENT_PORT: u16 = 3080; diff --git a/proxy_agent/src/service.rs b/proxy_agent/src/service.rs index 7d07d965..b091d153 100644 --- a/proxy_agent/src/service.rs +++ b/proxy_agent/src/service.rs @@ -28,7 +28,11 @@ use std::time::Duration; /// ``` pub async fn start_service(shared_state: SharedState) { if let Some(max_log_level) = config::get_file_log_level_for_system_events() { - logger_manager::set_system_logger(max_log_level, constants::PROXY_AGENT_SERVICE_NAME); + logger_manager::set_system_logger( + max_log_level, + constants::WINDOWS_AZURE, + constants::PROXY_AGENT_SERVICE_NAME, + ); } let log_folder = config::get_logs_dir(); diff --git a/proxy_agent_shared/src/etw.rs b/proxy_agent_shared/src/etw.rs index 7ad87c14..166b10d8 100644 --- a/proxy_agent_shared/src/etw.rs +++ b/proxy_agent_shared/src/etw.rs @@ -2,4 +2,19 @@ // SPDX-License-Identifier: MIT //! This module provides functionality for ETW (Event Tracing for Windows) logging. -pub mod application; +pub mod etw_writter; + +/// This module provides functionality to read ETW events. +/// Test quality only so far. +#[cfg(test)] +mod etw_reader; + +use std::ffi::OsStr; +use std::iter::once; +use std::os::windows::ffi::OsStrExt; + +/// Converts a string to a wide character vector (u16). +/// This is used to convert Rust strings to the format required by Windows API functions. +pub fn to_wide(s: &str) -> Vec { + OsStr::new(s).encode_wide().chain(once(0)).collect() +} diff --git a/proxy_agent_shared/src/etw/application.rs b/proxy_agent_shared/src/etw/application.rs deleted file mode 100644 index 364e4ff7..00000000 --- a/proxy_agent_shared/src/etw/application.rs +++ /dev/null @@ -1,467 +0,0 @@ -// Copyright (c) Microsoft Corporation -// SPDX-License-Identifier: MIT -//! This module provides functionality for Windows Application event -//! // logging using the Windows Event Log API. -//! // It allows registering an event source, writing logs to the Application Event Log. - -use crate::error::Error; -use crate::logger::LoggerLevel; -use crate::result::Result; -use std::ffi::OsStr; -use std::iter::once; -use std::os::windows::ffi::OsStrExt; -use windows_sys::core::PWSTR; -use windows_sys::Win32::Foundation::HANDLE; -use windows_sys::Win32::System::EventLog::{ - DeregisterEventSource, RegisterEventSourceW, ReportEventW, -}; // advapi32.dll -use windows_sys::Win32::System::EventLog::{ - EVENTLOG_ERROR_TYPE, EVENTLOG_INFORMATION_TYPE, EVENTLOG_WARNING_TYPE, REPORT_EVENT_TYPE, -}; - -/// Converts a string to a wide character vector (u16). -/// This is used to convert Rust strings to the format required by Windows API functions. -fn to_wide(s: &str) -> Vec { - OsStr::new(s).encode_wide().chain(once(0)).collect() -} - -/// Converts a `LoggerLevel` to a `REPORT_EVENT_TYPE`. -/// This function maps the logging levels to the corresponding Windows Event Log types. -fn to_event_level(level: LoggerLevel) -> REPORT_EVENT_TYPE { - match level { - LoggerLevel::Trace => EVENTLOG_INFORMATION_TYPE, - LoggerLevel::Debug => EVENTLOG_INFORMATION_TYPE, - LoggerLevel::Info => EVENTLOG_INFORMATION_TYPE, - LoggerLevel::Warn => EVENTLOG_WARNING_TYPE, - LoggerLevel::Error => EVENTLOG_ERROR_TYPE, - } -} - -/// A struct for writing application events to the Windows Event Log. -/// It registers an event source and provides a method to write logs. -/// It also ensures that the event source is deregistered when the struct is dropped. -pub struct ApplicationEventWritter { - event_source: HANDLE, -} - -impl ApplicationEventWritter { - pub fn new(source_name: &str) -> Result { - let source_name_wide = to_wide(source_name); - let event_source = - unsafe { RegisterEventSourceW(std::ptr::null(), source_name_wide.as_ptr()) }; - if event_source == 0 { - return Err(Error::WindowsApi( - "RegisterEventSourceW".to_string(), - std::io::Error::last_os_error(), - )); - } - - // register event source in the Windows Registry - // `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Application\{source_name}` - let key_name = - format!(r"SYSTEM\CurrentControlSet\Services\EventLog\Application\{source_name}"); - let value = crate::misc_helpers::resolve_env_variables( - r"%SystemRoot%\Microsoft.NET\Framework64\v4.0.30319\EventLogMessages.dll", - )?; - crate::windows::set_reg_string(&key_name, "EventMessageFile", value)?; - - Ok(ApplicationEventWritter { event_source }) - } - - pub fn write(&self, log_level: LoggerLevel, message: String) { - let wide_message = to_wide(&message); - let wide_message_ptrs: [PWSTR; 1] = [wide_message.as_ptr() as PWSTR]; - - unsafe { - ReportEventW( - self.event_source, - to_event_level(log_level), - 0, - 0, - std::ptr::null_mut(), - 1, - 0, - wide_message_ptrs.as_ptr() as *const *const u16, - std::ptr::null(), - ); - } - } -} - -impl Drop for ApplicationEventWritter { - fn drop(&mut self) { - unsafe { - DeregisterEventSource(self.event_source); - } - } -} - -#[cfg(test)] -mod tests { - - /// etw_reader test module is used to read ETW events from the Windows Event Log. - mod etw_reader { - - use crate::error::Error; - use crate::result::Result; - use chrono::DateTime; - use serde_derive::{Deserialize, Serialize}; - use std::ffi::OsString; - use std::os::windows::ffi::OsStringExt; - use windows_sys::Win32::Foundation::GetLastError; - use windows_sys::Win32::Foundation::ERROR_NO_MORE_ITEMS; - use windows_sys::Win32::System::EventLog::{ - EvtClose, EvtNext, EvtQuery, EvtRender, EVT_HANDLE, - }; // wevtapi.dll - use windows_sys::Win32::System::EventLog::{EvtQueryReverseDirection, EvtRenderEventXml}; - - /// Represents an ETW event structure - /// as defined in the XML schema. - /// The structure is used to deserialize ETW events from XML format. - /// The `Event` struct contains a `System` and `EventData` field, - /// which hold the metadata and data of the event respectively. - #[derive(Debug, Deserialize, Serialize)] - #[serde(rename = "Event")] - pub struct Event { - #[serde(rename = "System")] - pub system: System, - #[serde(rename = "EventData", skip_serializing_if = "Option::is_none")] - pub event_data: Option, - } - - #[derive(Debug, Deserialize, Serialize)] - pub struct System { - #[serde(rename = "Provider")] - pub provider: Provider, - #[serde(rename = "EventID")] - pub event_id: u32, - #[serde(rename = "Version")] - pub version: u8, - #[serde(rename = "Level")] - pub level: u8, - #[serde(rename = "Task")] - pub task: u8, - #[serde(rename = "Opcode")] - pub opcode: u8, - #[serde(rename = "Keywords")] - pub keywords: String, - #[serde(rename = "TimeCreated")] - pub time_created: TimeCreated, - #[serde(rename = "EventRecordID")] - pub event_record_id: u64, - #[serde(rename = "Execution")] - pub execution: Execution, - #[serde(rename = "Channel")] - pub channel: String, - #[serde(rename = "Computer")] - pub computer: String, - } - - #[derive(Debug, Deserialize, Serialize)] - pub struct Provider { - #[serde(rename = "@Name", skip_serializing_if = "Option::is_none")] - pub name: Option, - #[serde(rename = "@EventSourceName", skip_serializing_if = "Option::is_none")] - pub event_source_name: Option, - } - - #[derive(Debug, Deserialize, Serialize)] - pub struct TimeCreated { - #[serde(rename = "@SystemTime", skip_serializing_if = "Option::is_none")] - pub system_time: Option, - } - - #[derive(Debug, Deserialize, Serialize)] - pub struct Execution { - #[serde(rename = "@ProcessID")] - pub process_id: u32, - #[serde(rename = "@ThreadID")] - pub thread_id: u32, - } - - #[derive(Debug, Deserialize, Serialize)] - pub struct EventData { - #[serde(rename = "Data")] - pub data: Option>, - } - - pub struct WindowsEventReader { - query_handle: EVT_HANDLE, - current_event: EVT_HANDLE, - source_name: String, - start_time: Option>, - end_time: Option>, - } - - impl WindowsEventReader { - pub fn new( - event_name: &str, - source_name: &str, - start_time: Option>, - end_time: Option>, - ) -> Result { - let event_name_wide = crate::etw::application::to_wide(event_name); - let h_query = unsafe { - EvtQuery( - 0, - event_name_wide.as_ptr(), - std::ptr::null(), - EvtQueryReverseDirection, - ) - }; - if h_query == 0 { - return Err(Error::WindowsApi( - "EvtQuery".to_string(), - std::io::Error::last_os_error(), - )); - } - - Ok(WindowsEventReader { - query_handle: h_query, - current_event: 0, - source_name: source_name.to_string(), - start_time, - end_time, - }) - } - // Additional methods for reading events can be implemented here - } - - impl Drop for WindowsEventReader { - fn drop(&mut self) { - // Close the query handle and current event handle if they are open - unsafe { - EvtClose(self.query_handle); - EvtClose(self.current_event); - } - } - } - - impl Iterator for WindowsEventReader { - type Item = Result; - - fn next(&mut self) -> Option { - let mut returned: u32 = 0; - - if unsafe { - EvtNext( - self.query_handle, - 1, - &mut self.current_event, - 0, - 0, - &mut returned, - ) - } == 0 - { - let error_code = unsafe { GetLastError() }; - if error_code == ERROR_NO_MORE_ITEMS { - // No more items to read - return None; - } else { - return Some(Err(Error::WindowsApi( - "EvtNext".to_string(), - std::io::Error::from_raw_os_error(error_code as i32), - ))); - } - } - - if returned == 0 { - return None; // No events read - } - - // First call to get buffer size - let mut buffer_used = 0; - let mut property_count = 0; - let status = unsafe { - EvtRender( - 0, - self.current_event, - EvtRenderEventXml, - 0, - std::ptr::null_mut(), - &mut buffer_used, - &mut property_count, - ) - }; - if status != 0 || buffer_used == 0 { - return Some(Err(Error::WindowsApi( - "EvtRender_Buffer_Size".to_string(), - std::io::Error::last_os_error(), - ))); - } - // Allocate buffer for rendering - let mut buffer: Vec = vec![0; buffer_used as usize / 2]; - if unsafe { - EvtRender( - 0, - self.current_event, - EvtRenderEventXml, - buffer_used, - buffer.as_mut_ptr() as *mut _, - &mut buffer_used, - &mut property_count, - ) - } == 0 - { - return Some(Err(Error::WindowsApi( - "EvtRender".to_string(), - std::io::Error::last_os_error(), - ))); - } - - // Convert the buffer to a xml string - let xml = OsString::from_wide(&buffer) - .to_string_lossy() - .trim_end_matches('\0') - .to_string(); - - // Parse the XML string into an Event struct - match serde_xml_rs::from_str::(&xml) { - Ok(event) => { - let mut skip_event = false; - // Check if the event is from the specified source - if event.system.provider.name == Some(self.source_name.clone()) { - // Check if the event is within the specified time range - let time_created = event.system.time_created.system_time.clone(); - println!( - "Event '{}' Time Created: {:?}", - self.source_name, time_created - ); - if let Some(start_time) = self.start_time { - match time_created.clone() { - Some(time) => { - if let Ok(event_time) = - time.parse::>() - { - if event_time < start_time { - skip_event = true; // Skip this event - } - } - } - None => skip_event = true, // Skip this event if time is not available - } - } - if let Some(end_time) = self.end_time { - match time_created { - Some(time) => { - if let Ok(event_time) = - time.parse::>() - { - if event_time > end_time { - skip_event = true; // Skip this event - } - } - } - None => skip_event = true, // Skip this event if time is not available - } - } - } else { - skip_event = true; // Skip this event - } - - if skip_event { - self.next() // Skip to the next event - } else { - Some(Ok(event)) // Return the event - } - } - Err(e) => Some(Err(Error::Io(std::io::Error::new( - std::io::ErrorKind::InvalidData, - format!("Failed to parse event XML: {}", e), - )))), - } - } - } - } - - use chrono::DateTime; - - #[test] - fn write_event_log_test() { - use super::ApplicationEventWritter; - use crate::logger::LoggerLevel; - - // According to the test log, it indicates that Windows Container may have few milliseconds difference against its current host time. - // Therefore, we set the start time to 1 second before the current time. - let start_time = chrono::Utc::now() - chrono::Duration::seconds(1); - let end_time = start_time + chrono::Duration::seconds(60); - - let source_name = "GuestProxyAgent_TestApplication"; - let message = "This is a test log message"; - let event_writer = ApplicationEventWritter::new(source_name).unwrap(); - event_writer.write(LoggerLevel::Info, message.to_string()); - - println!("Verifying event log for source: {}", source_name); - let data = query_application_event(source_name, None, None); - assert_eq!( - data, message, - "Event log data does not match the expected message" - ); - - println!( - "Verifying event log for source: {} after {}", - source_name, start_time - ); - let data = query_application_event(source_name, Some(start_time), None); - assert_eq!( - data, message, - "Event log data does not match the expected message" - ); - - println!( - "Verifying event log for source: {} before {}", - source_name, end_time - ); - let data = query_application_event(source_name, None, Some(end_time)); - assert_eq!( - data, message, - "Event log data does not match the expected message" - ); - - println!( - "Verifying event log for source: {} between {} and {}", - source_name, start_time, end_time - ); - let data = query_application_event(source_name, Some(start_time), Some(end_time)); - assert_eq!( - data, message, - "Event log data does not match the expected message" - ); - - // Clean up: Remove the event source from the Windows Registry - let key_name = format!( - r"SYSTEM\CurrentControlSet\Services\EventLog\Application\{}", - source_name - ); - if let Err(e) = crate::windows::remove_reg_key(&key_name) { - eprintln!("Failed to remove event source from registry: {}", e); - } - } - - fn query_application_event( - source_name: &str, - start_time: Option>, - end_time: Option>, - ) -> String { - let mut reader = - etw_reader::WindowsEventReader::new("Application", source_name, start_time, end_time) - .unwrap(); - let data = reader - .next() - .map(|event| { - event - .unwrap() - .event_data - .unwrap() - .data - .unwrap() - .iter() - .map(|d| d.to_string()) - .collect::>() - }) - .unwrap_or_else(|| vec!["No data found".to_string()]); - - return data.join("\n"); - } -} diff --git a/proxy_agent_shared/src/etw/etw_reader.rs b/proxy_agent_shared/src/etw/etw_reader.rs new file mode 100644 index 00000000..5c06065b --- /dev/null +++ b/proxy_agent_shared/src/etw/etw_reader.rs @@ -0,0 +1,273 @@ +// Copyright (c) Microsoft Corporation +// SPDX-License-Identifier: MIT + +use crate::error::Error; +use crate::result::Result; +use chrono::DateTime; +use serde_derive::{Deserialize, Serialize}; +use std::ffi::OsString; +use std::os::windows::ffi::OsStringExt; +use windows_sys::Win32::Foundation::GetLastError; +use windows_sys::Win32::Foundation::ERROR_NO_MORE_ITEMS; +use windows_sys::Win32::System::EventLog::{EvtClose, EvtNext, EvtQuery, EvtRender, EVT_HANDLE}; // wevtapi.dll +use windows_sys::Win32::System::EventLog::{EvtQueryReverseDirection, EvtRenderEventXml}; + +/// Represents an ETW event structure +/// as defined in the XML schema. +/// The structure is used to deserialize ETW events from XML format. +/// The `Event` struct contains a `System` and `EventData` field, +/// which hold the metadata and data of the event respectively. +#[derive(Debug, Deserialize, Serialize)] +#[serde(rename = "Event")] +pub struct Event { + #[serde(rename = "System")] + pub system: System, + #[serde(rename = "EventData", skip_serializing_if = "Option::is_none")] + pub event_data: Option, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct System { + #[serde(rename = "Provider")] + pub provider: Provider, + #[serde(rename = "EventID")] + pub event_id: u32, + #[serde(rename = "Version")] + pub version: u8, + #[serde(rename = "Level")] + pub level: u8, + #[serde(rename = "Task")] + pub task: u8, + #[serde(rename = "Opcode")] + pub opcode: u8, + #[serde(rename = "Keywords")] + pub keywords: String, + #[serde(rename = "TimeCreated")] + pub time_created: TimeCreated, + #[serde(rename = "EventRecordID")] + pub event_record_id: u64, + #[serde(rename = "Execution")] + pub execution: Execution, + #[serde(rename = "Channel")] + pub channel: String, + #[serde(rename = "Computer")] + pub computer: String, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct Provider { + #[serde(rename = "@Name", skip_serializing_if = "Option::is_none")] + pub name: Option, + #[serde(rename = "@EventSourceName", skip_serializing_if = "Option::is_none")] + pub event_source_name: Option, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct TimeCreated { + #[serde(rename = "@SystemTime", skip_serializing_if = "Option::is_none")] + pub system_time: Option, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct Execution { + #[serde(rename = "@ProcessID")] + pub process_id: u32, + #[serde(rename = "@ThreadID")] + pub thread_id: u32, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct EventData { + #[serde(rename = "Data")] + pub data: Option>, +} + +pub struct WindowsEventReader { + query_handle: EVT_HANDLE, + current_event: EVT_HANDLE, + source_name: String, + start_time: Option>, + end_time: Option>, +} + +impl WindowsEventReader { + pub fn new( + event_name: &str, + source_name: &str, + start_time: Option>, + end_time: Option>, + ) -> Result { + let event_name_wide = crate::etw::to_wide(event_name); + let h_query = unsafe { + EvtQuery( + 0, + event_name_wide.as_ptr(), + std::ptr::null(), + EvtQueryReverseDirection, + ) + }; + if h_query == 0 { + return Err(Error::WindowsApi( + "EvtQuery".to_string(), + std::io::Error::last_os_error(), + )); + } + + Ok(WindowsEventReader { + query_handle: h_query, + current_event: 0, + source_name: source_name.to_string(), + start_time, + end_time, + }) + } + // Additional methods for reading events can be implemented here +} + +impl Drop for WindowsEventReader { + fn drop(&mut self) { + // Close the query handle and current event handle if they are open + unsafe { + EvtClose(self.query_handle); + EvtClose(self.current_event); + } + } +} + +impl Iterator for WindowsEventReader { + type Item = Result; + + fn next(&mut self) -> Option { + let mut returned: u32 = 0; + + if unsafe { + EvtNext( + self.query_handle, + 1, + &mut self.current_event, + 0, + 0, + &mut returned, + ) + } == 0 + { + let error_code = unsafe { GetLastError() }; + if error_code == ERROR_NO_MORE_ITEMS { + // No more items to read + return None; + } else { + return Some(Err(Error::WindowsApi( + "EvtNext".to_string(), + std::io::Error::from_raw_os_error(error_code as i32), + ))); + } + } + + if returned == 0 { + return None; // No events read + } + + // First call to get buffer size + let mut buffer_used = 0; + let mut property_count = 0; + let status = unsafe { + EvtRender( + 0, + self.current_event, + EvtRenderEventXml, + 0, + std::ptr::null_mut(), + &mut buffer_used, + &mut property_count, + ) + }; + if status != 0 || buffer_used == 0 { + return Some(Err(Error::WindowsApi( + "EvtRender_Buffer_Size".to_string(), + std::io::Error::last_os_error(), + ))); + } + // Allocate buffer for rendering + let mut buffer: Vec = vec![0; buffer_used as usize / 2]; + if unsafe { + EvtRender( + 0, + self.current_event, + EvtRenderEventXml, + buffer_used, + buffer.as_mut_ptr() as *mut _, + &mut buffer_used, + &mut property_count, + ) + } == 0 + { + return Some(Err(Error::WindowsApi( + "EvtRender".to_string(), + std::io::Error::last_os_error(), + ))); + } + + // Convert the buffer to a xml string + let xml = OsString::from_wide(&buffer) + .to_string_lossy() + .trim_end_matches('\0') + .to_string(); + + // Parse the XML string into an Event struct + match serde_xml_rs::from_str::(&xml) { + Ok(event) => { + let mut skip_event = false; + // Check if the event is from the specified source + if event.system.provider.name == Some(self.source_name.clone()) { + // Check if the event is within the specified time range + let time_created = event.system.time_created.system_time.clone(); + println!( + "Event '{}' Time Created: {:?}", + self.source_name, time_created + ); + + if let Some(start_time) = self.start_time { + match time_created.clone() { + Some(time) => { + if let Ok(event_time) = + time.parse::>() + { + if event_time < start_time { + skip_event = true; // Skip this event + } + } + } + None => skip_event = true, // Skip this event if time is not available + } + } + if let Some(end_time) = self.end_time { + match time_created { + Some(time) => { + if let Ok(event_time) = + time.parse::>() + { + if event_time > end_time { + skip_event = true; // Skip this event + } + } + } + None => skip_event = true, // Skip this event if time is not available + } + } + } else { + skip_event = true; // Skip this event + } + + if skip_event { + self.next() // Skip to the next event + } else { + Some(Ok(event)) // Return the event + } + } + Err(e) => Some(Err(Error::Io(std::io::Error::new( + std::io::ErrorKind::InvalidData, + format!("Failed to parse event XML: {e}"), + )))), + } + } +} diff --git a/proxy_agent_shared/src/etw/etw_writter.rs b/proxy_agent_shared/src/etw/etw_writter.rs new file mode 100644 index 00000000..bc71d821 --- /dev/null +++ b/proxy_agent_shared/src/etw/etw_writter.rs @@ -0,0 +1,200 @@ +// Copyright (c) Microsoft Corporation +// SPDX-License-Identifier: MIT + +//! This module provides functionality for Windows event +//! logging using the Windows Event Log API. +//! It allows registering an event source, writing logs to the Event Log. + +use crate::error::Error; +use crate::logger::LoggerLevel; +use crate::result::Result; +use windows_sys::core::PWSTR; +use windows_sys::Win32::Foundation::HANDLE; +use windows_sys::Win32::System::EventLog::{ + DeregisterEventSource, RegisterEventSourceW, ReportEventW, +}; // advapi32.dll +use windows_sys::Win32::System::EventLog::{ + EVENTLOG_ERROR_TYPE, EVENTLOG_INFORMATION_TYPE, EVENTLOG_WARNING_TYPE, REPORT_EVENT_TYPE, +}; + +/// Converts a `LoggerLevel` to a `REPORT_EVENT_TYPE`. +/// This function maps the logging levels to the corresponding Windows Event Log types. +fn to_event_level(level: LoggerLevel) -> REPORT_EVENT_TYPE { + match level { + LoggerLevel::Trace => EVENTLOG_INFORMATION_TYPE, + LoggerLevel::Debug => EVENTLOG_INFORMATION_TYPE, + LoggerLevel::Info => EVENTLOG_INFORMATION_TYPE, + LoggerLevel::Warn => EVENTLOG_WARNING_TYPE, + LoggerLevel::Error => EVENTLOG_ERROR_TYPE, + } +} + +/// A struct for writing windows etw events to the Windows Event Log. +/// It registers an event source and provides a method to write logs. +/// It also ensures that the event source is deregistered when the struct is dropped. +pub struct WindowsEventWritter { + event_source: HANDLE, +} + +impl WindowsEventWritter { + pub fn new(event_log_name: &str, source_name: &str) -> Result { + // Add event source in the Windows Registry before retrieving the event source handle. + // `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\{event_log_name}\{source_name}` + let key_name = format!( + "SYSTEM\\CurrentControlSet\\Services\\EventLog\\{event_log_name}\\{source_name}" + ); + let value = crate::misc_helpers::resolve_env_variables( + r"%SystemRoot%\Microsoft.NET\Framework64\v4.0.30319\EventLogMessages.dll", + )?; + crate::windows::set_reg_string(&key_name, "EventMessageFile", value)?; + + let source_name_wide = super::to_wide(source_name); + let event_source = + unsafe { RegisterEventSourceW(std::ptr::null(), source_name_wide.as_ptr()) }; + if event_source == 0 { + return Err(Error::WindowsApi( + "RegisterEventSourceW".to_string(), + std::io::Error::last_os_error(), + )); + } + + Ok(WindowsEventWritter { event_source }) + } + + pub fn write(&self, log_level: LoggerLevel, message: String) { + let wide_message = super::to_wide(&message); + let wide_message_ptrs: [PWSTR; 1] = [wide_message.as_ptr() as PWSTR]; + + unsafe { + ReportEventW( + self.event_source, + to_event_level(log_level), + 0, + 0, + std::ptr::null_mut(), + 1, + 0, + wide_message_ptrs.as_ptr() as *const *const u16, + std::ptr::null(), + ); + } + } +} + +impl Drop for WindowsEventWritter { + fn drop(&mut self) { + unsafe { + DeregisterEventSource(self.event_source); + } + } +} + +#[cfg(test)] +mod tests { + use super::WindowsEventWritter; + use crate::etw::etw_reader::WindowsEventReader; + use crate::logger::LoggerLevel; + use chrono::DateTime; + + /// This test verifies that the WindowsEventWritter can write to the Windows Event Log + /// and that the written log can be queried successfully. + /// It creates a new event source, writes a log message, + /// and then queries the event log to verify that the message was written correctly. + /// The test also checks for logs within a specific time range + /// to ensure that the event log is being written correctly. + /// # Note: This test picks `Application` as the event log name, + /// as `Windows Container` does have its own Registry but not its own Event Log System. + /// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-registereventsourcew#remarks + /// RegisterEventSourceW retrieves a registered handle to the specified event log, + /// but if the source name cannot be found, the event logging service uses the `Application` log. + #[test] + fn write_event_log_test() { + // According to the test log, it indicates that Windows Container may have few milliseconds difference against its current host time. + // Therefore, we set the start time to 1 second before the current time. + let start_time = chrono::Utc::now() - chrono::Duration::seconds(1); + let end_time = start_time + chrono::Duration::seconds(60); + + let event_log_name = "Application"; + let source_name = "Azure_GuestProxyAgent_TestApplication"; + let message = "This is a test log message"; + let event_writer = WindowsEventWritter::new(event_log_name, source_name).unwrap(); + event_writer.write(LoggerLevel::Info, message.to_string()); + + println!("Verifying event log for source: {}", source_name); + let data = query_windows_event(event_log_name, source_name, None, None); + assert_eq!( + data, message, + "Event log data does not match the expected message" + ); + + println!( + "Verifying event log for source: {} after {}", + source_name, start_time + ); + let data = query_windows_event(event_log_name, source_name, Some(start_time), None); + assert_eq!( + data, message, + "Event log data does not match the expected message" + ); + + println!( + "Verifying event log for source: {} before {}", + source_name, end_time + ); + let data = query_windows_event(event_log_name, source_name, None, Some(end_time)); + assert_eq!( + data, message, + "Event log data does not match the expected message" + ); + + println!( + "Verifying event log for source: {} between {} and {}", + source_name, start_time, end_time + ); + let data = query_windows_event( + event_log_name, + source_name, + Some(start_time), + Some(end_time), + ); + assert_eq!( + data, message, + "Event log data does not match the expected message" + ); + + // Clean up: Remove the event log from the Windows Registry + let key_name = format!( + r"SYSTEM\CurrentControlSet\Services\EventLog\{}\{}", + event_log_name, source_name + ); + if let Err(e) = crate::windows::remove_reg_key(&key_name) { + eprintln!("Failed to remove event source from registry: {}", e); + } + } + + fn query_windows_event( + event_log_name: &str, + source_name: &str, + start_time: Option>, + end_time: Option>, + ) -> String { + let mut reader = + WindowsEventReader::new(event_log_name, source_name, start_time, end_time).unwrap(); + let data = reader + .next() + .map(|event| { + event + .unwrap() + .event_data + .unwrap() + .data + .unwrap() + .iter() + .map(|d| d.to_string()) + .collect::>() + }) + .unwrap_or_else(|| vec!["No data found".to_string()]); + + return data.join("\n"); + } +} diff --git a/proxy_agent_shared/src/logger/logger_manager.rs b/proxy_agent_shared/src/logger/logger_manager.rs index a989a4a6..dc849050 100644 --- a/proxy_agent_shared/src/logger/logger_manager.rs +++ b/proxy_agent_shared/src/logger/logger_manager.rs @@ -6,7 +6,7 @@ use super::rolling_logger::RollingLogger; #[cfg(windows)] -use crate::etw::application::ApplicationEventWritter; +use crate::etw::etw_writter::WindowsEventWritter; use crate::logger::LoggerLevel; use std::collections::HashMap; @@ -21,7 +21,7 @@ static MAX_LOG_LEVEL: tokio::sync::OnceCell = tokio::sync::OnceCell static MAX_SYSTEM_LOG_LEVEL: tokio::sync::OnceCell = tokio::sync::OnceCell::const_new(); #[cfg(windows)] -static WINDOWS_ETW_APPLICATION_LOGGER: tokio::sync::OnceCell = +static WINDOWS_ETW_LOGGER: tokio::sync::OnceCell = tokio::sync::OnceCell::const_new(); /// Setup the loggers and set the default logger key @@ -65,23 +65,23 @@ pub fn set_loggers( } } -pub fn set_system_logger(max_log_level: LoggerLevel, _service_name: &str) { +pub fn set_system_logger(max_log_level: LoggerLevel, _event_log_name: &str, _service_name: &str) { #[cfg(windows)] { - if !WINDOWS_ETW_APPLICATION_LOGGER.initialized() { - match ApplicationEventWritter::new(_service_name) { + if !WINDOWS_ETW_LOGGER.initialized() { + match WindowsEventWritter::new(_event_log_name, _service_name) { Ok(logger) => { - if let Err(e) = WINDOWS_ETW_APPLICATION_LOGGER.set(logger) { + if let Err(e) = WINDOWS_ETW_LOGGER.set(logger) { write_system_log( LoggerLevel::Error, - format!("Failed to set Windows Application ETW logger: {e}"), + format!("Failed to set Windows ETW logger: {e}"), ); } } Err(e) => { write_system_log( LoggerLevel::Error, - format!("Failed to create Windows Application ETW logger: {e}"), + format!("Failed to create Windows ETW logger: {e}"), ); } } @@ -175,7 +175,7 @@ fn write_system_log(log_level: LoggerLevel, message: String) { #[cfg(windows)] { - if let Some(logger) = WINDOWS_ETW_APPLICATION_LOGGER.get() { + if let Some(logger) = WINDOWS_ETW_LOGGER.get() { logger.write(log_level, message); } else { eprintln!("Windows ETW Application logger is not initialized."); From 5d5e70194bdb75a33c9b52607a5a582fd2722652 Mon Sep 17 00:00:00 2001 From: Zhidong Peng Date: Mon, 7 Jul 2025 10:18:48 -0700 Subject: [PATCH 08/12] write to system log for connection logger (#250) --- proxy_agent/src/proxy/proxy_connection.rs | 6 ++++++ proxy_agent_shared/src/logger/logger_manager.rs | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/proxy_agent/src/proxy/proxy_connection.rs b/proxy_agent/src/proxy/proxy_connection.rs index 806057cf..b4200251 100644 --- a/proxy_agent/src/proxy/proxy_connection.rs +++ b/proxy_agent/src/proxy/proxy_connection.rs @@ -291,6 +291,12 @@ impl ConnectionLogger { "{}[{}] - {}", self.http_connection_id, self.tcp_connection_id, message ); + + // write to system log for connection logger explicitly, + // as the connection logger only writes to file when the connection is dropped and, + // connection logger file log does not write to system log implicitly. + logger_manager::write_system_log(logger_level, message.to_string()); + if let Some(log_for_event) = crate::common::config::get_file_log_level_for_events() { if log_for_event >= logger_level { // write to event diff --git a/proxy_agent_shared/src/logger/logger_manager.rs b/proxy_agent_shared/src/logger/logger_manager.rs index dc849050..4ab046b8 100644 --- a/proxy_agent_shared/src/logger/logger_manager.rs +++ b/proxy_agent_shared/src/logger/logger_manager.rs @@ -161,7 +161,7 @@ pub fn write_many(logger_key: Option, messages: Vec) { } } -fn write_system_log(log_level: LoggerLevel, message: String) { +pub fn write_system_log(log_level: LoggerLevel, message: String) { if log_level > get_max_system_logger_level() { return; } From 1550e05325299b84798cea3cb386f06285e86f4a Mon Sep 17 00:00:00 2001 From: Zhidong Peng Date: Mon, 7 Jul 2025 10:37:27 -0700 Subject: [PATCH 09/12] GPA to close the connection if it is not received response from host. (#251) --- proxy_agent/src/proxy/proxy_server.rs | 55 +++++++++++++++++++-------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/proxy_agent/src/proxy/proxy_server.rs b/proxy_agent/src/proxy/proxy_server.rs index 1fe378bc..8a4e4214 100644 --- a/proxy_agent/src/proxy/proxy_server.rs +++ b/proxy_agent/src/proxy/proxy_server.rs @@ -375,7 +375,7 @@ impl ProxyServer { LoggerLevel::Error, format!("Failed to increase connection count: {e}"), ); - return Ok(Self::empty_response(StatusCode::INTERNAL_SERVER_ERROR)); + return Ok(Self::closed_response(StatusCode::INTERNAL_SERVER_ERROR)); } }; @@ -405,7 +405,7 @@ impl ProxyServer { "Traversal characters found in the request, return NOT_FOUND!".to_string(), ) .await; - return Ok(Self::empty_response(StatusCode::NOT_FOUND)); + return Ok(Self::closed_response(StatusCode::NOT_FOUND)); } if http_connection_context.url == provision::provision_query::PROVISION_URL_PATH { @@ -427,7 +427,7 @@ impl ProxyServer { "No remote destination_ip found in the request, return!".to_string(), ) .await; - return Ok(Self::empty_response(StatusCode::MISDIRECTED_REQUEST)); + return Ok(Self::closed_response(StatusCode::MISDIRECTED_REQUEST)); } }; let port = tcp_connection_context.destination_port; @@ -441,7 +441,7 @@ impl ProxyServer { "No claims found in the request, return!".to_string(), ) .await; - return Ok(Self::empty_response(StatusCode::MISDIRECTED_REQUEST)); + return Ok(Self::closed_response(StatusCode::MISDIRECTED_REQUEST)); } }; http_connection_context.log(LoggerLevel::Trace, format!("Use lookup value:{ip}:{port}.")); @@ -455,7 +455,7 @@ impl ProxyServer { format!("Failed to get claims json string: {e}"), ) .await; - return Ok(Self::empty_response(StatusCode::MISDIRECTED_REQUEST)); + return Ok(Self::closed_response(StatusCode::MISDIRECTED_REQUEST)); } }; http_connection_context.log(LoggerLevel::Trace, claim_details.to_string()); @@ -477,7 +477,7 @@ impl ProxyServer { format!("Failed to get access control rules: {e}"), ) .await; - return Ok(Self::empty_response(StatusCode::INTERNAL_SERVER_ERROR)); + return Ok(Self::closed_response(StatusCode::INTERNAL_SERVER_ERROR)); } }; let result = proxy_authorizer::authorize( @@ -505,7 +505,7 @@ impl ProxyServer { format!("Block unauthorized request: {claim_details}"), ) .await; - return Ok(Self::empty_response(StatusCode::FORBIDDEN)); + return Ok(Self::closed_response(StatusCode::FORBIDDEN)); } } @@ -527,7 +527,7 @@ impl ProxyServer { LoggerLevel::Error, format!("Failed to add claims header: {host_claims} with error: {e}"), ); - return Ok(Self::empty_response(StatusCode::BAD_GATEWAY)); + return Ok(Self::closed_response(StatusCode::BAD_GATEWAY)); } }, ); @@ -540,7 +540,7 @@ impl ProxyServer { LoggerLevel::Error, format!("Failed to add date header with error: {e}"), ); - return Ok(Self::empty_response(StatusCode::BAD_GATEWAY)); + return Ok(Self::closed_response(StatusCode::BAD_GATEWAY)); } }, ); @@ -567,7 +567,7 @@ impl ProxyServer { LoggerLevel::Error, format!("Failed to convert request: {e}"), ); - return Ok(Self::empty_response(StatusCode::BAD_REQUEST)); + return Ok(Self::closed_response(StatusCode::BAD_REQUEST)); } }; let proxy_response = http_connection_context.send_request(request).await; @@ -600,7 +600,7 @@ impl ProxyServer { LoggerLevel::Warn, "No MetaData header found in the request.".to_string(), ); - return Ok(Self::empty_response(StatusCode::BAD_REQUEST)); + return Ok(Self::closed_response(StatusCode::BAD_REQUEST)); } // Get the query time_tick let query_time_tick = match request.headers().get(constants::TIME_TICK_HEADER) { @@ -695,7 +695,7 @@ impl ProxyServer { format!("Failed to send request to host: {e}"), ) .await; - return Ok(Self::empty_response(http_status_code)); + return Ok(Self::closed_response(http_status_code)); } }; @@ -828,6 +828,17 @@ impl ProxyServer { response } + fn closed_response(status_code: StatusCode) -> Response> { + let mut response = Self::empty_response(status_code); + + // Add the Connection: close header to close the tcp connection + response + .headers_mut() + .insert(hyper::header::CONNECTION, HeaderValue::from_static("close")); + + response + } + async fn handle_request_with_signature( &self, mut http_connection_context: HttpConnectionContext, @@ -841,7 +852,7 @@ impl ProxyServer { LoggerLevel::Error, format!("Failed to receive the request body: {e}"), ); - return Ok(Self::empty_response(StatusCode::BAD_REQUEST)); + return Ok(Self::closed_response(StatusCode::BAD_REQUEST)); } }; @@ -887,7 +898,7 @@ impl ProxyServer { "Failed to add authorization header: {authorization_value} with error: {e}" ), ); - return Ok(Self::empty_response(StatusCode::BAD_GATEWAY)); + return Ok(Self::closed_response(StatusCode::BAD_GATEWAY)); } }, ); @@ -965,15 +976,29 @@ mod tests { .unwrap_or(None), ) .unwrap(); - let response = hyper_client::send_request(host, port, request, logger::write_warning) + let mut sender = hyper_client::build_http_sender(host, port, logger::write_warning) .await .unwrap(); + let response = sender.send_request(request).await.unwrap(); assert_eq!( http::StatusCode::MISDIRECTED_REQUEST, response.status(), "response.status must be MISDIRECTED_REQUEST." ); + // verify the connection is closed + response.headers().get("connection").map(|v| { + assert_eq!( + v.to_str().unwrap(), + "close", + "response.headers.connection must be close." + ); + }); + assert!( + sender.is_closed(), + "sender must be closed after the request." + ); + // test with traversal characters let url: hyper::Uri = format!("http://{}:{}/test/../", host, port) .parse() From 4341bcb613c5da5e90b8e661ef1f3e23c070ffdc Mon Sep 17 00:00:00 2001 From: Zhidong Peng Date: Mon, 7 Jul 2025 11:28:08 -0700 Subject: [PATCH 10/12] Prepare release 1.0.32 --- Cargo.lock | 8 ++++---- proxy_agent/Cargo.toml | 2 +- proxy_agent_extension/Cargo.toml | 2 +- proxy_agent_setup/Cargo.toml | 2 +- proxy_agent_shared/Cargo.toml | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 76fcfd8c..80e2d820 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,7 +4,7 @@ version = 4 [[package]] name = "ProxyAgentExt" -version = "1.0.31" +version = "1.0.32" dependencies = [ "clap", "ctor", @@ -172,7 +172,7 @@ dependencies = [ [[package]] name = "azure-proxy-agent" -version = "1.0.31" +version = "1.0.32" dependencies = [ "aya", "bitflags", @@ -865,7 +865,7 @@ dependencies = [ [[package]] name = "proxy_agent_setup" -version = "1.0.31" +version = "1.0.32" dependencies = [ "clap", "proxy_agent_shared", @@ -877,7 +877,7 @@ dependencies = [ [[package]] name = "proxy_agent_shared" -version = "1.0.31" +version = "1.0.32" dependencies = [ "backtrace", "chrono", diff --git a/proxy_agent/Cargo.toml b/proxy_agent/Cargo.toml index 47f68d7a..e0585635 100644 --- a/proxy_agent/Cargo.toml +++ b/proxy_agent/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "azure-proxy-agent" -version = "1.0.31" # always 3-number version +version = "1.0.32" # always 3-number version edition = "2021" build = "build.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/proxy_agent_extension/Cargo.toml b/proxy_agent_extension/Cargo.toml index ad73f22c..6995ba67 100644 --- a/proxy_agent_extension/Cargo.toml +++ b/proxy_agent_extension/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ProxyAgentExt" -version = "1.0.31" # always 3-number version +version = "1.0.32" # always 3-number version edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/proxy_agent_setup/Cargo.toml b/proxy_agent_setup/Cargo.toml index 3ded82cd..698fdb9e 100644 --- a/proxy_agent_setup/Cargo.toml +++ b/proxy_agent_setup/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "proxy_agent_setup" -version = "1.0.31" +version = "1.0.32" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/proxy_agent_shared/Cargo.toml b/proxy_agent_shared/Cargo.toml index 231e8b27..098e387f 100644 --- a/proxy_agent_shared/Cargo.toml +++ b/proxy_agent_shared/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "proxy_agent_shared" -version = "1.0.31" +version = "1.0.32" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From 251b868635a02289dc35ada418e14228257f9373 Mon Sep 17 00:00:00 2001 From: shahneerali <131208062+shahneerali@users.noreply.github.com> Date: Mon, 7 Jul 2025 14:54:49 -0700 Subject: [PATCH 11/12] Bug Fix: Add Padding when logger header is not 34 chars long (#255) * add change * clippy --- proxy_agent_shared/src/logger.rs | 50 ++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/proxy_agent_shared/src/logger.rs b/proxy_agent_shared/src/logger.rs index 165d48dd..f80ccf63 100644 --- a/proxy_agent_shared/src/logger.rs +++ b/proxy_agent_shared/src/logger.rs @@ -8,13 +8,31 @@ pub mod rolling_logger; pub type LoggerLevel = log::Level; +const HEADER_LENGTH: usize = 34; pub fn get_log_header(level: LoggerLevel) -> String { - format!( - "{} [{}] ", + get_log_header_with_length( + level, misc_helpers::get_date_time_string_with_milliseconds(), - level - )[..34] - .to_string() + HEADER_LENGTH, + ) +} + +fn get_log_header_with_length( + level: LoggerLevel, + date_time_string: String, + length: usize, +) -> String { + let header = format!("{date_time_string} [{level}] ") + .chars() + .take(length) + .collect::(); + + // padding if the header is shorter than HEADER_LENGTH + if header.len() < length { + let padding = " ".repeat(length - header.len()); + return format!("{header}{padding}"); + } + header } const ASYNC_FUNCTION_NAME: &str = "{closure"; @@ -117,4 +135,26 @@ mod tests { // Check if the caller name is as expected assert_eq!(caller_name, expected_caller_name); } + + #[test] + fn get_log_header_with_length_test() { + let header = super::get_log_header_with_length( + Level::Info, + "2023-10-01 12:00:00.000".to_string(), + 34, + ); + assert_eq!(header, "2023-10-01 12:00:00.000 [INFO] "); + let header = super::get_log_header_with_length( + Level::Error, + "2023-10-01 12:00:00.000".to_string(), + 34, + ); + assert_eq!(header, "2023-10-01 12:00:00.000 [ERROR] "); + let header = super::get_log_header_with_length( + Level::Warn, + "2023-10-01 12:00:00.00".to_string(), + 34, + ); + assert_eq!(header, "2023-10-01 12:00:00.00 [WARN] "); + } } From 83a111d1d6b53b0039323aa460fe1adcda1605a8 Mon Sep 17 00:00:00 2001 From: shahneerali <131208062+shahneerali@users.noreply.github.com> Date: Mon, 7 Jul 2025 15:34:23 -0700 Subject: [PATCH 12/12] Update Logic if ProxyAgent File Version in Extension is Empty (#254) * report err status * clippy+cargo * wait 15 sec * use curr seq no --- proxy_agent_extension/src/constants.rs | 2 +- proxy_agent_extension/src/service_main.rs | 47 ++++++++++++++--------- 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/proxy_agent_extension/src/constants.rs b/proxy_agent_extension/src/constants.rs index fbd9d1bc..b25f5e71 100644 --- a/proxy_agent_extension/src/constants.rs +++ b/proxy_agent_extension/src/constants.rs @@ -47,12 +47,12 @@ pub const WINDOWS_SUPPORTED_VERSIONS: &str = "10.0.17763"; pub const INVALID_FILE_VERSION: &str = "0.0.0.0"; pub const SERVICE_START_RETRY_COUNT: u32 = 5; pub const STATUS_CODE_OK: i32 = 0; +pub const STATUS_CODE_NOT_OK: i32 = 4; // Non zero exit codes pub const EXIT_CODE_HANDLER_ENV_ERR: i32 = 1; pub const EXIT_CODE_SERVICE_UPDATE_ERR: i32 = 2; pub const EXIT_CODE_SERVICE_INSTALL_ERR: i32 = 3; -pub const STATUS_CODE_NOT_OK: i32 = 4; pub const EXIT_CODE_SERVICE_UNINSTALL_ERR: i32 = 5; pub const EXIT_CODE_NOT_SUPPORTED_OS_VERSION: i32 = 6; pub const EXIT_CODE_SERVICE_START_ERR: i32 = 7; diff --git a/proxy_agent_extension/src/service_main.rs b/proxy_agent_extension/src/service_main.rs index 2a28c9cb..936f5338 100644 --- a/proxy_agent_extension/src/service_main.rs +++ b/proxy_agent_extension/src/service_main.rs @@ -75,7 +75,7 @@ async fn monitor_thread() { let handler_environment = common::get_handler_environment(&exe_path); let status_folder_path: PathBuf = handler_environment.statusFolder.to_string().into(); let mut cache_seq_no = String::new(); - let proxyagent_file_version_in_extension = get_proxy_agent_file_version_in_extension(); + let mut proxyagent_file_version_in_extension = String::new(); let mut service_state = ServiceState::default(); let mut status = StatusObj { name: constants::PLUGIN_NAME.to_string(), @@ -94,7 +94,33 @@ async fn monitor_thread() { let mut restored_in_error = false; let mut proxy_agent_update_reported: Option = None; loop { - let current_seq_no = common::get_current_seq_no(&exe_path); + let current_seq_no: String = common::get_current_seq_no(&exe_path); + if proxyagent_file_version_in_extension.is_empty() { + // File version of proxy agent service already downloaded by VM Agent + let path = common::get_proxy_agent_exe_path(); + proxyagent_file_version_in_extension = + match misc_helpers::get_proxy_agent_version(&path) { + Ok(version) => version, + Err(e) => { + let error_message = format!( + "Failed to get GuestProxyAgent version from file {} with error: {}", + misc_helpers::path_to_string(&path), + e + ); + logger::write(error_message.clone()); + status.formattedMessage.message = error_message; + status.code = constants::STATUS_CODE_NOT_OK; + status.status = status_state_obj.update_state(false); + common::report_status( + status_folder_path.to_path_buf(), + ¤t_seq_no, + &status, + ); + tokio::time::sleep(Duration::from_secs(15)).await; + continue; + } + }; + } if cache_seq_no != current_seq_no { telemetry::event_logger::write_event( LoggerLevel::Info, @@ -736,23 +762,6 @@ fn report_proxy_agent_service_status( } } -fn get_proxy_agent_file_version_in_extension() -> String { - // File version of proxy agent service already downloaded by VM Agent - let path = common::get_proxy_agent_exe_path(); - match misc_helpers::get_proxy_agent_version(&path) { - Ok(version) => version, - Err(e) => { - logger::write(format!( - "Failed to get GuestProxyAgent version from file {} with error: {}", - misc_helpers::path_to_string(&path), - e - )); - // return empty string if failed to get version - "".to_string() - } - } -} - // test report status #[cfg(test)] mod tests {