Always-on service events log + show failure reasons on screen

So that if the service breaks on a machine where nobody enabled logging first
(e.g. a Win7 tester), we still learn WHY:

- New always-on ServiceStore.AppendServiceEvent -> service-events.log in
  ProgramData, independent of any logging toggle (like the update log).
- Service menu status-query failure now shows the actual reason IN the status
  line (a screen reader reads it) AND records it to the events log, instead of a
  bare 'status unavailable' whose reason only went to the off-by-default app log.
- ServiceAction (install/uninstall/start/stop) records request + outcome to the
  events log.
- ServiceEntry (the elevated child) logs each verb's start, and CATCHES a
  System.ServiceProcess load failure to record its reason before rethrowing (so
  the crash file still gets the full stack) — this is the likely Win7 failure.
- 'View service log' falls back to the events log when no runtime diagnostic log
  exists, so there's always something to view after any service interaction.

Recap of coverage: hard crashes -> crash-*.txt (always, no setup). Graceful
service failures -> now the events log + on-screen reason (no setup). Gate 35/35.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Ednunp
2026-07-15 19:08:49 +01:00
co-authored by Claude Opus 4.8
parent 4d1815e071
commit 5129aa2a39
4 changed files with 74 additions and 11 deletions
+6 -1
View File
@@ -1340,7 +1340,12 @@ internal static class SelfTest
File.SetLastWriteTimeUtc(older, new DateTime(2020, 1, 1, 0, 0, 0, DateTimeKind.Utc));
File.SetLastWriteTimeUtc(newer, new DateTime(2020, 1, 2, 0, 0, 0, DateTimeKind.Utc));
Check(ServiceStore.NewestLogFile() == newer, "NewestLogFile must return the most recently written .log");
return "log folder resolves under the service data dir; newest .log is found; empty case handled";
// Always-on service events log: writes without any toggle, and is where a Win7 failure reason lands.
ServiceStore.AppendServiceEvent("selftest: install THREW FileLoadException: could not load System.ServiceProcess");
Check(File.Exists(ServiceStore.ServiceEventsLogPath), "AppendServiceEvent must write even with no logging enabled");
Check(File.ReadAllText(ServiceStore.ServiceEventsLogPath).Contains("install THREW"), "the service events log must contain the recorded event");
return "log folder resolves; newest .log found; empty case handled; always-on events log records without a toggle";
}
finally
{