MXC Telemetry

August 20, 2026 · View on GitHub

MXC uses the Rust tracelogging crate (published by Microsoft) for TraceLogging ETW telemetry. No C++ shim, WIL, or FFI is required.

Overview

┌──────────────────────────────────────────────────────┐
│  wxc_common::telemetry                               │
│  (Rust — config resolution, sanitisation, types)     │
│                                                      │
│  init() / log_execution() / log_error() / shutdown() │
└───────────────┬──────────────────────────────────────┘
                │  Direct Rust function calls

┌──────────────────────────────────────────────────────┐
│  mxc_telemetry (Rust crate)                          │
│  src/lib.rs — define_provider! + write_event!        │
│                                                      │
│  Windows: ETW events via tracelogging crate          │
│  Linux/macOS: no-op stubs                            │
└──────────────────────────────────────────────────────┘

Why the Rust tracelogging Crate (Not WIL C++ Shim)

An earlier design used a WIL C++ shim compiled via the cc crate. PR review feedback correctly noted that the WIL dependency added C++ compilation, NuGet download, FFI unsafety, and blocked non-Windows contributors from building the crate. The Rust tracelogging crate provides the core ETW primitives needed, and the small set of WIL features MXC actually uses can be replicated with Rust constants and write_event! struct fields.

Feature comparison

FeatureWIL (wil/TraceLogging.h)Rust tracelogging crateMXC approach
Provider group GUIDTraceLoggingOptionMicrosoftTelemetry()group_id("...") in define_provider!build.rs generates provider_def.rs with/without group_id based on env var
Sampling keywordsMICROSOFT_KEYWORD_MEASURES named constantRaw u64 in keyword(...)const MICROSOFT_KEYWORD_MEASURES: u64 = 0x0000_4000_0000_0000
Common event fields_GENERIC_PARTB_FIELDS_ENABLED patternstruct("Name", { ... }) in write_event!struct("COMMON_MXC_PARAMS", { Version, Channel, IsDebugging, UTCReplace_AppSessionGuid })
Provider lifecycleIMPLEMENT_TRACELOGGING_CLASS singletondefine_provider! static + register()/unregister()OnceLock<ProviderState> for version/channel, manual lifecycle
Privacy Data TagsTelemetryPrivacyDataTag(PDT_*)u64("PartA_PrivTags", &val) fieldPDT_PRODUCT_AND_SERVICE_USAGE on all events
Activity trackingDEFINE_TELEMETRY_ACTIVITYManual OpcodeNot needed for current events

The remaining gap (activity tracking) is not needed for current events. If needed later, it can be added incrementally.

Common Event Fields (Part C)

Every MXC telemetry event includes a COMMON_MXC_PARAMS struct grouping shared Part C custom event fields:

FieldTypeDescription
VersionstringMXC crate version from CARGO_PKG_VERSION
Channelstring"dev" for debug builds, "release" for release
IsDebuggingboolcfg!(debug_assertions) — true for debug builds
UTCReplace_AppSessionGuidboolAlways true — tells UTC to replace the app session GUID with a per-session identifier for privacy

Events

The provider-qualified uploaded event identities are Microsoft.MXC/MXC.Execution and Microsoft.MXC/MXC.Error. Microsoft.MXC is the TraceLogging provider name; MXC.Execution and MXC.Error are the event names.

MXC.Execution

Emitted when a one-shot execution completes (success or failure). It is also emitted on early-exit failures in the one-shot executors — configuration, policy, and backend-init failures that terminate before a runner produces a result (with mxc.exit_code = 1 and mxc.outcome = failure).

The state-aware lifecycle (provision / start / exec / stop / deprovision) is also instrumented: each dispatched phase emits one MXC.Execution tagged with mxc.phase. Non-exec phases and exec dry-runs report success with mxc.exit_code = 0; a completed exec reports the sandbox process exit code; a dispatch error reports failure plus an MXC.Error. As in the one-shot path, a clean non-zero sandbox exit is not treated as an MXC error.

FieldTypeDescription
mxc.sandbox_kindstringContainment kind requested by the caller (process, vm, or a concrete backend name)
mxc.backendstringConcrete containment backend selected on the host
mxc.exit_codeint32Process exit code
mxc.outcomestring"success" or "failure"
mxc.duration_msuint64Total execution time
mxc.failure_reasonstringFailure category (if applicable)
mxc.phasestringState-aware lifecycle phase (provision|start|exec|stop|deprovision); empty for one-shot executions

MXC.Error

Emitted on execution errors.

FieldTypeDescription
mxc.sandbox_kindstringContainment kind requested by the caller (process, vm, or a concrete backend name)
mxc.backendstringConcrete containment backend selected on the host
mxc.error_typestringError category (config_error, policy_error, process_error, timeout, init_error, internal_error, cancelled, unknown)
mxc.exit_codeint32Process exit code
mxc.phasestringState-aware lifecycle phase; empty for one-shot executions

No free-form error text is emitted. Error messages can contain paths, usernames, or credentials, so MXC.Error deliberately carries only the bounded error_type category and the numeric exit_code — never the message string itself.

Crash telemetry (panic hook)

When telemetry is active, the executors install a global [std::panic::set_hook] handler — both the one-shot executors and the state-aware path (run_state_aware_main). If any thread panics, the hook emits a failure MXC.Execution plus an MXC.Error categorised as internal_error (with mxc.exit_code = 101, the conventional Rust panic/abort exit code), attributed to the containment backend recorded at telemetry init and, on the state-aware path, the mxc.phase in progress. Consistent with the PII policy, no panic message or backtrace text is emitted — only the bounded category and exit code. The hook chains the previously-installed hook, so the default stderr backtrace still prints.

Limitation: Only failures that occur after telemetry initialisation can be reported. A panic during argument parsing or config load — before telemetry::init runs — cannot emit an event, because the provider is not yet registered.

Limitation: On backends that recover panics via catch_unwind (the LXC runner does this for container-cleanup safety), the panic hook still fires during unwinding and records the crash event with the 101 sentinel exit code, then claims the exactly-once terminal-emit slot. The recovered MXC.Execution completion event is therefore suppressed, so telemetry reports mxc.exit_code = 101 even though the recovered process ultimately exits with a different code (-1). the 101 here is a "a panic occurred" sentinel, not a claim about the observed process exit code; outcome and error_type remain accurate. Backends that do not catch panics (the Windows one-shot executor) abort with 101, so the recorded code matches the real exit.

Cancellation telemetry (console control handler)

On Windows, when telemetry is active, wxc-exec's console control handler emits a failure MXC.Execution plus an MXC.Error categorised as cancelled when the operator interrupts a run (Ctrl-C, console close, or a system shutdown/logoff). The reported mxc.exit_code is 130 (the conventional "terminated by Ctrl-C" code, 128 + SIGINT) — a bounded attribution sentinel, since the OS ultimately terminates the process with its own status. The handler runs on a short, OS-imposed budget and does not shut the provider down; the events carry no free-form text.

Cross-Platform Behaviour

PlatformBehaviour
WindowsFull ETW telemetry via tracelogging crate
LinuxNo-op — all telemetry functions return immediately
macOSNo-op — all telemetry functions return immediately

Telemetry emission is gated by the per-run request, MXC-owned consent, administrative policy, and provider availability. See docs/telemetry/telemetry-consent-design.md.

Privacy review status

The version 1 en-US consent wording is approved for release review. The canonical title, body, action labels, and privacy link are documented in Telemetry consent design and must be rendered verbatim by every EXE and SDK presenter.

Data sent

MXC's optional diagnostic events contain:

  • MXC version and channel
  • Whether the build has debug assertions enabled (IsDebugging)
  • Caller-requested sandbox kind and the concrete backend selected on the host
  • Run outcome and exit code
  • Run duration
  • Bounded failure category
  • State-aware lifecycle phase
  • UTCReplace_AppSessionGuid, which asks the telemetry pipeline to supply a random per-session app identifier

MXC does not emit commands, file paths, credentials, customer content, or free-form error text. The consent notice's phrase “other customer content” covers any such values that a host or sandbox may process but MXC does not include in these events.

Review status

The consent wording and canonical resource are approved for release review. The broader data inventory, retention, access, regional processing, deletion, and localization/accessibility decisions remain pending explicit privacy review.