Skip to content

Commit 04611e6

Browse files
committed
feat(diagnostics): add installer log to diagnostics ZIP and pretty-print all JSON files
The NSIS post-install hook now writes rigstats-install.log to the app\ndata directory (%APPDATA%\\se.codeby.rigstats\\), capturing the selected\nLHM executable path and exit codes for the config copy and scheduled\ntask registration steps. The diagnostics ZIP includes this file as\ninstall.log so installer failures are visible in bug reports.\n\nAll JSON files in the ZIP are now pretty-printed: manifest.json was\nrewritten using serde_json::json!, hardware.json had -Compress removed\nfrom the PowerShell script, and lhm-data.json is re-parsed via a new\npretty_json() helper before writing. Files that were already using\nto_string_pretty are unchanged.\n\ndocs/architecture.md updated with install.log and displays.json entries\nin the diagnostics table, and setup.md updated to remove the outdated\nmanual Task Scheduler instructions for autostart.
1 parent 4165637 commit 04611e6

3 files changed

Lines changed: 49 additions & 11 deletions

File tree

build/installer.nsh

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
!include "FileFunc.nsh"
22

33
!macro NSIS_HOOK_POSTINSTALL
4+
; Open install log in the app data directory so it can be included in diagnostics.
5+
CreateDirectory "$APPDATA\se.codeby.rigstats"
6+
FileOpen $9 "$APPDATA\se.codeby.rigstats\rigstats-install.log" w
7+
FileWrite $9 "[RIGStats post-install]$\r$\n"
8+
49
; Prefer an existing LibreHardwareMonitor installation if present.
510
; Fallback to bundled LHM inside RigStats installation directory.
611
StrCpy $0 "$INSTDIR\\lhm\\LibreHardwareMonitor.exe"
@@ -14,14 +19,21 @@
1419
IfFileExists "$LOCALAPPDATA\\Programs\\LibreHardwareMonitor\\LibreHardwareMonitor.exe" 0 +2
1520
StrCpy $0 "$LOCALAPPDATA\\Programs\\LibreHardwareMonitor\\LibreHardwareMonitor.exe"
1621

22+
FileWrite $9 "lhm_exe=$0$\r$\n"
23+
1724
; Apply default config to the selected LHM installation (existing or bundled).
1825
; This enables the web server on port 8085 without manual setup.
19-
IfFileExists "$INSTDIR\\lhm\\defaults\\LibreHardwareMonitor.config" 0 +9
26+
IfFileExists "$INSTDIR\\lhm\\defaults\\LibreHardwareMonitor.config" 0 no_bundled_config
2027
${GetParent} "$0" $1
2128
IfFileExists "$1\\LibreHardwareMonitor.config" 0 +3
2229
Delete "$1\\LibreHardwareMonitor.config.backup"
2330
Rename "$1\\LibreHardwareMonitor.config" "$1\\LibreHardwareMonitor.config.backup"
24-
nsExec::ExecToLog 'cmd /C copy /Y "$INSTDIR\lhm\defaults\LibreHardwareMonitor.config" "$1\LibreHardwareMonitor.config"'
31+
nsExec::ExecToStack 'cmd /C copy /Y "$INSTDIR\lhm\defaults\LibreHardwareMonitor.config" "$1\LibreHardwareMonitor.config"'
32+
Pop $4
33+
Pop $5
34+
DetailPrint "LHM config copy: exit $4"
35+
FileWrite $9 "config_copy_exit=$4$\r$\n"
36+
no_bundled_config:
2537

2638
; Create or update scheduled task for LibreHardwareMonitor at any user logon.
2739
; Uses PowerShell Register-ScheduledTask without -UserId so the trigger fires for
@@ -38,14 +50,21 @@
3850
FileWrite $3 "$$p = New-ScheduledTaskPrincipal -GroupId 'S-1-5-32-545' -RunLevel Highest$\r$\n"
3951
FileWrite $3 "Register-ScheduledTask -TaskName 'LibreHardwareMonitor' -Action $$a -Trigger $$t -Settings $$s -Principal $$p -Force$\r$\n"
4052
FileClose $3
41-
nsExec::ExecToLog 'powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "$TEMP\create-lhm-task.ps1"'
53+
nsExec::ExecToStack 'powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "$TEMP\create-lhm-task.ps1"'
54+
Pop $4
55+
Pop $5
56+
DetailPrint "LHM task register: exit $4"
57+
FileWrite $9 "lhm_task_register_exit=$4$\r$\n"
4258
Delete "$TEMP\create-lhm-task.ps1"
4359

4460
; Run LHM directly in the installer's admin context so PawnIO (kernel driver) is
4561
; installed on first use. The user will see a PawnIO prompt and should click Yes.
4662
; Using Exec (non-blocking) so the installer can finish while LHM initialises.
4763
DetailPrint "Starting LibreHardwareMonitor — click Yes if asked about PawnIO installation."
64+
FileWrite $9 "lhm_started=1$\r$\n"
4865
Exec "$\"$0$\""
66+
67+
FileClose $9
4968
!macroend
5069

5170
!macro NSIS_HOOK_POSTUNINSTALL

docs/architecture.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,9 @@ It produces a self-contained ZIP for bug reports and sensor-support work.
7575
| `hardware.json` | `diag_collect_hardware()` — PowerShell `Get-CimInstance` | OS, CPU, GPU, board, RAM |
7676
| `sched-task.txt` | `diag_collect_tasks()``schtasks /Query /V` | Both LHM task names |
7777
| `environment.txt` | `diag_collect_environment()` — env vars + Windows registry | Arch, build, hostname |
78+
| `install.log` | `diag_collect_installer_log()` — reads `rigstats-install.log` from app data dir | Written by the NSIS installer; contains LHM exe path and task registration exit codes |
7879
| `sysinfo.json` | `diag_collect_sysinfo()` — reads shared `AppState` mutexes | CPU brand, RAM totals, mount points, interfaces |
80+
| `displays.json` | `diag_collect_displays()` — reads available monitors via Tauri | Each monitor's resolution, position, scale factor, fit score, and which one was selected for the current profile |
7981

8082
---
8183

src-tauri/src/diagnostics.rs

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,16 @@ use serde::Serialize;
1111
use std::io::Write;
1212
use std::time::{Duration, SystemTime, UNIX_EPOCH};
1313

14+
// --- Helpers ---------------------------------------------------------------
15+
16+
/// Re-parses a JSON string and returns it pretty-printed.
17+
/// Falls back to the original string if it isn't valid JSON.
18+
fn pretty_json(s: &str) -> String {
19+
serde_json::from_str::<serde_json::Value>(s)
20+
.and_then(|v| serde_json::to_string_pretty(&v))
21+
.unwrap_or_else(|_| s.to_string())
22+
}
23+
1424
// --- Data collection helpers -----------------------------------------------
1525

1626
fn diag_collect_hardware() -> String {
@@ -31,7 +41,7 @@ fn diag_collect_hardware() -> String {
3141
"gpu=@($gpu|%{@{name=$_.Name;ramBytes=$_.AdapterRAM;driver=$_.DriverVersion}});",
3242
"board=@{csMfr=$cs.Manufacturer;csModel=$cs.Model;bbMfr=$bb.Manufacturer;bbProd=$bb.Product;cspName=$csp.Name;cspVer=$csp.Version};",
3343
"ram=@($mem|%{@{capBytes=$_.Capacity;speed=$_.Speed;configured=$_.ConfiguredClockSpeed;typeCode=$_.SMBIOSMemoryType;mfr=$_.Manufacturer;part=$_.PartNumber}})",
34-
"}|ConvertTo-Json -Depth 4 -Compress",
44+
"}|ConvertTo-Json -Depth 4",
3545
"}catch{'{ \"error\": \"collection failed\" }'}"
3646
);
3747
match run_hidden_command("powershell", &["-NoProfile", "-Command", script]) {
@@ -134,6 +144,11 @@ struct SysinfoSnapshot {
134144
ping_target: String,
135145
}
136146

147+
fn diag_collect_installer_log(app: &tauri::AppHandle) -> Vec<u8> {
148+
let path = debug_log_path(app).with_file_name("rigstats-install.log");
149+
std::fs::read(path).unwrap_or_else(|_| b"(install log not found)".to_vec())
150+
}
151+
137152
fn diag_collect_sysinfo(state: &AppState) -> String {
138153
let (cpu_brand, cpu_count, total_memory_mb, used_memory_mb) = {
139154
let system = state.system.lock().unwrap_or_else(|e| e.into_inner());
@@ -286,11 +301,11 @@ pub async fn collect_diagnostics(
286301
return Ok(None); // user cancelled
287302
};
288303

289-
let manifest = format!(
290-
"{{\"collected_at_unix\":{},\"rigstats_version\":\"{}\"}}",
291-
ts,
292-
env!("CARGO_PKG_VERSION")
293-
);
304+
let manifest = serde_json::to_string_pretty(&serde_json::json!({
305+
"collected_at_unix": ts,
306+
"rigstats_version": env!("CARGO_PKG_VERSION"),
307+
}))
308+
.unwrap_or_default();
294309

295310
let log_bytes = std::fs::read(debug_log_path(&app)).unwrap_or_else(|_| b"(log not found)".to_vec());
296311

@@ -307,14 +322,15 @@ pub async fn collect_diagnostics(
307322
.send()
308323
.await
309324
{
310-
Ok(resp) => resp.text().await.unwrap_or_else(|e| format!("{{\"error\":\"body: {}\"}}", e)),
325+
Ok(resp) => pretty_json(&resp.text().await.unwrap_or_else(|e| format!("{{\"error\":\"body: {}\"}}", e))),
311326
Err(e) => format!("{{\"error\":\"request: {}\"}}", e),
312327
};
313328

314-
let hardware_json = diag_collect_hardware();
329+
let hardware_json = pretty_json(&diag_collect_hardware());
315330
let tasks_txt = diag_collect_tasks();
316331
let env_txt = diag_collect_environment();
317332
let sysinfo_json = diag_collect_sysinfo(&state);
333+
let install_log_bytes = diag_collect_installer_log(&app);
318334
let displays_json = {
319335
let profile = state.settings.lock().unwrap_or_else(|e| e.into_inner()).dashboard_profile.clone();
320336
diag_collect_displays(&app, &profile)
@@ -328,6 +344,7 @@ pub async fn collect_diagnostics(
328344
let entries: &[(&str, &[u8])] = &[
329345
("manifest.json", manifest.as_bytes()),
330346
("debug.log", &log_bytes),
347+
("install.log", &install_log_bytes),
331348
("settings.json", settings_json.as_bytes()),
332349
("lhm-data.json", lhm_json.as_bytes()),
333350
("hardware.json", hardware_json.as_bytes()),

0 commit comments

Comments
 (0)