diff options
| author | Linus Färnstrand <linus@mullvad.net> | 2017-10-30 17:15:19 +0100 |
|---|---|---|
| committer | Linus Färnstrand <linus@mullvad.net> | 2017-10-30 17:15:19 +0100 |
| commit | 059e48363a20fe4680d9e7b46a9de463d2db11e2 (patch) | |
| tree | c5f8a8872de7354e66501f0de509ce288df438ee /mullvad-daemon/src | |
| parent | 3df28edf3258b3de877a14becac237e413978e02 (diff) | |
| download | mullvadvpn-059e48363a20fe4680d9e7b46a9de463d2db11e2.tar.xz mullvadvpn-059e48363a20fe4680d9e7b46a9de463d2db11e2.zip | |
Add daemon, os and kernel info to problem report
Diffstat (limited to 'mullvad-daemon/src')
| -rw-r--r-- | mullvad-daemon/src/bin/problem-report.rs | 80 |
1 files changed, 75 insertions, 5 deletions
diff --git a/mullvad-daemon/src/bin/problem-report.rs b/mullvad-daemon/src/bin/problem-report.rs index 8ecae0a0e5..447de8796f 100644 --- a/mullvad-daemon/src/bin/problem-report.rs +++ b/mullvad-daemon/src/bin/problem-report.rs @@ -10,6 +10,7 @@ extern crate clap; #[macro_use] extern crate error_chain; +extern crate sys_info; extern crate mullvad_rpc; @@ -19,6 +20,7 @@ use std::fmt; use std::fs::File; use std::io::{self, Read, Seek, SeekFrom, Write}; use std::path::{Path, PathBuf}; +use std::process::Command; /// Maximum number of bytes to read from each log file const LOG_MAX_READ_BYTES: usize = 5 * 1024 * 1024; @@ -48,10 +50,10 @@ error_chain!{ quick_main!(run); fn run() -> Result<()> { - let app = clap::App::new(crate_name!()) + let app = clap::App::new("problem-report") .version(crate_version!()) .author(crate_authors!()) - .about(crate_description!()) + .about("Mullvad VPN problem report tool. Collects logs and send them to Mullvad support.") .setting(clap::AppSettings::SubcommandRequired) .subcommand( clap::SubCommand::with_name("collect") @@ -121,7 +123,7 @@ fn run() -> Result<()> { } fn collect_report(log_paths: &[&Path], output_path: &Path) -> Result<()> { - let mut problem_report = ProblemReport::default(); + let mut problem_report = ProblemReport::new(); for log_path in log_paths { problem_report.add_log(log_path); } @@ -149,15 +151,32 @@ fn write_problem_report(path: &Path, problem_report: ProblemReport) -> io::Resul Ok(()) } -#[derive(Debug, Default)] + +#[derive(Debug)] struct ProblemReport { + system_info: Vec<String>, logs: Vec<(String, String)>, } impl ProblemReport { + pub fn new() -> Self { + ProblemReport { + system_info: Self::collect_system_info(), + logs: Vec::new(), + } + } + + fn collect_system_info() -> Vec<String> { + vec![ + format!("Mullvad daemon: {}", daemon_version()), + format!("OS: {}", os_version()), + format!("Kernel: {}", kernel_version()), + ] + } + /// Attach file log to this report. This method uses the error chain instead of log /// contents if error occurred when reading log file. - fn add_log(&mut self, path: &Path) { + pub fn add_log(&mut self, path: &Path) { let content = read_file_lossy(path, LOG_MAX_READ_BYTES) .chain_err(|| ErrorKind::ReadLogError(path.to_path_buf())) .unwrap_or_else(|e| e.display_chain().to_string()); @@ -168,6 +187,11 @@ impl ProblemReport { impl fmt::Display for ProblemReport { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + writeln!(fmt, "System information:")?; + for system_info in &self.system_info { + writeln!(fmt, "{}", system_info)?; + } + writeln!(fmt, "")?; for &(ref label, ref content) in &self.logs { writeln!(fmt, "{}", LOG_DELIMITER)?; writeln!(fmt, "Log: {}", label)?; @@ -194,3 +218,49 @@ fn read_file_lossy(path: &Path, max_bytes: usize) -> io::Result<String> { file.take(max_bytes as u64).read_to_end(&mut buffer)?; Ok(String::from_utf8_lossy(&buffer).into_owned()) } + +fn daemon_version() -> String { + format!( + "v{} {}", + env!("CARGO_PKG_VERSION"), + include_str!(concat!(env!("OUT_DIR"), "/git-commit-info.txt")) + ) +} + +fn kernel_version() -> String { + sys_info::os_release().unwrap_or(String::from("Unknown")) +} + +#[cfg(target_os = "linux")] +fn os_version() -> String { + format!( + "Linux, {}", + command_stdout_lossy("lsb_release", &["-ds"]) + .unwrap_or(String::from("[Failed to get LSB release]")) + ) +} + +#[cfg(target_os = "macos")] +fn os_version() -> String { + format!( + "macOS {}", + command_stdout_lossy("sw_vers", &["-productVersion"]) + .unwrap_or(String::from("[Failed to detect version]")) + ) +} + +#[cfg(windows)] +fn os_version() -> String { + String::from("Windows") +} + +/// Helper for getting stdout of some command as a String. Ignores the exit code of the command. +fn command_stdout_lossy(cmd: &str, args: &[&str]) -> Option<String> { + Command::new(cmd) + .args(args) + .output() + .map(|output| { + String::from_utf8_lossy(&output.stdout).trim().to_string() + }) + .ok() +} |
