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:
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)