From 802d4979c6e1d7ea68ad5bc2f034a7827765d959 Mon Sep 17 00:00:00 2001 From: naman-monga Date: Thu, 17 Oct 2024 14:34:12 +0530 Subject: [PATCH 1/8] replaced a localized log counter in capture logs with a global arc based mutex counter --- src/enclave_monitor.rs | 14 +++++++++----- src/http_server.rs | 26 +++++++++++++++++++++----- src/main.rs | 10 +++++++--- 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/src/enclave_monitor.rs b/src/enclave_monitor.rs index 02a5243..18a3f91 100644 --- a/src/enclave_monitor.rs +++ b/src/enclave_monitor.rs @@ -2,20 +2,23 @@ use crate::logging::log_message; use anyhow::{bail, Context}; use serde_json::Value; use std::process::Stdio; +use std::sync::Arc; use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader}; use tokio::process::Command; -use tokio::sync::broadcast; +use tokio::sync::{broadcast, Mutex}; pub async fn monitor_and_capture_logs( sse_tx: &broadcast::Sender, enclave_log_file_path: &str, script_log_file_path: &str, target_cid: u64, + log_counter: Arc>, ) -> anyhow::Result<()> { loop { let enclave_id = wait_for_enclave_with_cid(target_cid) .await .context("Error in wait for enclave with cid call")?; + let log_counter = log_counter.clone(); log_message( script_log_file_path, &format!( @@ -29,6 +32,7 @@ pub async fn monitor_and_capture_logs( &enclave_id, enclave_log_file_path, script_log_file_path, + log_counter ) .await { @@ -76,6 +80,7 @@ async fn capture_logs( enclave_id: &str, enclave_log_file_path: &str, script_log_file_path: &str, + log_counter: Arc>, ) -> anyhow::Result<()> { let mut child = Command::new("nitro-cli") .args(["console", "--enclave-id", enclave_id]) @@ -83,8 +88,6 @@ async fn capture_logs( .spawn() .context("Failed to spawn nitro-cli process")?; - let mut log_id_counter: u64 = 0; - // Open the file asynchronously let mut file = tokio::fs::OpenOptions::new() .create(true) @@ -95,9 +98,10 @@ async fn capture_logs( let stdout = child.stdout.take().expect("Failed to capture stdout"); let mut reader = BufReader::new(stdout).lines(); + let mut log_counter = log_counter.lock().await; while let Some(line) = reader.next_line().await? { - let log_entry = format!("[{}] {}", log_id_counter, line); + let log_entry = format!("[{}] {}", *log_counter, line); { file.write_all(log_entry.as_bytes()).await?; @@ -109,7 +113,7 @@ async fn capture_logs( println!("No active SSE subscribers, skipping log transmission."); } - log_id_counter += 1; + *log_counter += 1; } let status = child.wait().await?; diff --git a/src/http_server.rs b/src/http_server.rs index f647042..6d723f7 100644 --- a/src/http_server.rs +++ b/src/http_server.rs @@ -1,10 +1,10 @@ use anyhow::{anyhow, Context}; use serde_json::json; -use std::collections::HashMap; +use std::{collections::HashMap, sync::Arc}; use std::convert::Infallible; use tokio::{ fs::File, - io::{AsyncBufReadExt, BufReader}, + io::{AsyncBufReadExt, BufReader}, sync::Mutex, }; use warp::{http::Method, Filter}; @@ -50,24 +50,40 @@ pub async fn fetch_logs_with_offset( pub fn create_routes( enclave_log_file_path: String, sse_tx: tokio::sync::broadcast::Sender, + log_counter: Arc> ) -> impl Filter + Clone { let logs_file = enclave_log_file_path.clone(); + let log_counter1 = log_counter.clone(); + let log_counter2 = log_counter.clone(); let home_html = include_str!("../assets/logs.html"); let home_route = warp::path("logs") .and(warp::get()) .map(move || warp::reply::html(home_html)); + let tail_log_route = warp::path("logs") + .and(warp::path("tail-log-id")) + .and(warp::get()) + .and_then(move || { + let log_counter = log_counter1.clone(); + async move { + let latest_log_id = log_counter.lock().await; + Ok::<_, Infallible>(warp::reply::json(&json!({"log_id": *latest_log_id}))) + } + }); + let history_route = warp::path("logs") .and(warp::path("history")) .and(warp::query::>()) - .and_then(move |params: HashMap| { + .and_then( move |params: HashMap| { let logs_file = logs_file.clone(); + let log_counter = log_counter2.clone(); async move { + let latest_log_id = log_counter.lock().await; let log_id = params .get("log_id") .and_then(|id| id.parse::().ok()) - .unwrap_or(1); + .unwrap_or(*latest_log_id); let offset = params .get("offset") @@ -127,5 +143,5 @@ pub fn create_routes( Method::HEAD, ]); - history_route.or(sse_route).or(home_route).with(cors) + history_route.or(tail_log_route).or(sse_route).or(home_route).with(cors) } diff --git a/src/main.rs b/src/main.rs index 0b98fa2..52f88cd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,16 +3,19 @@ mod enclave_monitor; mod http_server; mod logging; +use std::sync::Arc; + use anyhow::Context; use args::Args; use clap::Parser; use enclave_monitor::monitor_and_capture_logs; use logging::{clear_log_file, log_message}; -use tokio::sync::broadcast; +use tokio::sync::{broadcast, Mutex}; #[tokio::main] async fn main() -> anyhow::Result<()> { let args = Args::parse(); + let log_counter: Arc> = Arc::new(Mutex::new(0)); clear_log_file(&args.enclave_log_file_path) .await @@ -30,10 +33,11 @@ async fn main() -> anyhow::Result<()> { let script_log_file = args.script_log_file_path.clone(); let enclave_log_file = args.enclave_log_file_path.clone(); let target_cid = args.target_cid; + let log_counter = Arc::clone(&log_counter); tokio::task::spawn(async move { if let Err(e) = - monitor_and_capture_logs(&sse_tx, &enclave_log_file, &script_log_file, target_cid) + monitor_and_capture_logs(&sse_tx, &enclave_log_file, &script_log_file, target_cid, log_counter) .await { // Ensure you await the async function @@ -46,7 +50,7 @@ async fn main() -> anyhow::Result<()> { }); } - let routes = http_server::create_routes(args.enclave_log_file_path.clone(), sse_tx.clone()); + let routes = http_server::create_routes(args.enclave_log_file_path.clone(), sse_tx.clone(),log_counter); log_message( &args.script_log_file_path, From 116fea680a7ff9ded0d4e1b0dd41679e5787b306 Mon Sep 17 00:00:00 2001 From: naman-monga Date: Thu, 17 Oct 2024 14:51:46 +0530 Subject: [PATCH 2/8] moved lock to correct scope --- src/enclave_monitor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/enclave_monitor.rs b/src/enclave_monitor.rs index 18a3f91..5fc5066 100644 --- a/src/enclave_monitor.rs +++ b/src/enclave_monitor.rs @@ -98,9 +98,9 @@ async fn capture_logs( let stdout = child.stdout.take().expect("Failed to capture stdout"); let mut reader = BufReader::new(stdout).lines(); - let mut log_counter = log_counter.lock().await; while let Some(line) = reader.next_line().await? { + let mut log_counter = log_counter.lock().await; let log_entry = format!("[{}] {}", *log_counter, line); { From a928efaf6bae92ee7de0915c33e4c6e96cc9e195 Mon Sep 17 00:00:00 2001 From: naman-monga Date: Thu, 17 Oct 2024 15:16:49 +0530 Subject: [PATCH 3/8] updated readme --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9d83468..5a46cd3 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,8 @@ A simple and efficient logging server designed to run inside the host machine to stream logs from the AWS Nitro Enclave. 1. GET `logs/stream` -- Creates an SSE connection which can be listened by the client to access realtime logs -2. GET `/logs/history?log_id=50&offset=10` -- Responds with the logs starting with `offset` number of logs starting from log id = `log_id-1` +2. GET `/logs/history?log_id=50&offset=10` -- Responds with the logs starting with `offset` number of logs starting from log id = `log_id-1`. Omitting log_id param will provide latest printed offset number of logs. +3. GET `logs/tail-log-id` -- Responnds with the id of the last received log 3. GET `/logs` -- Server html file in response to both stream and view log history out of the box ### Building the Server From 286af672d14ee2424c3cd244db7f8663d6b367d4 Mon Sep 17 00:00:00 2001 From: naman-monga Date: Thu, 17 Oct 2024 18:17:45 +0530 Subject: [PATCH 4/8] updated logs html --- assets/logs.html | 214 ++++++++++++++++++++++++++++------------------- 1 file changed, 127 insertions(+), 87 deletions(-) diff --git a/assets/logs.html b/assets/logs.html index 420e7b1..7168074 100644 --- a/assets/logs.html +++ b/assets/logs.html @@ -1,20 +1,17 @@ - - - - View Logs - - - - - -
    + + View Logs + + + + + + +
      - -
    - - - startLogs(`http://${window.location.hostname}:${PORT}`); - \ No newline at end of file From e64299964ea166cbbcd3f2ca8a2b6c95f110991c Mon Sep 17 00:00:00 2001 From: naman-monga Date: Thu, 17 Oct 2024 18:26:54 +0530 Subject: [PATCH 5/8] cargo formatting --- src/enclave_monitor.rs | 2 +- src/http_server.rs | 15 ++++++++++----- src/main.rs | 17 +++++++++++++---- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/enclave_monitor.rs b/src/enclave_monitor.rs index 5fc5066..a9aa2b8 100644 --- a/src/enclave_monitor.rs +++ b/src/enclave_monitor.rs @@ -32,7 +32,7 @@ pub async fn monitor_and_capture_logs( &enclave_id, enclave_log_file_path, script_log_file_path, - log_counter + log_counter, ) .await { diff --git a/src/http_server.rs b/src/http_server.rs index 6d723f7..0698534 100644 --- a/src/http_server.rs +++ b/src/http_server.rs @@ -1,10 +1,11 @@ use anyhow::{anyhow, Context}; use serde_json::json; -use std::{collections::HashMap, sync::Arc}; use std::convert::Infallible; +use std::{collections::HashMap, sync::Arc}; use tokio::{ fs::File, - io::{AsyncBufReadExt, BufReader}, sync::Mutex, + io::{AsyncBufReadExt, BufReader}, + sync::Mutex, }; use warp::{http::Method, Filter}; @@ -50,7 +51,7 @@ pub async fn fetch_logs_with_offset( pub fn create_routes( enclave_log_file_path: String, sse_tx: tokio::sync::broadcast::Sender, - log_counter: Arc> + log_counter: Arc>, ) -> impl Filter + Clone { let logs_file = enclave_log_file_path.clone(); let log_counter1 = log_counter.clone(); @@ -75,7 +76,7 @@ pub fn create_routes( let history_route = warp::path("logs") .and(warp::path("history")) .and(warp::query::>()) - .and_then( move |params: HashMap| { + .and_then(move |params: HashMap| { let logs_file = logs_file.clone(); let log_counter = log_counter2.clone(); async move { @@ -143,5 +144,9 @@ pub fn create_routes( Method::HEAD, ]); - history_route.or(tail_log_route).or(sse_route).or(home_route).with(cors) + history_route + .or(tail_log_route) + .or(sse_route) + .or(home_route) + .with(cors) } diff --git a/src/main.rs b/src/main.rs index 52f88cd..14d4f21 100644 --- a/src/main.rs +++ b/src/main.rs @@ -36,9 +36,14 @@ async fn main() -> anyhow::Result<()> { let log_counter = Arc::clone(&log_counter); tokio::task::spawn(async move { - if let Err(e) = - monitor_and_capture_logs(&sse_tx, &enclave_log_file, &script_log_file, target_cid, log_counter) - .await + if let Err(e) = monitor_and_capture_logs( + &sse_tx, + &enclave_log_file, + &script_log_file, + target_cid, + log_counter, + ) + .await { // Ensure you await the async function let _ = log_message( @@ -50,7 +55,11 @@ async fn main() -> anyhow::Result<()> { }); } - let routes = http_server::create_routes(args.enclave_log_file_path.clone(), sse_tx.clone(),log_counter); + let routes = http_server::create_routes( + args.enclave_log_file_path.clone(), + sse_tx.clone(), + log_counter, + ); log_message( &args.script_log_file_path, From d5ad73b15ef7e4d7fc8be5efbe8e3ac29f3c3731 Mon Sep 17 00:00:00 2001 From: Naman Monga <42845908+Naman-Monga@users.noreply.github.com> Date: Thu, 17 Oct 2024 18:32:13 +0530 Subject: [PATCH 6/8] Minor update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5a46cd3..1cd6750 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A simple and efficient logging server designed to run inside the host machine to 1. GET `logs/stream` -- Creates an SSE connection which can be listened by the client to access realtime logs 2. GET `/logs/history?log_id=50&offset=10` -- Responds with the logs starting with `offset` number of logs starting from log id = `log_id-1`. Omitting log_id param will provide latest printed offset number of logs. 3. GET `logs/tail-log-id` -- Responnds with the id of the last received log -3. GET `/logs` -- Server html file in response to both stream and view log history out of the box +4. GET `/logs` -- Server html file in response to both stream and view log history out of the box ### Building the Server From 44a87124967245f87b3264b905e81fb92068404e Mon Sep 17 00:00:00 2001 From: naman-monga Date: Fri, 18 Oct 2024 16:51:16 +0530 Subject: [PATCH 7/8] updated logs html --- assets/logs.html | 235 ++++++++++++++++++++++------------------------- 1 file changed, 112 insertions(+), 123 deletions(-) diff --git a/assets/logs.html b/assets/logs.html index 7168074..0d40c21 100644 --- a/assets/logs.html +++ b/assets/logs.html @@ -1,17 +1,20 @@ - - - - - View Logs - - - - - - -
      + + View Logs + + + + + +
        - -
      - - + lastScrollTop = scrollTop; + }); + startLogs(`http://${window.location.hostname}:${PORT}`); + \ No newline at end of file From 7bccb26a0cc5597ad21659a06e271bd9956812cd Mon Sep 17 00:00:00 2001 From: Naman Monga <42845908+Naman-Monga@users.noreply.github.com> Date: Tue, 22 Oct 2024 17:17:50 +0530 Subject: [PATCH 8/8] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1cd6750..c18fa82 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,9 @@ A simple and efficient logging server designed to run inside the host machine to stream logs from the AWS Nitro Enclave. 1. GET `logs/stream` -- Creates an SSE connection which can be listened by the client to access realtime logs -2. GET `/logs/history?log_id=50&offset=10` -- Responds with the logs starting with `offset` number of logs starting from log id = `log_id-1`. Omitting log_id param will provide latest printed offset number of logs. -3. GET `logs/tail-log-id` -- Responnds with the id of the last received log -4. GET `/logs` -- Server html file in response to both stream and view log history out of the box +2. GET `/logs/history?log_id=50&offset=10` -- Responds with the logs starting with `offset` number of logs starting from log id = `log_id-1`. Omitting log_id param will provide latest produced offset number of logs. +3. GET `logs/tail-log-id` -- Responds with the id of the last received log +4. GET `/logs` -- Renders html page to both stream logs realtime and retrieve existing logs. ### Building the Server