Skip to content

Add sample usage and crash telemetry - #2235

Draft
Morten Nielsen (dotMorten) wants to merge 4 commits into
mainfrom
dotmorten/telemetry
Draft

Morten Nielsen (dotMorten) wants to merge 4 commits into
mainfrom
dotmorten/telemetry

Conversation

@dotMorten

@dotMorten Morten Nielsen (dotMorten) commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Description

Adds opt-out telemetry for WinUI Gallery sample usage and crash diagnostics.

  • Records catalog-validated sample page identifiers and the app version after successful navigation.
  • Tracks the active sample for crash context.
  • Records exception type, HRESULT, app version, crash time, and a sanitized stack trace limited to WinUI Gallery frames.
  • Excludes exception messages, source-file paths, search text, navigation history, and app-generated user, device, installation, or session identifiers.
  • Persists one pending crash record before attempting immediate local emission, retries it on the next launch when unavailable, and expires it after seven days.
  • Adds an enabled-by-default Optional diagnostic data setting that applies immediately and clears pending crash diagnostics when disabled.
  • Keeps source builds on local-only EventSource logging. The Store release pipeline enables telemetry only when secured provider and privacy values are supplied.
  • Adds public telemetry documentation and focused unit coverage.

Production activation still requires the approved provider group, privacy product ID, crash privacy tags, event ownership/schema registration, and privacy review.

Motivation and Context

Sample page views provide an aggregate signal about which Windows App SDK controls and features developers are most interested in. Crash diagnostics add the active sample context needed to identify unstable samples without collecting exception messages or arbitrary navigation data.

How Has This Been Tested?

  • dotnet test tests\WinUIGallery.UnitTests\WinUIGallery.UnitTests.csproj
  • dotnet build WinUIGallery\WinUIGallery.csproj --configuration Debug --no-restore /p:Platform=x64
  • Release build with telemetry enabled and non-production validation values:
    dotnet build WinUIGallery\WinUIGallery.csproj --configuration Release --no-restore /p:Platform=x64 /p:EnableTelemetry=true /p:TelemetryProviderGroupGuid=11111111-1111-1111-1111-111111111111 /p:TelemetryPrivacyProductId=1 /p:TelemetryCrashPrivacyTags=1
  • Verified source-build events remain local-only.
  • Verified valid sample IDs, excluded navigation, opt-out behavior, crash sanitization, immediate crash emission, deferred retry, expiry, and pending-record deletion.

Screenshots (if appropriate):

The Settings page now includes a Privacy section with the Optional diagnostic data toggle and public telemetry
disclosure link.
image

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Privacy overview

The proposed collection has two events with one shared purpose: understand which WinUI samples are useful and diagnose failures associated with those samples.

Proposed event contracts

Sample page view

Provider: Microsoft.Windows.WinUIGallery
Event:    PageView_Event
Purpose:  Aggregate sample popularity and compare interest across app versions
Field Type Source and allowed values Why it is needed
PageId String Exact, case-sensitive UniqueId from the sample catalog bundled with the app Groups visits by SDK sample
AppVersion String WinUI Gallery product/package version Separates behavior across releases
PartA_PrivacyProduct Unsigned 16-bit integer Privacy-approved product ID supplied to the official build Associates the event with its privacy inventory
PartA_PrivTags Unsigned 64-bit integer Currently proposed as Product and Service Usage Declares the event's privacy datatype

The event is emitted only after successful root-frame navigation to ItemPage. The navigation parameter must match exactly one catalog item. Null, non-string, unknown, duplicate, category, Home, All Controls, Settings, failed, and embedded-frame navigation values are rejected without logging the rejected value.

Each successful eligible visit is a separate event. Revisits and back/forward visits are intentionally counted. The event does not measure dwell time or retain navigation history.

Managed unhandled exception

Provider: Microsoft.Windows.WinUIGallery
Event:    UnhandledException_Event
Purpose:  Diagnose managed XAML-thread failures and identify the active sample
Field Type Source and allowed values Why it is needed
CrashTimeUtc UTC date/time App clock at exception handling time Supports incident windows, trends, and expiry
SampleId String Exact catalog ID from the most recent successful root navigation, or empty when no sample is active Associates a failure with a sample without recording navigation history
ExceptionType String CLR full type name, falling back to the short type name Groups failures by exception class
HResult Signed 32-bit integer Exception.HResult Distinguishes error conditions without collecting the message
StackTrace String Exception.StackTrace, or empty when unavailable Identifies the failing code path
AppVersion String WinUI Gallery product/package version Separates regressions across releases
PartA_PrivacyProduct Unsigned 16-bit integer Privacy-approved product ID supplied to the official build Associates the event with its privacy inventory
PartA_PrivTags Unsigned 64-bit integer Build-time value that must be approved before telemetry can be enabled Declares the event's approved privacy datatype or datatypes

SampleId is updated only after successful root-frame navigation and is cleared on every non-sample navigation. It is therefore a single current context value, not a navigation-history field.

This event covers exceptions observed by Application.UnhandledException. It does not claim to capture native crashes, fail-fast termination, stack overflow, process termination before the handler runs, or every background-thread failure.

Field-level safeguards

  • Page and sample identifiers are allow-listed against the bundled catalog. Rejected navigation parameters are never included in telemetry.
  • Exception messages and inner-exception messages are never collected.
  • HResult is collected instead of the potentially user-containing exception message.
  • The active sample is represented by its stable catalog ID, not its title, description, route, path, or arbitrary navigation argument.
  • No search text, user-entered sample content, file path, URI, model prompt, clipboard content, or document content is collected.
  • No app-defined account, user, device, installation, advertising, session, or correlation identifier is created or collected.
  • No dwell time, full navigation history, window title, locale, or geographic-region code is included in either event.
  • The region used to decide whether consent is required is evaluated locally and is not added to telemetry.

Consent and regional safeguards

  • One Settings toggle covers both sample-usage and crash-diagnostic events.
  • The telemetry gate is evaluated immediately before each event is created or written.
  • Turning telemetry off stops both event types immediately.
  • In the same privacy-sensitive regions used by AI Dev Gallery, telemetry defaults off and the Home page asks the user to choose Allow or Don't allow.
  • Until the user chooses Allow in those regions, page-view events, crash events, and pending-crash retries are blocked.
  • The consent decision and telemetry preference are stored only in local app settings.
  • Turning telemetry off attempts to delete both the pending crash record and its temporary file. If Windows denies or interrupts deletion, the record remains blocked from transmission and deletion is attempted again on a later applicable launch or settings action.

The privacy-sensitive region decision uses the Windows-configured geographic region, not IP geolocation, and currently includes:

AUT BEL BGR BRA CAN HRV CYP CZE DNK EST FIN FRA DEU GRC HUN ISL IRL ITA
KOR LVA LIE LTU LUX MLT NLD NOR POL PRT ROU SVK SVN ESP SWE CHE GBR

Local crash-record safeguards

  • The crash record is persisted before attempting immediate emission so a process failure does not necessarily lose the diagnostic.
  • Only one pending crash record is retained. A newer crash replaces the older record.
  • The record is stored as JSON under the app's ApplicationData.LocalFolder; the app does not copy it to another local location.
  • A temporary file is written first and then moved over the pending record to reduce partial-write corruption.
  • The pending and temporary files are deleted after local EventSource acceptance, when telemetry is disabled, when the record is malformed, or when it is older than seven days.
  • Seven-day expiry is enforced when the app next loads the record; the app does not run a background timer while it is closed.
  • The app does not add application-layer encryption. Local access relies on Windows and app-data access controls. Privacy should confirm whether that is sufficient for the proposed fields and seven-day maximum age.
  • Delivery is at least once. A rare duplicate can occur if EventSource accepts the crash and the process terminates before local deletion.
  • EventSource acceptance confirms only a successful local write. It does not prove backend delivery.

Build and distribution safeguards

  • Production-capable telemetry is compiled only when EnableTelemetry=true.
  • Telemetry-enabled builds must use the Release configuration and supply the approved provider-group GUID, privacy product ID, and crash privacy tags; otherwise the build fails.
  • Ordinary local, source, Debug, PR, and unconfigured Release builds do not join the production provider group.
  • Both events currently use the Measures keyword rather than Critical.

Information explicitly excluded

Exception and inner-exception messages
Rejected or arbitrary navigation arguments
Search queries and user-entered sample data
Sample titles and descriptions
URLs and URI parameters
Account or authentication data
App-defined user, device, installation, session, advertising, or correlation IDs
Full navigation history and dwell time
Geographic-region code
Clipboard, document, prompt, and model content

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant