For some fields aside from messageType
“IN” situation works advantageous.
Additionally .reverse
possibility doesn’t appear to make any distinction no less than on iOS.
Right here is fast pattern to test:
public extension Logger {
static let appSubsystem = Bundle.important.bundleIdentifier!
static func fetch(since date: Date) async throws -> [String] {
let retailer = attempt OSLogStore(scope: .currentProcessIdentifier)
let place = retailer.place(date: date)
// This does NOT work.
// let predicate = NSPredicate(format: "(subsystem == %@) && (messageType IN %@)", Logger.appSubsystem, ["error", "fault"])
// This, nevertheless, works.
let predicate = NSPredicate(format: "(subsystem IN %@) && (messageType == %@)", [Logger.appSubsystem], "error")
let entries = attempt retailer.getEntries(/* with: [.reverse], */ at: place,
matching: predicate)
var logs: [String] = []
for entry in entries {
attempt Process.checkCancellation()
if let log = entry as? OSLogEntryLog {
logs.append("""
(entry.date):(log.subsystem):
(log.class):(log.stage):
(entry.composedMessage)n
""")
} else {
logs.append("(entry.date): (entry.composedMessage)n")
}
}
if logs.isEmpty { logs = ["Nothing found"] }
return logs
}
}
// This extension is for pattern functions solely
extension OSLogEntryLog.Stage: @retroactive CustomStringConvertible {
public var description: String {
swap self {
case .undefined: "undefined"
case .debug: "debug"
case .information: "information"
case .discover: "discover"
case .error: "error"
case .fault: "fault"
@unknown default: "default"
}
}
}
extension OSLogEntryLog.Stage: @retroactive Identifiable {
public var id: Int {
rawValue
}
}
Right here is small SwiftUI display to help in reproducing the problem
import SwiftUI
import OSLog
struct LogView: View {
@State personal var textual content = "Loading..."
@State personal var job: Process<(), Error>?
@State personal var isLoading = false
@State personal var selectedLogLevel: OSLogEntryLog.Stage = .undefined
personal let logLevels: [OSLogEntryLog.Level] = [.undefined, .debug, .info, .notice, .error, .fault]
let logger = Logger(subsystem: Logger.appSubsystem, class: "important")
var physique: some View {
VStack {
HStack {
Button(isLoading ? "Cancel" : "Refresh") {
if isLoading {
job?.cancel()
} else {
job = Process {
textual content = await fetchLogs()
isLoading = false
}
}
}
ProgressView()
.opacity(isLoading ? 1 : 0)
Picker(choice: $selectedLogLevel, label: Textual content("Select Log Stage")) {
ForEach(logLevels) { logLevel in
Textual content(logLevel.description)
.tag(logLevel)
}
}
Button("Log") {
logMessage(selectedLogLevel: selectedLogLevel)
}
}
ScrollView {
Textual content(textual content)
.textSelection(.enabled)
.fontDesign(.monospaced)
.padding()
}
}
.onAppear {
isLoading = true
job = Process {
textual content = await fetchLogs()
isLoading = false
}
}
}
}
personal extension LogView {
@MainActor
func fetchLogs() async -> String {
let calendar = Calendar.present
guard let hourAgo = calendar.date(byAdding: .hour,
worth: -1, to: Date.now) else {
return "Invalid calendar"
}
do {
let logs = attempt await Logger.fetch(since: hourAgo)
return logs.joined()
} catch {
return error.localizedDescription
}
}
func logMessage(selectedLogLevel: OSLogEntryLog.Stage) {
swap(selectedLogLevel) {
case .undefined:
logger.log("Default log message")
case .debug:
logger.debug("Debug log message")
case .information:
logger.information("Information log message")
// case .warning:
// logger.warning("Warning log message")
case .discover:
logger.discover("Discover log message")
case .error:
logger.error("Error log message")
case .fault:
logger.fault("Fault log message")
@unknown default:
logger.log("Default log message")
}
}
}