Created
September 27, 2021 15:54
-
-
Save joshuajhomann/2fdbbb6a6bf94863704e6092ecc6f49b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
import OSLog | |
struct LogName { | |
let network = "Networking" | |
} | |
@dynamicMemberLookup | |
enum Log { | |
struct Info: CustomStringConvertible { | |
let description: String | |
let category: String | |
fileprivate init(description: String, category: String) { | |
self.description = description | |
self.category = category | |
} | |
} | |
private static var logs: [String: Logger] = [:] | |
private static let name = LogName() | |
static let enumeratedLogInfo: [Info] = { | |
let mirror = Mirror(reflecting: Log.name) | |
return mirror.children.compactMap { child in | |
guard let description = child.value as? String, let category = child.label else { return nil } | |
return Info(description: description, category: category) | |
} | |
}() | |
static subscript(dynamicMember keyPath: KeyPath<LogName, String>) -> Logger { | |
let category = name[keyPath: keyPath] | |
let log = Self.logs[category, default: Logger(subsystem: Bundle.main.bundleIdentifier ?? "", category: category)] | |
logs[category] = log | |
return log | |
} | |
static func fetchLogEntries<SomeSequence: Sequence>( | |
for logInfo: SomeSequence, | |
since elapsed: TimeInterval, | |
isReversed: Bool = true | |
) throws -> [OSLogEntryLog] where SomeSequence.Element == Info { | |
let logStore = try OSLogStore(scope: .currentProcessIdentifier) | |
let position = logStore.position(date: .now.addingTimeInterval(-elapsed)) | |
let predicate = NSCompoundPredicate( | |
type: .or, | |
subpredicates: logInfo.map(\.category).map { NSPredicate(format: "category == %@", argumentArray: [$0]) } | |
) | |
let entries = try logStore.getEntries(with: isReversed ? [.reverse] : [], at: position, matching: predicate) | |
return entries.compactMap { $0 as? OSLogEntryLog }.filter { $0.subsystem == Bundle.main.bundleIdentifier ?? "" } | |
} | |
} | |
enum TabSeparatedValue { | |
static func escape(_ value: String) -> String { | |
"\"" + value.replacingOccurrences(of: "\"", with: "'") + "\"" | |
} | |
static func makeRow(from strings: [String]) -> String { | |
strings.map(Self.escape(_:)).joined(separator: "\t") + "\r\n" | |
} | |
static func make(header: [String], rows: [[String]]) -> String { | |
makeRow(from: header) + rows.map(makeRow(from:)).joined() | |
} | |
} | |
extension FileManager { | |
static func writeTemporary(_ value: String, filename: String) throws -> URL { | |
let url = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0].appendingPathComponent(filename) | |
try value.write(to: url, atomically: true, encoding: .utf8) | |
return url | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment