60 lines
1.4 KiB
Swift
60 lines
1.4 KiB
Swift
import Foundation
|
|
import os
|
|
|
|
struct LogEntry: Identifiable, Sendable {
|
|
let id = UUID()
|
|
let timestamp = Date()
|
|
let message: String
|
|
let level: LogLevel
|
|
let source: String
|
|
}
|
|
|
|
enum LogLevel: String, Sendable, CaseIterable {
|
|
case debug
|
|
case info
|
|
case warning
|
|
case error
|
|
|
|
fileprivate var osLogType: OSLogType {
|
|
switch self {
|
|
case .debug: return .debug
|
|
case .info: return .info
|
|
case .warning: return .default
|
|
case .error: return .error
|
|
}
|
|
}
|
|
}
|
|
|
|
@MainActor
|
|
final class Logger: ObservableObject {
|
|
|
|
static let shared = Logger()
|
|
|
|
@Published private(set) var entries: [LogEntry] = []
|
|
|
|
private static let maxEntries = 1000
|
|
|
|
private let osLogger: os.Logger
|
|
|
|
private init() {
|
|
let subsystem = Bundle.main.bundleIdentifier ?? "com.puremac.app"
|
|
self.osLogger = os.Logger(subsystem: subsystem, category: "general")
|
|
}
|
|
|
|
nonisolated func log(_ message: String, level: LogLevel = .info, source: String = #function) {
|
|
osLogger.log(level: level.osLogType, "\(message, privacy: .public)")
|
|
|
|
let entry = LogEntry(message: message, level: level, source: source)
|
|
Task { @MainActor [weak self] in
|
|
self?.append(entry)
|
|
}
|
|
}
|
|
|
|
private func append(_ entry: LogEntry) {
|
|
entries.append(entry)
|
|
if entries.count > Self.maxEntries {
|
|
entries.removeFirst(entries.count - Self.maxEntries)
|
|
}
|
|
}
|
|
}
|