9.5 C
New York
Tuesday, March 11, 2025

ios – OSLogStore func `getEntries(with:, at:, matching: predicate)` fails for “messageType IN %@” predicate sorts


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")
        }
    }
}

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles