I've found Console.app much harder to use in recent years, and one of the issues is the firehose of data is much more difficult to examine when you don't know what you're looking for, especially if you have to turn on debug and info.
As an example of a tool, I'm posting a script I wrote to gather likely subsystem/category names from other binaries. It's crude, but does a decent job when you're not sure where to start
As an example of a tool, I'm posting a script I wrote to gather likely subsystem/category names from other binaries. It's crude, but does a decent job when you're not sure where to start
Code Block Swift #!/usr/bin/swift import Foundation extension Process { class func launchedForLines(url: URL, args: [String], block: (String) -> Void) { let proc = Process(), pipe = Pipe(), eol = Data([0x0A]) proc.executableURL = url proc.arguments = args proc.standardOutput = pipe proc.launch() let output = pipe.fileHandleForReading var buffer = Data(capacity: Int(LINE_MAX)), chunk = output.availableData while !chunk.isEmpty { buffer.append(chunk) while let range = buffer.range(of: eol) { let slice = buffer[0..<range.lowerBound] buffer.replaceSubrange(0..<range.upperBound, with: Data()) if let line = String(data: slice, encoding: .utf8) { block(line) } } chunk = output.availableData } proc.terminate() } } struct Log : Hashable, Equatable { let subsystem:String, category:String } func find_logs(url: URL) -> [Log]? { let literal = "literal pool for: \"", hold = "HOLD" var ring = [hold, hold], idx = false, logs = Set<Log>() Process.launchedForLines(url: URL(fileURLWithPath: "/usr/bin/otool", isDirectory: false), args: ["-tV", url.path], block: { (line) in if let range = line.range(of: literal) { let frag = line[range.upperBound..<line.index(before: line.endIndex)] ring[idx ? 1 : 0] = String(frag) idx = !idx } else if line.range(of: "_os_log_create", options: .literal) != nil { let sub = ring[idx ? 1 : 0], cat = ring[idx ? 0 : 1] if sub != hold && cat != hold && sub.range(of: ".", options: .literal) != nil { logs.insert(Log(subsystem: sub, category: cat)) } ring = [hold, hold] } }) return logs.isEmpty ? nil : Array(logs) } func check_mach(url: URL) -> Bool { guard let handle = try? FileHandle(forReadingFrom: url) else { return false } let size = MemoryLayout.size(ofValue: MH_MAGIC), magic = handle.readData(ofLength: size) try? handle.close() return magic.count == size && [MH_MAGIC, MH_MAGIC_64, FAT_CIGAM, FAT_CIGAM_64].contains(magic.withUnsafeBytes({ $0.load(as: UInt32.self) })) } func enumerate(url: URL, block: (URL, URLFileResourceType) -> Void) { guard let type = try? url.resourceValues(forKeys: [.fileResourceTypeKey]).fileResourceType else { return } block(url, type) if (type == .directory) { _ = (try? FileManager.default.contentsOfDirectory(at: url, includingPropertiesForKeys: [.fileResourceTypeKey], options: []))?.map({ enumerate(url: $0, block: block) }) } } let args = ProcessInfo().arguments guard let base = args.count > 1 ? URL(fileURLWithPath: args[1]) : nil else { print("Specify exactly one argument, the path to search") exit(1) } enumerate(url: base) { (url, type) in autoreleasepool { if type == .regular && check_mach(url: url), let logs = find_logs(url: url) { print("Found binary \(url.path)") _ = logs.map({ print("Subsystem: \($0.subsystem) Category: \($0.category)") }) } } }