Skip to content

Add FileLoggingProvider for MacCatalyst UI test logging#33518

Merged
PureWeen merged 4 commits intomainfrom
hostapp-file-logging
Jan 14, 2026
Merged

Add FileLoggingProvider for MacCatalyst UI test logging#33518
PureWeen merged 4 commits intomainfrom
hostapp-file-logging

Conversation

@PureWeen
Copy link
Member

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!

Description

Adds a FileLoggingProvider to capture ILogger output during MacCatalyst UI tests. This solves the problem where Console.WriteLine and ILogger messages were not being captured when running UI tests via Appium.

Problem

When running MacCatalyst UI tests with BuildAndRunHostApp.ps1, log output was not being captured because:

  1. Appium's Mac2 driver relaunches the app with macos: launchApp
  2. This kills any existing app instance that had stderr capture configured
  3. The new app instance launched by Appium has no logging connection to the test script

Solution

Instead of trying to capture stderr from outside the app, the app now writes its own logs to a file:

  1. Test script sets MAUI_LOG_FILE environment variable to the desired log path
  2. UITest.cs passes this env var to the app via Appium's environment args
  3. MauiProgram.cs checks for the env var and adds FileLoggingProvider if set
  4. App writes all ILogger output directly to the specified file
  5. This works regardless of how the app is launched (directly or via Appium relaunch)

Changes

  • FileLoggingProvider.cs (new): Simple ILoggerProvider implementation that writes formatted log messages to a file with timestamps and log levels
  • MauiProgram.cs: Adds FileLoggingProvider to logging pipeline when MAUI_LOG_FILE env var is set
  • UITest.cs: Reads MAUI_LOG_FILE from environment and passes it to app via SetTestConfigurationArg
  • BuildAndRunHostApp.ps1: Simplified - now just sets MAUI_LOG_FILE directly to output path instead of copying from temp file

Usage

# Run MacCatalyst UI test with logging
pwsh .github/scripts/BuildAndRunHostApp.ps1 -Platform catalyst -TestFilter "FullyQualifiedName~MyTest"

# Logs are written directly to:
# CustomAgentLogsTmp/UITests/catalyst-device.log

Example Log Output

=== MAUI HostApp File Logger Started at 1/13/2026 2:29:21 PM ===
Log file: /path/to/catalyst-device.log
Minimum log level: Debug

[14:29:36.015] [ERROR] Microsoft.Maui.IApplication: Error Domain=UISceneErrorDomain Code=0 "The application does not support multiple scenes."
  Exception: Foundation.NSErrorException: Error Domain=UISceneErrorDomain Code=0 ...

- Add FileLoggingProvider.cs: ILoggerProvider that writes to a file
- Update MauiProgram.cs to add FileLoggingProvider when MAUI_LOG_FILE env var is set
- Update UITest.cs to pass MAUI_LOG_FILE env var to app via Appium
- Simplify BuildAndRunHostApp.ps1 to set MAUI_LOG_FILE directly to output path

This enables capturing ILogger output (including framework errors) during
MacCatalyst UI tests. The app writes logs directly to the specified file,
which works even when Appium relaunches the app.
Copilot AI review requested due to automatic review settings January 13, 2026 20:44
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a FileLoggingProvider to capture ILogger output during MacCatalyst UI tests, solving the problem where log messages were not being captured when Appium relaunches the app.

Changes:

  • Implements a new FileLoggingProvider class that writes logs directly to a file specified via the MAUI_LOG_FILE environment variable
  • Updates MauiProgram.cs to register the file logging provider when the environment variable is set
  • Modifies UITest.cs to pass the log file path from environment to the app via Appium's environment arguments
  • Simplifies BuildAndRunHostApp.ps1 to set the environment variable directly instead of trying to capture stderr

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 10 comments.

File Description
src/Controls/tests/TestCases.HostApp/FileLoggingProvider.cs New file implementing ILoggerProvider and ILogger for file-based logging with timestamps and log levels
src/Controls/tests/TestCases.HostApp/MauiProgram.cs Adds FileLoggingProvider registration when MAUI_LOG_FILE environment variable is set
src/Controls/tests/TestCases.Shared.Tests/UITest.cs Reads MAUI_LOG_FILE from environment and passes it to app via SetTestConfigurationArg
.github/scripts/BuildAndRunHostApp.ps1 Sets MAUI_LOG_FILE environment variable for MacCatalyst and removes old stderr capture logic
Comments suppressed due to low confidence (1)

.github/scripts/BuildAndRunHostApp.ps1:288

  • The variable $catalystAppProcess is initialized to $null but is never assigned a value in the updated code. The cleanup logic in the finally block (lines 279-288) checks if this variable is set and attempts to kill the process, but it will never execute because the variable remains null. This appears to be dead code left over from the previous implementation. Consider removing the unused variable and the unreachable cleanup code, or document why it's being kept for future use.
$catalystAppProcess = $null
if ($Platform -eq "catalyst") {
    # Determine runtime identifier
    $arch = [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString().ToLower()
    $rid = if ($arch -eq "arm64") { "maccatalyst-arm64" } else { "maccatalyst-x64" }
    
    # Build app path - matches Build-AndDeploy.ps1 output location
    $appPath = Join-Path $PSScriptRoot "../../artifacts/bin/Controls.TestCases.HostApp/Debug/$TargetFramework/$rid/Controls.TestCases.HostApp.app"
    $appPath = [System.IO.Path]::GetFullPath($appPath)
    
    if (Test-Path $appPath) {
        Write-Info "MacCatalyst app ready at: $appPath"
        
        # Make executable (like CI does)
        $executablePath = Join-Path $appPath "Contents/MacOS/Controls.TestCases.HostApp"
        if (Test-Path $executablePath) {
            & chmod +x $executablePath
        }
        
        Write-Success "MacCatalyst app prepared (Appium will launch with test name)"
    } else {
        Write-Warning "MacCatalyst app not found at: $appPath"
        Write-Warning "Test may use wrong app bundle if another version is registered"
    }
    
    # Set log file path directly - app will write ILogger output here
    $env:MAUI_LOG_FILE = $deviceLogFile
}

Write-Info "Executing: dotnet test --filter `"$effectiveFilter`""
Write-Host ""

try {
    # Run dotnet test and capture output
    $testOutput = & dotnet test $TestProject --filter $effectiveFilter --logger "console;verbosity=detailed" 2>&1
    
    # Save test output to file
    $testOutput | Out-File -FilePath $testOutputFile -Encoding UTF8
    
    # Display test output
    $testOutput | ForEach-Object { Write-Host $_ }
    
    $testExitCode = $LASTEXITCODE
    
    Write-Host ""
    Write-Info "Test output saved to: $testOutputFile"
    
} catch {
    Write-Error "Failed to run tests: $_"
    exit 1
} finally {
    # Stop MacCatalyst app process if we started it
    if ($catalystAppProcess) {
        # Re-fetch the process since the original reference may be stale
        $runningApp = Get-Process -Id $catalystAppProcess.Id -ErrorAction SilentlyContinue
        if ($runningApp -and -not $runningApp.HasExited) {
            Write-Info "Stopping MacCatalyst app process (PID: $($catalystAppProcess.Id))..."
            $runningApp.Kill()
            $runningApp.WaitForExit(5000) | Out-Null
            Write-Success "App process stopped"
        }
    }

- Fix XML doc comment: MAUI_ENABLE_FILE_LOGGING -> MAUI_LOG_FILE
- Add Directory.CreateDirectory before StreamWriter for robustness
- Change FileLoggingProvider and FileLogger to internal
- Fix misleading comment: 'backward compatibility' -> 'local debugging visibility'
@PureWeen PureWeen merged commit 7897eae into main Jan 14, 2026
25 of 28 checks passed
@PureWeen PureWeen deleted the hostapp-file-logging branch January 14, 2026 20:37
kubaflo pushed a commit to kubaflo/maui that referenced this pull request Jan 16, 2026
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

## Description

Adds a `FileLoggingProvider` to capture ILogger output during
MacCatalyst UI tests. This solves the problem where Console.WriteLine
and ILogger messages were not being captured when running UI tests via
Appium.

### Problem

When running MacCatalyst UI tests with `BuildAndRunHostApp.ps1`, log
output was not being captured because:
1. Appium's Mac2 driver relaunches the app with `macos: launchApp`
2. This kills any existing app instance that had stderr capture
configured
3. The new app instance launched by Appium has no logging connection to
the test script

### Solution

Instead of trying to capture stderr from outside the app, the app now
writes its own logs to a file:
1. Test script sets `MAUI_LOG_FILE` environment variable to the desired
log path
2. `UITest.cs` passes this env var to the app via Appium's environment
args
3. `MauiProgram.cs` checks for the env var and adds
`FileLoggingProvider` if set
4. App writes all ILogger output directly to the specified file
5. This works regardless of how the app is launched (directly or via
Appium relaunch)

### Changes

- **`FileLoggingProvider.cs`** (new): Simple `ILoggerProvider`
implementation that writes formatted log messages to a file with
timestamps and log levels
- **`MauiProgram.cs`**: Adds `FileLoggingProvider` to logging pipeline
when `MAUI_LOG_FILE` env var is set
- **`UITest.cs`**: Reads `MAUI_LOG_FILE` from environment and passes it
to app via `SetTestConfigurationArg`
- **`BuildAndRunHostApp.ps1`**: Simplified - now just sets
`MAUI_LOG_FILE` directly to output path instead of copying from temp
file

### Usage

```powershell
# Run MacCatalyst UI test with logging
pwsh .github/scripts/BuildAndRunHostApp.ps1 -Platform catalyst -TestFilter "FullyQualifiedName~MyTest"

# Logs are written directly to:
# CustomAgentLogsTmp/UITests/catalyst-device.log
```

### Example Log Output

```
=== MAUI HostApp File Logger Started at 1/13/2026 2:29:21 PM ===
Log file: /path/to/catalyst-device.log
Minimum log level: Debug

[14:29:36.015] [ERROR] Microsoft.Maui.IApplication: Error Domain=UISceneErrorDomain Code=0 "The application does not support multiple scenes."
  Exception: Foundation.NSErrorException: Error Domain=UISceneErrorDomain Code=0 ...
```
simonrozsival pushed a commit that referenced this pull request Jan 16, 2026
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

## Description

Adds a `FileLoggingProvider` to capture ILogger output during
MacCatalyst UI tests. This solves the problem where Console.WriteLine
and ILogger messages were not being captured when running UI tests via
Appium.

### Problem

When running MacCatalyst UI tests with `BuildAndRunHostApp.ps1`, log
output was not being captured because:
1. Appium's Mac2 driver relaunches the app with `macos: launchApp`
2. This kills any existing app instance that had stderr capture
configured
3. The new app instance launched by Appium has no logging connection to
the test script

### Solution

Instead of trying to capture stderr from outside the app, the app now
writes its own logs to a file:
1. Test script sets `MAUI_LOG_FILE` environment variable to the desired
log path
2. `UITest.cs` passes this env var to the app via Appium's environment
args
3. `MauiProgram.cs` checks for the env var and adds
`FileLoggingProvider` if set
4. App writes all ILogger output directly to the specified file
5. This works regardless of how the app is launched (directly or via
Appium relaunch)

### Changes

- **`FileLoggingProvider.cs`** (new): Simple `ILoggerProvider`
implementation that writes formatted log messages to a file with
timestamps and log levels
- **`MauiProgram.cs`**: Adds `FileLoggingProvider` to logging pipeline
when `MAUI_LOG_FILE` env var is set
- **`UITest.cs`**: Reads `MAUI_LOG_FILE` from environment and passes it
to app via `SetTestConfigurationArg`
- **`BuildAndRunHostApp.ps1`**: Simplified - now just sets
`MAUI_LOG_FILE` directly to output path instead of copying from temp
file

### Usage

```powershell
# Run MacCatalyst UI test with logging
pwsh .github/scripts/BuildAndRunHostApp.ps1 -Platform catalyst -TestFilter "FullyQualifiedName~MyTest"

# Logs are written directly to:
# CustomAgentLogsTmp/UITests/catalyst-device.log
```

### Example Log Output

```
=== MAUI HostApp File Logger Started at 1/13/2026 2:29:21 PM ===
Log file: /path/to/catalyst-device.log
Minimum log level: Debug

[14:29:36.015] [ERROR] Microsoft.Maui.IApplication: Error Domain=UISceneErrorDomain Code=0 "The application does not support multiple scenes."
  Exception: Foundation.NSErrorException: Error Domain=UISceneErrorDomain Code=0 ...
```
simonrozsival pushed a commit that referenced this pull request Jan 16, 2026
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

## Description

Adds a `FileLoggingProvider` to capture ILogger output during
MacCatalyst UI tests. This solves the problem where Console.WriteLine
and ILogger messages were not being captured when running UI tests via
Appium.

### Problem

When running MacCatalyst UI tests with `BuildAndRunHostApp.ps1`, log
output was not being captured because:
1. Appium's Mac2 driver relaunches the app with `macos: launchApp`
2. This kills any existing app instance that had stderr capture
configured
3. The new app instance launched by Appium has no logging connection to
the test script

### Solution

Instead of trying to capture stderr from outside the app, the app now
writes its own logs to a file:
1. Test script sets `MAUI_LOG_FILE` environment variable to the desired
log path
2. `UITest.cs` passes this env var to the app via Appium's environment
args
3. `MauiProgram.cs` checks for the env var and adds
`FileLoggingProvider` if set
4. App writes all ILogger output directly to the specified file
5. This works regardless of how the app is launched (directly or via
Appium relaunch)

### Changes

- **`FileLoggingProvider.cs`** (new): Simple `ILoggerProvider`
implementation that writes formatted log messages to a file with
timestamps and log levels
- **`MauiProgram.cs`**: Adds `FileLoggingProvider` to logging pipeline
when `MAUI_LOG_FILE` env var is set
- **`UITest.cs`**: Reads `MAUI_LOG_FILE` from environment and passes it
to app via `SetTestConfigurationArg`
- **`BuildAndRunHostApp.ps1`**: Simplified - now just sets
`MAUI_LOG_FILE` directly to output path instead of copying from temp
file

### Usage

```powershell
# Run MacCatalyst UI test with logging
pwsh .github/scripts/BuildAndRunHostApp.ps1 -Platform catalyst -TestFilter "FullyQualifiedName~MyTest"

# Logs are written directly to:
# CustomAgentLogsTmp/UITests/catalyst-device.log
```

### Example Log Output

```
=== MAUI HostApp File Logger Started at 1/13/2026 2:29:21 PM ===
Log file: /path/to/catalyst-device.log
Minimum log level: Debug

[14:29:36.015] [ERROR] Microsoft.Maui.IApplication: Error Domain=UISceneErrorDomain Code=0 "The application does not support multiple scenes."
  Exception: Foundation.NSErrorException: Error Domain=UISceneErrorDomain Code=0 ...
```
simonrozsival pushed a commit that referenced this pull request Jan 20, 2026
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

## Description

Adds a `FileLoggingProvider` to capture ILogger output during
MacCatalyst UI tests. This solves the problem where Console.WriteLine
and ILogger messages were not being captured when running UI tests via
Appium.

### Problem

When running MacCatalyst UI tests with `BuildAndRunHostApp.ps1`, log
output was not being captured because:
1. Appium's Mac2 driver relaunches the app with `macos: launchApp`
2. This kills any existing app instance that had stderr capture
configured
3. The new app instance launched by Appium has no logging connection to
the test script

### Solution

Instead of trying to capture stderr from outside the app, the app now
writes its own logs to a file:
1. Test script sets `MAUI_LOG_FILE` environment variable to the desired
log path
2. `UITest.cs` passes this env var to the app via Appium's environment
args
3. `MauiProgram.cs` checks for the env var and adds
`FileLoggingProvider` if set
4. App writes all ILogger output directly to the specified file
5. This works regardless of how the app is launched (directly or via
Appium relaunch)

### Changes

- **`FileLoggingProvider.cs`** (new): Simple `ILoggerProvider`
implementation that writes formatted log messages to a file with
timestamps and log levels
- **`MauiProgram.cs`**: Adds `FileLoggingProvider` to logging pipeline
when `MAUI_LOG_FILE` env var is set
- **`UITest.cs`**: Reads `MAUI_LOG_FILE` from environment and passes it
to app via `SetTestConfigurationArg`
- **`BuildAndRunHostApp.ps1`**: Simplified - now just sets
`MAUI_LOG_FILE` directly to output path instead of copying from temp
file

### Usage

```powershell
# Run MacCatalyst UI test with logging
pwsh .github/scripts/BuildAndRunHostApp.ps1 -Platform catalyst -TestFilter "FullyQualifiedName~MyTest"

# Logs are written directly to:
# CustomAgentLogsTmp/UITests/catalyst-device.log
```

### Example Log Output

```
=== MAUI HostApp File Logger Started at 1/13/2026 2:29:21 PM ===
Log file: /path/to/catalyst-device.log
Minimum log level: Debug

[14:29:36.015] [ERROR] Microsoft.Maui.IApplication: Error Domain=UISceneErrorDomain Code=0 "The application does not support multiple scenes."
  Exception: Foundation.NSErrorException: Error Domain=UISceneErrorDomain Code=0 ...
```
@kubaflo kubaflo added the area-ai-agents Copilot CLI agents, agent skills, AI-assisted development label Jan 28, 2026
@kubaflo kubaflo added the copilot label Feb 6, 2026
This was referenced Feb 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-ai-agents Copilot CLI agents, agent skills, AI-assisted development copilot

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants