crossmate

A collaborative crossword app for iOS
Log | Files | Refs | LICENSE

commit 61175a392c0e9a71909f74e7f7687f784a68df1c
parent ca0242332924fd1bb31f1ab579ca2fed5ab95456
Author: Michael Camilleri <[email protected]>
Date:   Thu, 11 Jun 2026 14:40:40 +0900

Mirror EventLog breadcrumbs into the unified system log

Every append now also emits to an os.Logger (`subsystem = bundle id,
category = "events"`), mapping error/warn/info levels across. The
file-backed buffer stays the system of record for TestFlight shares; the
mirror adds live streaming in Xcode/Console.app on tethered runs,
capture in sysdiagnoses, and keeps the ~2s tail that the debounced file
flush would lose in a hard crash. Interpolation is .public since the
same messages are already exposed via the diagnostics share sheet.

Co-Authored-By: Claude Fable 5 <[email protected]>

Diffstat:
MCrossmate/Services/DebuggingMonitors.swift | 21+++++++++++++++++++++
1 file changed, 21 insertions(+), 0 deletions(-)

diff --git a/Crossmate/Services/DebuggingMonitors.swift b/Crossmate/Services/DebuggingMonitors.swift @@ -1,6 +1,7 @@ import CloudKit import Foundation import Observation +import os struct PerformanceDiagnosticEntry: Identifiable, Sendable { let id = UUID() @@ -244,6 +245,18 @@ final class EventLog { private let store: EventLogStore + /// Mirror of every breadcrumb into the unified system log. The file-backed + /// buffer remains the system of record for TestFlight shares; this mirror + /// adds live streaming in Xcode/Console.app on tethered runs, capture in + /// sysdiagnoses, and crash resilience — a hard crash loses up to 2s of + /// tail to the debounced file flush, but the system log keeps it. + /// Interpolation is `.public` because these messages are already exposed + /// verbatim through the diagnostics share sheet. + @ObservationIgnored private let systemLog = Logger( + subsystem: Bundle.main.bundleIdentifier ?? "Crossmate", + category: "events" + ) + /// Until the on-disk history has been merged in, appends must not flush: /// a flush before `loadPersisted` would clobber the file with a partial, /// pre-hydration snapshot and lose the very overnight history we're after. @@ -270,6 +283,14 @@ final class EventLog { } fileprivate func append(level: String, _ message: String) { + switch level { + case "error": + systemLog.error("\(message, privacy: .public)") + case "warn": + systemLog.warning("\(message, privacy: .public)") + default: + systemLog.info("\(message, privacy: .public)") + } let now = Date() entries.append(EventLogEntry(timestamp: now, level: level, message: message)) prune(now: now)