diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index c9614e5c21..1b698f6772 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -347,6 +347,7 @@ wpr -stop logs.ETL ### Log Analysis Tools - Use WPA (Windows Performance Analyzer) for ETL traces - Key providers: `Microsoft.Windows.Lxss.Manager`, `Microsoft.Windows.Subsystem.Lxss` +- For graphical/audio (WSLg) issues, see `.github/copilot/wslg-logs.md`. `collect-wsl-logs.ps1` gathers WSLg logs (`/mnt/wslg`: weston.log, pulseaudio.log, wlog.log, stderr.log, versions.txt) into a `wslg/` folder using `wsl.exe --system --user root`; crash dumps (`%TEMP%\wsl-crashes`, legacy `/mnt/wslg/dumps`) are only collected with `-Dump`. WSLg code lives in https://github.com/microsoft/wslg, not this repo. ### Debug Console (Linux) Add to `%USERPROFILE%\.wslconfig`: diff --git a/.github/copilot/wslg-logs.md b/.github/copilot/wslg-logs.md new file mode 100644 index 0000000000..132350bb2d --- /dev/null +++ b/.github/copilot/wslg-logs.md @@ -0,0 +1,79 @@ +# Analyzing WSLg logs + +WSLg is the component that runs graphical (GUI) and audio Linux applications on WSL. Its +source lives in a separate repository: https://github.com/microsoft/wslg. The canonical list +of diagnostics to request for a WSLg bug is the WSLg repo bug report template +(`.github/ISSUE_TEMPLATE/bug_report.yml` in microsoft/wslg). + +`diagnostics/collect-wsl-logs.ps1` collects the logs into a `wslg/` subfolder of the log archive +(via `wsl.exe --system --user root`, with a timeout so a wedged service can't hang collection), so a +standard WSL log collection already contains the log files below. Crash dumps (`dumps/`, +`wsl-crashes/`) are only collected when the script is run with `-Dump`. + +## Architecture (just enough to read the logs) + +WSLg runs a **system distro** (a small Azure Linux VM, separate from the user distro) that hosts: +- **weston** (Wayland compositor) with the `rdp-backend.so` / `rdprail-shell.so` modules +- **Xwayland** for X11 apps +- **pulseaudio** with an RDP sink/source for audio +- **FreeRDP** to stream the surfaces over an hvsocket to the Windows RDP client (`msrdc.exe`) + +`weston.log` and `wlog.log` are written by weston/FreeRDP, `pulseaudio.log` by pulseaudio, and +`stderr.log` is the combined stderr of `WSLGd` and the processes it launches. + +## Files (in the `wslg/` folder, sourced from `/mnt/wslg`) + +| File | Contents | +|---|---| +| `versions.txt` | WSLg version, architecture, build date, component git hashes (weston, FreeRDP, mesa, pulseaudio) | +| `weston.log` | Weston compositor + RDP backend log | +| `wlog.log` | FreeRDP (WLog) log | +| `pulseaudio.log` | PulseAudio log | +| `stderr.log` | `WSLGd` and child-process stderr | +| `dumps/` | Legacy WSLg crash dumps (older builds only; collected with `-Dump`) | +| `wsl-crashes/` | Host-side WSLg crash dumps copied from `%TEMP%\wsl-crashes` (newer builds, e.g. `core.weston`; collected with `-Dump`) | + +## Reading tips and common signatures + +- **`weston.log` is truncated on every boot.** Weston is started with `--log=/mnt/wslg/weston.log` + and opens it truncating, so the file only ever contains the **latest** system-distro boot. To + tell whether weston restarted, compare the boot timestamp on the first line (`weston 9.0.0 ...`) + across snapshots, or correlate with `dmesg`. + +- **System distro cycling / teardown.** In `dmesg` (collected via the ETL `GuestLog` events or + the debug console), this pair means the WSLg system distro's `init` exited and the distro was + torn down (idle timeout or shutdown), which also restarts weston: + ``` + Exception: Operation canceled @p9io.cpp:258 (AcceptAsync) + WSL (1 - init()) ERROR: InitEntryUtilityVm:2551: Init has exited. Terminating distribution + ``` + Repeating every ~25-60s with no GUI client attached is usually normal idle teardown, not a crash. + A genuine weston crash instead leaves a core dump in `wsl-crashes/` (or `dumps/`). + +- **No GPU acceleration (software rendering).** This means the virtual GPU (`/dev/dxg`, d3d12 mesa) + is not usable, so rendering falls back to CPU: + ``` + Xwayland glamor: GBM Wayland interfaces not available + Failed to initialize glamor, falling back to sw + ``` + Investigate GPU driver presence, `/dev/dxg`, and the `mesa`/`d3d12` stack if the user reports + black windows, slow rendering, or missing 3D. + +- **Audio sink not connected (usually benign at boot).** Expected until an RDP/audio client attaches: + ``` + [rdp-sink] RDP Sink - Trying to connect to /mnt/wslg/PulseAudioRDPSink + [rdp-sink] Connected failed + ``` + If it persists while audio is actively broken, look at the RDP client (`msrdc`) audio channel. + +- **Mostly-benign startup noise** (not a root cause on its own): + - `WSLGd: Exception: No such file or directory @FontMonitor.cpp:280` - font share not mounted. + - `XDG_RUNTIME_DIR "/mnt/wslg/runtime-dir" ... mode 040777` (should be 0700) - common warning. + - `dbus: Unknown username "pulse"` / `Option "-listen" is deprecated` - harmless. + +## When to escalate to the WSLg repo + +WSLg code is not in this repository. Fixes to weston, FreeRDP, pulseaudio, or the RDP backend +belong in https://github.com/microsoft/wslg. Use a commit-pinned permalink when referencing files +there so the link does not drift, e.g. +`https://github.com/microsoft/wslg/blob//`. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 283744a067..64ce9a4ed0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -90,6 +90,8 @@ Set-ExecutionPolicy Bypass -Scope Process -Force ``` The script will output the path of the log file once done. +The collected logs include WSLg (graphical and audio application) logs from `/mnt/wslg`, so the same script covers graphical-app issues. WSLg crash dumps are included when the script is run with `-Dump`. + For specific scenarios, you can use different log profiles: - `.\collect-wsl-logs.ps1 -LogProfile storage` - Enhanced storage tracing - `.\collect-wsl-logs.ps1 -LogProfile networking` - Comprehensive networking tracing (includes packet capture, tcpdump, etc.) diff --git a/diagnostics/collect-wsl-logs.ps1 b/diagnostics/collect-wsl-logs.ps1 index fa271f9b28..9a8a799f3f 100644 --- a/diagnostics/collect-wsl-logs.ps1 +++ b/diagnostics/collect-wsl-logs.ps1 @@ -341,6 +341,49 @@ if ($LogProfile -eq "networking") Remove-Item $networkingBashScript } +# Collect WSLg logs (https://github.com/microsoft/wslg) +$wslgFolder = "$folder/wslg" +mkdir -p $wslgFolder | Out-Null + +# Run in a job with a timeout so a wedged WSL service can't hang collection. --system --user root +# reaches /mnt/wslg even when the default distro is WSL1 or isn't running, and can read root-only logs. +$wslgJob = Start-Job -ScriptBlock { + param($DestFull, $CollectDumps) + + $destWsl = & wsl.exe --system --user root -e wslpath -u "$DestFull" 2>$null + if ([string]::IsNullOrWhiteSpace($destWsl)) { return } + $destWsl = $destWsl.Trim() + + # Destination is passed as $1 so paths containing a single quote are handled safely. + & wsl.exe --system --user root -e sh -c 'cp /mnt/wslg/pulseaudio.log /mnt/wslg/weston.log /mnt/wslg/wlog.log /mnt/wslg/stderr.log /mnt/wslg/versions.txt "$1/" 2>/dev/null; exit 0' sh "$destWsl" + + if ($CollectDumps) + { + & wsl.exe --system --user root -e sh -c '[ -d /mnt/wslg/dumps ] && cp -r /mnt/wslg/dumps "$1/dumps"; exit 0' sh "$destWsl" + } +} -ArgumentList (Resolve-Path $wslgFolder).Path, ([bool]$Dump) + +if (Wait-Job $wslgJob -Timeout 60) +{ + Receive-Job $wslgJob | Out-Null +} +else +{ + Write-Host -ForegroundColor Yellow "WSLg log collection timed out and was skipped." + Stop-Job $wslgJob +} +Remove-Job $wslgJob -Force + +# Crash dumps are only collected with -Dump, since users may not expect dumps to be published by default. +if ($Dump) +{ + $wslCrashes = "$env:TEMP\wsl-crashes" + if (Test-Path $wslCrashes) + { + Copy-Item $wslCrashes "$wslgFolder/wsl-crashes" -Recurse -ErrorAction Ignore + } +} + if ($Dump) { $Assembly = [PSObject].Assembly.GetType('System.Management.Automation.WindowsErrorReporting') diff --git a/doc/docs/debugging.md b/doc/docs/debugging.md index 12a011f2c2..795a9618b3 100644 --- a/doc/docs/debugging.md +++ b/doc/docs/debugging.md @@ -51,6 +51,30 @@ debugConsole=true to `%USERPROFILE%/.wslconfig` and restarting WSL +## WSLg (graphical and audio applications) logs + +[WSLg](https://github.com/microsoft/wslg) runs graphical and audio Linux applications. It runs a +system distro that hosts the `weston` Wayland compositor (with an RDP backend), `Xwayland`, +`pulseaudio`, and `FreeRDP`. WSLg's source lives in a separate repository: +[microsoft/wslg](https://github.com/microsoft/wslg). + +WSLg writes its logs to `/mnt/wslg` (accessible from Windows via `\\wsl$\\mnt\wslg`): + +- `weston.log` - Weston compositor and RDP backend log +- `wlog.log` - FreeRDP log +- `pulseaudio.log` - PulseAudio log +- `stderr.log` - `WSLGd` and child-process stderr +- `versions.txt` - WSLg version and component git hashes + +Crash dumps (e.g. `core.weston`) are written to `%TEMP%\wsl-crashes` on newer builds, or +`/mnt/wslg/dumps` on older ones. + +The [collect-wsl-logs.ps1](https://github.com/microsoft/WSL/blob/master/diagnostics/collect-wsl-logs.ps1) +script gathers the logs above automatically into a `wslg/` folder (crash dumps are included when run +with `-Dump`). Note that `weston.log` is truncated on every system-distro boot, so it only contains +the most recent boot. + + ## Attaching debuggers Usermode can be attached to WSL Windows processes (wsl.exe, wslservice.exe, wslrelay.exe, ...). The symbols are available under the `bin//` folder.