Browse Source

cli: Stream program logs to file when testing

Armani Ferrante 4 years ago
parent
commit
ce5ca7ddab
2 changed files with 39 additions and 0 deletions
  1. 1 0
      CHANGELOG.md
  2. 38 0
      cli/src/main.rs

+ 1 - 0
CHANGELOG.md

@@ -12,6 +12,7 @@ incremented for features.
 ## [Unreleased]
 
 * cli: Embed workspace programs into local validator genesis when testing.
+* cli: Stream program logs to `.anchor/program-logs` directory when testing.
 
 ## [0.2.0] - 2021-02-08
 

+ 38 - 0
cli/src/main.rs

@@ -603,6 +603,8 @@ fn test(skip_deploy: bool) -> Result<()> {
             }
         };
 
+        let log_streams = stream_logs(&cfg.cluster.url())?;
+
         // Run the tests.
         if let Err(e) = std::process::Command::new("mocha")
             .arg("-t")
@@ -622,6 +624,10 @@ fn test(skip_deploy: bool) -> Result<()> {
             validator_handle.kill()?;
         }
 
+        for mut stream in log_streams {
+            stream.kill()?;
+        }
+
         Ok(())
     })
 }
@@ -652,6 +658,38 @@ fn genesis_flags() -> Result<Vec<String>> {
     Ok(flags)
 }
 
+fn stream_logs(url: &str) -> Result<Vec<std::process::Child>> {
+    let program_logs_dir = ".anchor/program-logs";
+    if Path::new(program_logs_dir).exists() {
+        std::fs::remove_dir_all(program_logs_dir)?;
+    }
+    fs::create_dir_all(program_logs_dir)?;
+    let mut handles = vec![];
+    for program in read_all_programs()? {
+        let mut file = File::open(&format!("target/idl/{}.json", program.lib_name))?;
+        let mut contents = vec![];
+        file.read_to_end(&mut contents)?;
+        let idl: Idl = serde_json::from_slice(&contents)?;
+        let metadata = idl.metadata.ok_or(anyhow!("Program address not found."))?;
+        let metadata: IdlTestMetadata = serde_json::from_value(metadata)?;
+
+        let log_file = File::create(format!(
+            "{}/{}.{}.log",
+            program_logs_dir, metadata.address, program.idl.name
+        ))?;
+        let stdio = std::process::Stdio::from(log_file);
+        let child = std::process::Command::new("solana")
+            .arg("logs")
+            .arg(metadata.address)
+            .arg("--url")
+            .arg(url)
+            .stdout(stdio)
+            .spawn()?;
+        handles.push(child);
+    }
+    Ok(handles)
+}
+
 #[derive(Debug, Serialize, Deserialize)]
 pub struct IdlTestMetadata {
     address: String,