- Discover an approach to structure & architecture your app to have a flexible & scalable logging layer.
- Learn why it is necessary to do your own log layer ;)
iOS app Layer architecture for logs From yesterday to powerful tools Issues & need on an iOS app Create your own logger layer Flexible & Scalable logs on iOS
apps / feature = multiple loggers One entry point but multiple available destinations No need to update your code Logger Basic output console SwiftyBeaver NSLogger Logmatic Firebase / Fabric
isEnabled = true public let rawValue: String public init(rawValue: String) { self.rawValue = rawValue } public static let app = LogContext(rawValue: "App") public static let layout = LogContext(rawValue: "View Layout") public static let routing = LogContext(rawValue: "Routing") public static let service = LogContext(rawValue: "Service") public static let model = LogContext(rawValue: Model") public static func custom(_ value: String, enabled: Bool = true) -> LogContext { var context = LogContext(rawValue: value) context.isEnabled = enabled return context } }
" App") public static let layout = LogContext(rawValue: " View Layout") public static let routing = LogContext(rawValue: "⛵ Routing") public static let service = LogContext(rawValue: " Service") public static let model = LogContext(rawValue: " Model")
= "$DHH:mm:ss.SSS$d $C$L [$i-$X]$c $N.$F:$l - $M" open var minLevel = Logger.Level.verbose /// set custom log level colors for each level open var levelColor = LevelColor() // For a colored log level word in a logged line // empty on default public struct LevelColor { public var verbose = "" // silver public var debug = "" // green public var info = "" // blue public var warning = "" // yellow public var error = "" // red } open var levelString = LevelString() let moduleIdentification: Logger.Identification public init(identification: Logger.Identification, level: Logger.Level = .verbose) { open func send(_ level: Logger.Level, msg: String, thread: String, file: String, function: String, line: Int, context: LogContext = LogContext.app) -> String? {}
class Logger { // a set of active destinations public private(set) var destinations = Set<LoggerDestination>() // Destinations private lazy var basicDestination = BasicConsoleDestination(loggerIdentifier: self.identifier) private lazy var nsloggerDestination = NSLoggerDestination(loggerIdentifier: self.identifier) // MARK: Destinations set up public func setBasicConsole(enabled isEnabled: Bool) { if isEnabled { self.addDestination(self.basicDestination) } else { self.removeDestination(self.basicDestination) } } public func setNSLogger(enabled isEnabled: Bool) {}
LogContext) -> OSLog { let category = context.rawValue let subsystem = self.moduleIdentification.bundleIdentifier let customLog = OSLog(subsystem: subsystem, category: category) return customLog } func osLogLevelRelated(to logLevel: Logger.Level) -> OSLogType { var logType: OSLogType switch logLevel { case .debug: logType = .debug case .verbose: logType = .default case .info: logType = .info case .warning: //We use "error" here because of indicator in the Console logType = .error case .error: //We use "fault" here because of indicator in the Console logType = .fault } return logType } }