From fcfdaa3bef709d759a5a6d0ce4e268d54eab55e7 Mon Sep 17 00:00:00 2001 From: Stephan Yelle Date: Sat, 31 Jan 2026 17:53:45 -0500 Subject: [PATCH] Add docs/logging.fallback.md --- docs/logging.fallback.md | 137 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 docs/logging.fallback.md diff --git a/docs/logging.fallback.md b/docs/logging.fallback.md new file mode 100644 index 0000000..e74bd16 --- /dev/null +++ b/docs/logging.fallback.md @@ -0,0 +1,137 @@ +# logging.fallback.ps1 + +This file implements SAMY’s fallback logging functions used across the project. + +It supports: +- Console logging (color-coded) +- In-memory log caching (for UI/diagnostics) +- Optional file logging (UTF-8 **without BOM**) +- Optional Windows Event Log logging, including: + - first-run creation of the log/source (when elevated) + - resolving “source bound to the wrong log” problems + +--- + +## Regions overview + +### Globals +**What it does** +- Initializes shared global state used by logging: + - `LogCache`: an `ArrayList` of log entries created during execution. + - `EventSinkCache`: a `Hashtable` caching resolved Event Log sinks so we do not repeatedly initialize/bind. + +**Why it exists** +- Makes log output available to UI or post-run summaries. +- Prevents repeated Event Log setup attempts and repeated warnings. + +--- + +### Helpers: Formatting + File +**What it does** +- `Get-LogColor(Level)`: maps `Info/Warning/Error/Success/General` to console colors. +- `Get-EventIdForLevel(Level, CustomEventID)`: returns default Event IDs by level unless overridden. +- `Get-EventEntryTypeForLevel(Level)`: maps levels to Event Log entry types. +- `Append-Utf8NoBomLine(Path, Line)`: appends a line to a file using UTF-8 **without BOM**. + +**Why it exists** +- Keeps the main logging functions readable. +- Ensures runtime log files comply with the repository encoding rule (UTF-8 no BOM). + +--- + +### Helpers: Event Log Binding +**Background** +Windows Event Log has a key constraint: + +A **Source** can only be registered to **one** Log at a time. + +Example: +- If source `SVMSP_Module` is registered to `Application`, + you cannot write with: + `Write-EventLog -LogName "SVSMSP Events" -Source "SVMSP_Module"` + until that binding is repaired or avoided. + +**What it does** +- `Test-IsAdmin()`: checks if the current PowerShell session is elevated. +- `Initialize-EventLogBinding(DesiredLog, DesiredSource, ConflictPolicy)`: + returns an effective `{ LogName, Source, IsAdmin }` that is safe to use for `Write-EventLog`. + +**ConflictPolicy** +If `DesiredSource` exists but is bound to a different log, one of these policies applies: + +- `Repair` (default) + - Removes the existing source registration from its current log + - Recreates it under `DesiredLog` + - Requires elevation + - Best when you want **all SAMY logs in one custom log** + +- `Unique` + - Creates a new SAMY-specific source under `DesiredLog` + (e.g., `SVMSP_Module.SAMY`, `SVMSP_Module.SAMY2`, etc.) + - Does not delete anything + - Requires elevation to create the new source + - Best when you want **no deletion / no rebinding risk** + +- `Follow` + - Uses whichever log the source is already bound to + - Never deletes anything + - May log to `Application` if that’s where the source already exists + - Best when you want **maximum safety and minimum changes** + +**Non-admin behavior** +If not elevated and the desired source does not exist, the code falls back to: +- `LogName = Application` +- `Source = Windows PowerShell` + +This avoids trying to create custom Event Log sources without admin rights. + +--- + +### Public: Write-LogHelper +**What it does** +This is the core fallback logger. + +Always does: +- Writes a formatted message to console (with color) +- Adds an entry to `Global:LogCache` + +Optionally does: +- File logging (when `-LogFile` is provided) +- Event Log logging (when `-LogToEvent` is set) + +**Event Log caching** +To avoid repeating setup work, the function caches the resolved Event Log sink: +- Key format: `"$EventLog|$EventSource|$EventLogConflictPolicy"` +- Cached value includes: + - `Ready` (boolean) + - `LogName` (effective log to write to) + - `Source` (effective source to write with) + +**Parameters that matter most** +- `-Message`: text to log +- `-Level`: affects console color, EventId, EntryType +- `-TaskCategory`: included in formatted message and event message +- `-LogToEvent`: enable/disable Event Log writes +- `-EventLog`, `-EventSource`: desired Event Log sink +- `-EventLogConflictPolicy`: `Repair`, `Unique`, or `Follow` + +--- + +### Public: Write-LogHybrid +**What it does** +A wrapper for compatibility. + +Behavior: +- If a preferred logger function `Write-Log` exists, it calls that. +- Otherwise it calls `Write-LogHelper`. + +**Why it exists** +- Lets SAMY swap logging implementations without changing all call sites. + +--- + +## Typical usage examples + +### Console only +```powershell +Write-LogHybrid -Message "Starting SAMY" -Level Info -TaskCategory "Startup"