For some fields aside from messageType
“IN” situation works tremendous.
Additionally .reverse
choice doesn’t appear to make any distinction at the least on iOS.
Right here is fast pattern to verify:
public extension Logger {
static let appSubsystem = Bundle.most important.bundleIdentifier!
static func fetch(since date: Date) async throws -> [String] {
let retailer = strive 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, nonetheless, works.
let predicate = NSPredicate(format: "(subsystem IN %@) && (messageType == %@)", [Logger.appSubsystem], "error")
let entries = strive retailer.getEntries(/* with: [.reverse], */ at: place,
matching: predicate)
var logs: [String] = []
for entry in entries {
strive Job.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.Degree: @retroactive CustomStringConvertible {
public var description: String {
change self {
case .undefined: "undefined"
case .debug: "debug"
case .information: "information"
case .discover: "discover"
case .error: "error"
case .fault: "fault"
@unknown default: "default"
}
}
}
extension OSLogEntryLog.Degree: @retroactive Identifiable {
public var id: Int {
rawValue
}
}
Right here is small SwiftUI display screen to help in reproducing the problem
import SwiftUI
import OSLog
struct LogView: View {
@State personal var textual content = "Loading..."
@State personal var process: Job<(), Error>?
@State personal var isLoading = false
@State personal var selectedLogLevel: OSLogEntryLog.Degree = .undefined
personal let logLevels: [OSLogEntryLog.Level] = [.undefined, .debug, .info, .notice, .error, .fault]
let logger = Logger(subsystem: Logger.appSubsystem, class: "most important")
var physique: some View {
VStack {
HStack {
Button(isLoading ? "Cancel" : "Refresh") {
if isLoading {
process?.cancel()
} else {
process = Job {
textual content = await fetchLogs()
isLoading = false
}
}
}
ProgressView()
.opacity(isLoading ? 1 : 0)
Picker(choice: $selectedLogLevel, label: Textual content("Select Log Degree")) {
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
process = Job {
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 = strive await Logger.fetch(since: hourAgo)
return logs.joined()
} catch {
return error.localizedDescription
}
}
func logMessage(selectedLogLevel: OSLogEntryLog.Degree) {
change(selectedLogLevel) {
case .undefined:
logger.log("Default log message")
case .debug:
logger.debug("Debug log message")
case .information:
logger.information("Data 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")
}
}
}