// // Copyright 2023 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only // import CocoaLumberjack import Foundation final class LogFormatter: NSObject, DDLogFormatter { func format(message logMessage: DDLogMessage) -> String? { return Self.formatLogMessage(logMessage, modifiedMessage: nil) } static func formatLogMessage(_ logMessage: DDLogMessage, modifiedMessage: String?) -> String { let timestamp = dateFormatter.string(from: logMessage.timestamp) let level = Self.formattedLevel(for: logMessage.flag) let location = Self.formattedLocation(logMessage: logMessage) let message = modifiedMessage ?? logMessage.message return "\(timestamp) \(level) \(location)\(message)" } private static let dateFormatter: DateFormatter = { // Copied from DDLogFileFormatterDefault. let formatter = DateFormatter() formatter.formatterBehavior = .behavior10_4 formatter.locale = Locale(identifier: "en_US_POSIX") formatter.timeZone = TimeZone(secondsFromGMT: 0) formatter.dateFormat = "yyyy/MM/dd HH:mm:ss:SSS" return formatter }() private static func formattedLevel(for flag: DDLogFlag) -> String { if flag.contains(.error) { return "ERR❤️" } // Error if flag.contains(.warning) { return "WRN🧡" } // Warning if flag.contains(.info) { return "INF💛" } // Info if flag.contains(.debug) { return "DBG💚" } // Debug if flag.contains(.verbose) { return "VRB💙" } // Verbose return "UNK💜" // Unknown } private static func formattedLocation(logMessage: DDLogMessage) -> String { var file = logMessage.file file = file.replacingOccurrences(of: ".swift", with: "") let line = logMessage.line // Drop the arguments from the function name. var function = logMessage.function ?? "" if let parensIndex = function.firstIndex(of: "(") { function = String(function[..