Skip to content

Exporting Unified Logging Data (SwiftUI)

A SwiftUI guide for coding agents. Also covers oslogstore read logs, export logs from device, share app logs with developer, getentries oslog filter subsystem, logs since last boot.

OSLogStore reads back the log entries your app wrote with Logger. Pair it with a share sheet, and users can send their logs to you from a settings screen, without a cable or the Console app.

Fetch Entries With OSLogStore

Open the store scoped to the current process, pick a start position, then fetch and filter. Filter on your own subsystem, or you also get system noise from the process.

import OSLog

@MainActor final class LogStore: ObservableObject {
  @Published private(set) var entries: [String] = []

  func export() {
    do {
      let store = try OSLogStore(scope: .currentProcessIdentifier)
      let position = store.position(timeIntervalSinceLatestBoot: 1)
      entries = try store
        .getEntries(at: position)
        .compactMap { $0 as? OSLogEntryLog }
        .filter { $0.subsystem == Bundle.main.bundleIdentifier! }
        .map { "[\($0.date.formatted())] [\($0.category)] \($0.composedMessage)" }
    } catch {
      // log the failure with your own Logger
    }
  }
}

getEntries(at:) returns generic entries, so cast each one to OSLogEntryLog to reach subsystem, category, and composedMessage.

Choose the Time Window With position

The position function has two useful overloads. timeIntervalSinceLatestBoot: starts at the last boot. position(date:) starts at any date, for example the last 24 hours.

let store = try OSLogStore(scope: .currentProcessIdentifier)
let date = Date.now.addingTimeInterval(-24 * 3600)
let position = store.position(date: date)

Share the Logs From Settings

Join the entries into one string and hand it to a wrapped UIActivityViewController. The user picks Mail, Messages, or Files themselves.

struct SettingsView: View {
  @ObservedObject var logs: LogStore
  @State private var exportShown = false

  var body: some View {
    Form {
      Section(header: Text("debug")) {
        Button("exportLogs") {
          logs.export()
          exportShown = true
        }
        .sheet(isPresented: $exportShown) {
          ShareView(items: [logs.entries.joined(separator: "\n")])
        }
      }
    }
  }
}

struct ShareView: UIViewControllerRepresentable {
  let items: [Any]

  func makeUIViewController(context: Context) -> UIActivityViewController {
    UIActivityViewController(activityItems: items, applicationActivities: nil)
  }

  func updateUIViewController(_ vc: UIActivityViewController, context: Context) {}
}

Only persisted levels come back: notice, warning, and critical survive, while trace messages are never stored, so they cannot be exported.

Use this guidance in your coding agent

Install the Better Design MCP once. Your agent then loads this page with one call.

get-swiftui-guide({ topic: "swiftui-exporting-data-from-unified-logging-system-in-swift" })
claude mcp add --scope user better-design --transport http https://better-design.com/api/mcp --header "Authorization: Bearer <YOUR_API_KEY>"
Browse related design systems