From 870fdd99dd8ba4efd5bbebb7e0b72df80c1b0dc1 Mon Sep 17 00:00:00 2001 From: Thomas Mellenthin Date: Tue, 8 Jun 2021 18:31:14 +0200 Subject: [PATCH 1/2] File logging: - make sure we always append to the file - align different linebreaks for actions and state messages - make sure logging to files and to os_log looks the same --- .../LoggerMiddleware/LoggerMiddleware.swift | 55 +++++++++++-------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/Sources/LoggerMiddleware/LoggerMiddleware.swift b/Sources/LoggerMiddleware/LoggerMiddleware.swift index 21e11b5..91133b1 100644 --- a/Sources/LoggerMiddleware/LoggerMiddleware.swift +++ b/Sources/LoggerMiddleware/LoggerMiddleware.swift @@ -103,26 +103,21 @@ extension LoggerMiddleware { // MARK: State Logger extension LoggerMiddleware { public enum StateLogger { + /// Logs using os_log. case osLog - case file(URL) + /// Appends the messages to a file. The file must exist! + case file(URL, DateFormatter) + /// A custom handler. case custom((String) -> Void) func log(state: String) { switch self { - case .osLog: LoggerMiddleware.osLog(state: state) - case let .file(url): LoggerMiddleware.fileLog(state: state, to: url) + case .osLog: LoggerMiddleware.osLog(state) + case let .file(url, dateFormatter): LoggerMiddleware.fileLog(state, to: url, dateFormatter: dateFormatter) case let .custom(closure): closure(state) } } } - - private static func osLog(state: String) { - os_log(.debug, log: .default, "%{PUBLIC}@", state) - } - - private static func fileLog(state: String, to fileURL: URL) { - try? state.write(toFile: fileURL.absoluteString, atomically: false, encoding: String.Encoding.utf8) - } } // MARK: State Diff Transform @@ -243,32 +238,27 @@ extension LoggerMiddleware { // MARK: Action Logger extension LoggerMiddleware { public enum ActionLogger { + /// Logs using os_log. case osLog - case file(URL) + /// Appends the messages to a file. The file must exist! + case file(URL, DateFormatter) + /// A custom handler. case custom((String) -> Void) func log(action: String) { switch self { - case .osLog: LoggerMiddleware.osLog(action: action) - case let .file(url): LoggerMiddleware.fileLog(action: action, to: url) + case .osLog: LoggerMiddleware.osLog(action) + case let .file(url, dateFormatter): LoggerMiddleware.fileLog(action, to: url, dateFormatter: dateFormatter) case let .custom(closure): closure(action) } } } - - private static func osLog(action: String) { - os_log(.debug, log: .default, "%{PUBLIC}@", action) - } - - private static func fileLog(action: String, to fileURL: URL) -> Void { - try? action.write(toFile: fileURL.absoluteString, atomically: false, encoding: .utf8) - } } // MARK: Action Transform extension LoggerMiddleware { public enum ActionTransform { - case `default`(actionPrefix: String = "\n🕹 ", sourcePrefix: String = "\n🎪 ") + case `default`(actionPrefix: String = "🕹 ", sourcePrefix: String = " 🎪 ") case actionNameOnly case custom((InputActionType, ActionSource) -> String) @@ -284,3 +274,22 @@ extension LoggerMiddleware { } } } + +// MARK: Log output + +extension LoggerMiddleware { + + fileprivate static func fileLog(_ message: String, to fileURL: URL, dateFormatter: DateFormatter) { + guard let fileUpdater = try? FileHandle(forUpdating: fileURL), + let data = (dateFormatter.string(from: Date()) + " " + message + "\n") + .data(using: String.Encoding.utf8) else { return } + fileUpdater.seekToEndOfFile() + fileUpdater.write(data) + fileUpdater.closeFile() + } + + fileprivate static func osLog(_ message: String) { + os_log(.debug, log: .default, "%{PUBLIC}@", message) + } + +} From b3993a1b8d78b0d751271d396921dfa3aeff9b07 Mon Sep 17 00:00:00 2001 From: Thomas Mellenthin Date: Wed, 9 Jun 2021 15:48:15 +0200 Subject: [PATCH 2/2] properly inject dependencies --- .../LoggerMiddleware/LoggerMiddleware.swift | 53 ++++++++++++++----- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/Sources/LoggerMiddleware/LoggerMiddleware.swift b/Sources/LoggerMiddleware/LoggerMiddleware.swift index 91133b1..4ee9c16 100644 --- a/Sources/LoggerMiddleware/LoggerMiddleware.swift +++ b/Sources/LoggerMiddleware/LoggerMiddleware.swift @@ -106,14 +106,14 @@ extension LoggerMiddleware { /// Logs using os_log. case osLog /// Appends the messages to a file. The file must exist! - case file(URL, DateFormatter) + case file(FileAppender) /// A custom handler. case custom((String) -> Void) func log(state: String) { switch self { case .osLog: LoggerMiddleware.osLog(state) - case let .file(url, dateFormatter): LoggerMiddleware.fileLog(state, to: url, dateFormatter: dateFormatter) + case let .file(fileAppender): fileAppender.write(state) case let .custom(closure): closure(state) } } @@ -241,14 +241,14 @@ extension LoggerMiddleware { /// Logs using os_log. case osLog /// Appends the messages to a file. The file must exist! - case file(URL, DateFormatter) + case file(FileAppender) /// A custom handler. case custom((String) -> Void) func log(action: String) { switch self { case .osLog: LoggerMiddleware.osLog(action) - case let .file(url, dateFormatter): LoggerMiddleware.fileLog(action, to: url, dateFormatter: dateFormatter) + case let .file(fileappender): fileappender.write(action) case let .custom(closure): closure(action) } } @@ -279,17 +279,44 @@ extension LoggerMiddleware { extension LoggerMiddleware { - fileprivate static func fileLog(_ message: String, to fileURL: URL, dateFormatter: DateFormatter) { - guard let fileUpdater = try? FileHandle(forUpdating: fileURL), - let data = (dateFormatter.string(from: Date()) + " " + message + "\n") - .data(using: String.Encoding.utf8) else { return } - fileUpdater.seekToEndOfFile() - fileUpdater.write(data) - fileUpdater.closeFile() - } - fileprivate static func osLog(_ message: String) { os_log(.debug, log: .default, "%{PUBLIC}@", message) } } + +public struct FileAppender { + private let url: URL + private let date: () -> Date + private let dateFormatter: DateFormatter + private let writer: (URL, Data) -> Void + + public init(url: URL, date: @escaping () -> Date, dateFormatter: DateFormatter, writer: @escaping (URL, Data) -> Void) { + self.url = url + self.date = date + self.dateFormatter = dateFormatter + self.writer = writer + } + + public func write(_ message: String) { + guard let data = (dateFormatter.string(from: date()) + " " + message + "\n").data(using: String.Encoding.utf8) else { return } + writer(url, data) + } +} + +extension FileAppender { + public static func live(url: URL, dateFormatter: DateFormatter = .init(), date: @escaping () -> Date = Date.init, fileHandle: @escaping (URL) throws -> FileHandle = FileHandle.init(forUpdating:)) -> FileAppender { + FileAppender( + url: url, + date: date, + dateFormatter: dateFormatter, + writer: { url, data in + guard let fileUpdater = try? fileHandle(url) else { return } + fileUpdater.seekToEndOfFile() + fileUpdater.write(data) + fileUpdater.closeFile() + } + ) + } +} +