--amend IOS-1455
authorXavier Algarra <xavier@pep-project.org>
Mon, 18 Feb 2019 16:55:14 +0100
branchIOS-1455
changeset 77143b863a450416
parent 7713 fb0528c26598
child 7719 dfaf8109cad7
--amend
Submodules/pEpIOSToolbox/pEpIOSToolbox/Other/Logger.swift
subModules/pEpIOSToolbox/pEpIOSToolbox/Log/Logger.swift
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/Submodules/pEpIOSToolbox/pEpIOSToolbox/Other/Logger.swift	Mon Feb 18 16:55:14 2019 +0100
     1.3 @@ -0,0 +1,454 @@
     1.4 +//
     1.5 +//  Logger.swift
     1.6 +//  pEp
     1.7 +//
     1.8 +//  Created by Dirk Zimmermann on 18.12.18.
     1.9 +//  Copyright © 2018 p≡p Security S.A. All rights reserved.
    1.10 +//
    1.11 +
    1.12 +import Foundation
    1.13 +import os.log
    1.14 +import asl
    1.15 +
    1.16 +/**
    1.17 + Thin layer over `os_log` or `asl_logger` where not available.
    1.18 + The fallback to asl is only in effect for iOS 9, and currently
    1.19 + doesn't appear anywhere visible on that platform.
    1.20 + */
    1.21 +public class Logger {
    1.22 +    /**
    1.23 +     Map `os_log` levels.
    1.24 +     */
    1.25 +    public enum Severity {
    1.26 +        /**
    1.27 +         - Note: Not persisted by default, but will be written in case of errors.
    1.28 +         */
    1.29 +        case info
    1.30 +
    1.31 +        /**
    1.32 +         - Note: Not persisted by default, but will be written in case of errors.
    1.33 +         */
    1.34 +        case debug
    1.35 +
    1.36 +        /**
    1.37 +         This is the lowest priority that gets written to disk by default.
    1.38 +         Used like WARN in this logger.
    1.39 +         */
    1.40 +        case `default`
    1.41 +
    1.42 +        case error
    1.43 +
    1.44 +        /**
    1.45 +         - Note: As this is referring to inter-process problems, I don't see a use-case
    1.46 +         for iOS.
    1.47 +         */
    1.48 +        case fault
    1.49 +
    1.50 +        @available(iOS 10.0, macOS 10.12, tvOS 10.0, watchOS 3.0, *)
    1.51 +        public func osLogType() -> OSLogType {
    1.52 +            switch self {
    1.53 +            case .info:
    1.54 +                return .info
    1.55 +            case .debug:
    1.56 +                return .debug
    1.57 +            case .default:
    1.58 +                return .default
    1.59 +            case .error:
    1.60 +                return .error
    1.61 +            case .fault:
    1.62 +                return .fault
    1.63 +            }
    1.64 +        }
    1.65 +
    1.66 +        /**
    1.67 +         Maps the internal criticality of a log  message into a subsystem of ASL levels.
    1.68 +
    1.69 +         ASL has the following:
    1.70 +         * ASL_LEVEL_EMERG
    1.71 +         * ASL_LEVEL_ALERT
    1.72 +         * ASL_LEVEL_CRIT
    1.73 +         * ASL_LEVEL_ERR
    1.74 +         * ASL_LEVEL_WARNING
    1.75 +         * ASL_LEVEL_NOTICE
    1.76 +         * ASL_LEVEL_INFO
    1.77 +         * ASL_LEVEL_DEBUG
    1.78 +         */
    1.79 +        public func aslLevelString() -> String {
    1.80 +            switch self {
    1.81 +            case .default:
    1.82 +                return "ASL_LEVEL_NOTICE"
    1.83 +            case .info:
    1.84 +                return "ASL_LEVEL_INFO"
    1.85 +            case .debug:
    1.86 +                return "ASL_LEVEL_DEBUG"
    1.87 +            case .error:
    1.88 +                return "ASL_LEVEL_ERR"
    1.89 +            case .fault:
    1.90 +                return "ASL_LEVEL_CRIT"
    1.91 +            }
    1.92 +        }
    1.93 +    }
    1.94 +
    1.95 +    // move this loggers to the app
    1.96 +
    1.97 +    public static let frontendLogger = Logger(category: "frontend")
    1.98 +    public static let backendLogger = Logger(category: "backend")
    1.99 +    public static let utilLogger = Logger(category: "util")
   1.100 +    public static let htmlParsingLogger = Logger(category: "htmlParsing")
   1.101 +    public static let modelLogger = Logger(category: "model")
   1.102 +    public static let appDelegateLogger = Logger(category: "appDelegate")
   1.103 +
   1.104 +    public init(subsystem: String = "security.pEp.app.iOS", category: String) {
   1.105 +        self.subsystem = subsystem
   1.106 +        self.category = category
   1.107 +        if #available(iOS 10.0, macOS 10.12, tvOS 10.0, watchOS 3.0, *) {
   1.108 +            osLogger = OSLog(subsystem: subsystem, category: category)
   1.109 +        } else {
   1.110 +            osLogger = nil
   1.111 +        }
   1.112 +    }
   1.113 +
   1.114 +    /**
   1.115 +     Logs to default.
   1.116 +     */
   1.117 +    public func log(function: String = #function,
   1.118 +                    filePath: String = #file,
   1.119 +                    fileLine: Int = #line,
   1.120 +                    _ message: StaticString,
   1.121 +                    _ args: CVarArg...) {
   1.122 +        saveLog(message: message,
   1.123 +                severity: .default,
   1.124 +                function: function,
   1.125 +                filePath: filePath,
   1.126 +                fileLine: fileLine,
   1.127 +                args: args)
   1.128 +    }
   1.129 +
   1.130 +    /**
   1.131 +     os_log doesn't have a warn per se, but default is coming close.
   1.132 +     This is the same as log.
   1.133 +     */
   1.134 +    public func warn(function: String = #function,
   1.135 +                     filePath: String = #file,
   1.136 +                     fileLine: Int = #line,
   1.137 +                     _ message: StaticString,
   1.138 +                     _ args: CVarArg...) {
   1.139 +        saveLog(message: message,
   1.140 +                severity: .default,
   1.141 +                function: function,
   1.142 +                filePath: filePath,
   1.143 +                fileLine: fileLine,
   1.144 +                args: args)
   1.145 +    }
   1.146 +
   1.147 +    /**
   1.148 +     Logs to info.
   1.149 +     */
   1.150 +    public func info(function: String = #function,
   1.151 +                     filePath: String = #file,
   1.152 +                     fileLine: Int = #line,
   1.153 +                     _ message: StaticString,
   1.154 +                     _ args: CVarArg...) {
   1.155 +        saveLog(message: message,
   1.156 +                severity: .info,
   1.157 +                function: function,
   1.158 +                filePath: filePath,
   1.159 +                fileLine: fileLine,
   1.160 +                args: args)
   1.161 +    }
   1.162 +
   1.163 +    /**
   1.164 +     Logs to debug.
   1.165 +     */
   1.166 +    public func debug(function: String = #function,
   1.167 +                      filePath: String = #file,
   1.168 +                      fileLine: Int = #line,
   1.169 +                      _ message: StaticString,
   1.170 +                      _ args: CVarArg...) {
   1.171 +        saveLog(message: message,
   1.172 +                severity: .debug,
   1.173 +                function: function,
   1.174 +                filePath: filePath,
   1.175 +                fileLine: fileLine,
   1.176 +                args: args)
   1.177 +    }
   1.178 +
   1.179 +    /**
   1.180 +     Logs to error.
   1.181 +     */
   1.182 +    public func error(function: String = #function,
   1.183 +                      filePath: String = #file,
   1.184 +                      fileLine: Int = #line,
   1.185 +                      _ message: StaticString,
   1.186 +                      _ args: CVarArg...) {
   1.187 +        saveLog(message: message,
   1.188 +                severity: .error,
   1.189 +                function: function,
   1.190 +                filePath: filePath,
   1.191 +                fileLine: fileLine,
   1.192 +                args: args)
   1.193 +    }
   1.194 +
   1.195 +    /**
   1.196 +     Logs to fault.
   1.197 +     */
   1.198 +    public func fault(function: String = #function,
   1.199 +                      filePath: String = #file,
   1.200 +                      fileLine: Int = #line,
   1.201 +                      _ message: StaticString,
   1.202 +                      _ args: CVarArg...) {
   1.203 +        saveLog(message: message,
   1.204 +                severity: .fault,
   1.205 +                function: function,
   1.206 +                filePath: filePath,
   1.207 +                fileLine: fileLine,
   1.208 +                args: args)
   1.209 +    }
   1.210 +
   1.211 +    public func errorAndCrash(function: String = #function,
   1.212 +                              filePath: String = #file,
   1.213 +                              fileLine: Int = #line,
   1.214 +                              _ message: StaticString,
   1.215 +                              _ args: CVarArg...) {
   1.216 +        saveLog(message: message,
   1.217 +                severity: .fault,
   1.218 +                function: function,
   1.219 +                filePath: filePath,
   1.220 +                fileLine: fileLine,
   1.221 +                args: args)
   1.222 +
   1.223 +        // This will omit the arguments, but it's still matchable
   1.224 +        SystemUtils.crash("\(message)")
   1.225 +    }
   1.226 +
   1.227 +    /**
   1.228 +     Logs an error.
   1.229 +     */
   1.230 +    public func log(function: String = #function,
   1.231 +                    filePath: String = #file,
   1.232 +                    fileLine: Int = #line,
   1.233 +                    error: Error) {
   1.234 +        // Error is not supported by "%@", because it doesn't conform to CVArg
   1.235 +        // and CVArg is only meant for internal types.
   1.236 +        // An alternative would be to use localizedDescription(),
   1.237 +        // but if they are indeed localized you end up with international
   1.238 +        // log messages.
   1.239 +        // So we wrap it into an NSError which does suppord CVArg.
   1.240 +        let nsErr = NSError(domain: subsystem, code: 0, userInfo: [NSUnderlyingErrorKey: error])
   1.241 +
   1.242 +        saveLog(message: "%{public}@",
   1.243 +                severity: .default,
   1.244 +                function: function,
   1.245 +                filePath: filePath,
   1.246 +                fileLine: fileLine,
   1.247 +                args: [nsErr])
   1.248 +    }
   1.249 +
   1.250 +    /**
   1.251 +     Testing only. If you want to test the fallback to ASL logging you may have to call
   1.252 +     this, as all the logging is deferred to a serial queue.
   1.253 +     */
   1.254 +    public func testFlush() {
   1.255 +        if #available(iOS 10.0, macOS 10.12, tvOS 10.0, watchOS 3.0, *) {
   1.256 +            // no sense on these versions
   1.257 +        } else {
   1.258 +            aslLogQueue.sync {
   1.259 +                // nothing
   1.260 +            }
   1.261 +        }
   1.262 +    }
   1.263 +
   1.264 +    /**
   1.265 +     Since this kind of logging is used so often in the codebase, it has its
   1.266 +     own method.
   1.267 +     */
   1.268 +    public func lostMySelf() {
   1.269 +        errorAndCrash("Lost MySelf")
   1.270 +    }
   1.271 +
   1.272 +    private let subsystem: String
   1.273 +    private let category: String
   1.274 +
   1.275 +    private let osLogger: Any?
   1.276 +
   1.277 +    private func saveLog(message: StaticString,
   1.278 +                         severity: Severity,
   1.279 +                         function: String = #function,
   1.280 +                         filePath: String = #file,
   1.281 +                         fileLine: Int = #line,
   1.282 +                         args: [CVarArg]) {
   1.283 +        if #available(iOS 10.0, macOS 10.12, tvOS 10.0, watchOS 3.0, *) {
   1.284 +            osLog(message: message,
   1.285 +                  severity: severity,
   1.286 +                  function: function,
   1.287 +                  filePath: filePath,
   1.288 +                  fileLine: fileLine,
   1.289 +                  args: args)
   1.290 +        } else {
   1.291 +            aslLog(message: message,
   1.292 +                   severity: severity,
   1.293 +                   function: function,
   1.294 +                   filePath: filePath,
   1.295 +                   fileLine: fileLine,
   1.296 +                   args: args)
   1.297 +        }
   1.298 +    }
   1.299 +
   1.300 +    /**
   1.301 +     - Note: If the number of arguments to the format string exceeds 10,
   1.302 +     the logging doesn't work correctly. Can be easily fixed though, if really needed.
   1.303 +     */
   1.304 +    @available(iOS 10.0, macOS 10.12, tvOS 10.0, watchOS 3.0, *)
   1.305 +    private func osLog(message: StaticString,
   1.306 +                       severity: Severity,
   1.307 +                       function: String = #function,
   1.308 +                       filePath: String = #file,
   1.309 +                       fileLine: Int = #line,
   1.310 +                       args: [CVarArg]) {
   1.311 +        let theLog = osLogger as! OSLog
   1.312 +        let theType = severity.osLogType()
   1.313 +
   1.314 +        // I haven't found a way of injecting `function` etc. into the original message for
   1.315 +        // just one call to `os_log`, so the 'position' is logged on a separate line.
   1.316 +        os_log("%@:%d %@:",
   1.317 +               log: theLog,
   1.318 +               type: theType,
   1.319 +               filePath,
   1.320 +               fileLine,
   1.321 +               function)
   1.322 +
   1.323 +        // We have to expand the array of arguments into positional ones.
   1.324 +        // There is no attempt of trying to format the string on our side
   1.325 +        // in order to make use of `os_log`'s fast 'offline' formatting
   1.326 +        // (that is, the work is delayed until actual log display).
   1.327 +        switch args.count {
   1.328 +        case 0:
   1.329 +            os_log(message,
   1.330 +                   log: theLog,
   1.331 +                   type: theType)
   1.332 +        case 1:
   1.333 +            os_log(message,
   1.334 +                   log: theLog,
   1.335 +                   type: theType,
   1.336 +                   args[0])
   1.337 +        case 2:
   1.338 +            os_log(message,
   1.339 +                   log: theLog,
   1.340 +                   type: theType,
   1.341 +                   args[0], args[1])
   1.342 +        case 3:
   1.343 +            os_log(message,
   1.344 +                   log: theLog,
   1.345 +                   type: theType,
   1.346 +                   args[0], args[1], args[2])
   1.347 +        case 4:
   1.348 +            os_log(message,
   1.349 +                   log: theLog,
   1.350 +                   type: theType,
   1.351 +                   args[0], args[1], args[2], args[3])
   1.352 +        case 5:
   1.353 +            os_log(message,
   1.354 +                   log: theLog,
   1.355 +                   type: theType,
   1.356 +                   args[0], args[1], args[2], args[3], args[4])
   1.357 +        case 6:
   1.358 +            os_log(message,
   1.359 +                   log: theLog,
   1.360 +                   type: theType,
   1.361 +                   args[0], args[1], args[2], args[3], args[4], args[5])
   1.362 +        case 7:
   1.363 +            os_log(message,
   1.364 +                   log: theLog,
   1.365 +                   type: theType,
   1.366 +                   args[0], args[1], args[2], args[3], args[4], args[5], args[6])
   1.367 +        case 8:
   1.368 +            os_log(message,
   1.369 +                   log: theLog,
   1.370 +                   type: theType,
   1.371 +                   args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7])
   1.372 +        case 9:
   1.373 +            os_log(message,
   1.374 +                   log: theLog,
   1.375 +                   type: theType,
   1.376 +                   args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7],
   1.377 +                   args[8])
   1.378 +        case 10:
   1.379 +            os_log(message,
   1.380 +                   log: theLog,
   1.381 +                   type: theType,
   1.382 +                   args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7],
   1.383 +                   args[8], args[9])
   1.384 +        default:
   1.385 +            os_log("Using more than 10 parameters",
   1.386 +                   log: theLog,
   1.387 +                   type: .error)
   1.388 +            os_log(message,
   1.389 +                   log: theLog,
   1.390 +                   type: theType,
   1.391 +                   args)
   1.392 +        }
   1.393 +    }
   1.394 +
   1.395 +    private func aslLog(message: StaticString,
   1.396 +                        severity: Severity,
   1.397 +                        function: String = #function,
   1.398 +                        filePath: String = #file,
   1.399 +                        fileLine: Int = #line,
   1.400 +                        args: [CVarArg]) {
   1.401 +        aslLogQueue.async { [weak self] in
   1.402 +            if let theSelf = self {
   1.403 +                let logMessage = asl_new(UInt32(ASL_TYPE_MSG))
   1.404 +
   1.405 +                theSelf.checkASLSuccess(asl_set(logMessage, ASL_KEY_SENDER, theSelf.subsystem))
   1.406 +
   1.407 +                theSelf.checkASLSuccess(asl_set(logMessage, ASL_KEY_FACILITY, theSelf.category))
   1.408 +
   1.409 +                theSelf.checkASLSuccess(asl_set(
   1.410 +                    logMessage,
   1.411 +                    ASL_KEY_MSG,
   1.412 +                    "\(filePath):\(fileLine) \(function): \(message) \(args)"))
   1.413 +
   1.414 +                theSelf.checkASLSuccess(asl_set(logMessage, ASL_KEY_LEVEL, "ASL_LEVEL_ERROR"))
   1.415 +
   1.416 +                let nowDate = Date()
   1.417 +                let dateString = "\(Int(nowDate.timeIntervalSince1970))"
   1.418 +                theSelf.checkASLSuccess(asl_set(logMessage, ASL_KEY_TIME, dateString))
   1.419 +
   1.420 +                theSelf.checkASLSuccess(asl_set(logMessage, ASL_KEY_READ_UID, "-1"))
   1.421 +
   1.422 +                theSelf.checkASLSuccess(asl_send(theSelf.consoleLogger(), logMessage))
   1.423 +
   1.424 +                asl_free(logMessage)
   1.425 +            }
   1.426 +        }
   1.427 +    }
   1.428 +
   1.429 +    private var consoleClient: aslclient?
   1.430 +
   1.431 +    private lazy var aslLogQueue = DispatchQueue(label: "security.pEp.asl.log")
   1.432 +
   1.433 +    private let sender = "security.pEp.app.iOS"
   1.434 +
   1.435 +    private func createConsoleLogger() -> asl_object_t {
   1.436 +        return asl_open(self.sender, subsystem, 0)
   1.437 +    }
   1.438 +
   1.439 +    private func consoleLogger() -> aslclient? {
   1.440 +        if consoleClient == nil {
   1.441 +            consoleClient = createConsoleLogger()
   1.442 +        }
   1.443 +        return consoleClient
   1.444 +    }
   1.445 +
   1.446 +    deinit {
   1.447 +        if consoleClient != nil {
   1.448 +            asl_free(consoleClient)
   1.449 +        }
   1.450 +    }
   1.451 +
   1.452 +    private func checkASLSuccess(_ result: Int32, comment: String = "no comment") {
   1.453 +        if result != 0 {
   1.454 +            print("*** error: \(comment)")
   1.455 +        }
   1.456 +    }
   1.457 +}
     2.1 --- a/subModules/pEpIOSToolbox/pEpIOSToolbox/Log/Logger.swift	Mon Feb 18 16:52:36 2019 +0100
     2.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.3 @@ -1,454 +0,0 @@
     2.4 -//
     2.5 -//  Logger.swift
     2.6 -//  pEp
     2.7 -//
     2.8 -//  Created by Dirk Zimmermann on 18.12.18.
     2.9 -//  Copyright © 2018 p≡p Security S.A. All rights reserved.
    2.10 -//
    2.11 -
    2.12 -import Foundation
    2.13 -import os.log
    2.14 -import asl
    2.15 -
    2.16 -/**
    2.17 - Thin layer over `os_log` or `asl_logger` where not available.
    2.18 - The fallback to asl is only in effect for iOS 9, and currently
    2.19 - doesn't appear anywhere visible on that platform.
    2.20 - */
    2.21 -public class Logger {
    2.22 -    /**
    2.23 -     Map `os_log` levels.
    2.24 -     */
    2.25 -    public enum Severity {
    2.26 -        /**
    2.27 -         - Note: Not persisted by default, but will be written in case of errors.
    2.28 -         */
    2.29 -        case info
    2.30 -
    2.31 -        /**
    2.32 -         - Note: Not persisted by default, but will be written in case of errors.
    2.33 -         */
    2.34 -        case debug
    2.35 -
    2.36 -        /**
    2.37 -         This is the lowest priority that gets written to disk by default.
    2.38 -         Used like WARN in this logger.
    2.39 -         */
    2.40 -        case `default`
    2.41 -
    2.42 -        case error
    2.43 -
    2.44 -        /**
    2.45 -         - Note: As this is referring to inter-process problems, I don't see a use-case
    2.46 -         for iOS.
    2.47 -         */
    2.48 -        case fault
    2.49 -
    2.50 -        @available(iOS 10.0, macOS 10.12, tvOS 10.0, watchOS 3.0, *)
    2.51 -        public func osLogType() -> OSLogType {
    2.52 -            switch self {
    2.53 -            case .info:
    2.54 -                return .info
    2.55 -            case .debug:
    2.56 -                return .debug
    2.57 -            case .default:
    2.58 -                return .default
    2.59 -            case .error:
    2.60 -                return .error
    2.61 -            case .fault:
    2.62 -                return .fault
    2.63 -            }
    2.64 -        }
    2.65 -
    2.66 -        /**
    2.67 -         Maps the internal criticality of a log  message into a subsystem of ASL levels.
    2.68 -
    2.69 -         ASL has the following:
    2.70 -         * ASL_LEVEL_EMERG
    2.71 -         * ASL_LEVEL_ALERT
    2.72 -         * ASL_LEVEL_CRIT
    2.73 -         * ASL_LEVEL_ERR
    2.74 -         * ASL_LEVEL_WARNING
    2.75 -         * ASL_LEVEL_NOTICE
    2.76 -         * ASL_LEVEL_INFO
    2.77 -         * ASL_LEVEL_DEBUG
    2.78 -         */
    2.79 -        public func aslLevelString() -> String {
    2.80 -            switch self {
    2.81 -            case .default:
    2.82 -                return "ASL_LEVEL_NOTICE"
    2.83 -            case .info:
    2.84 -                return "ASL_LEVEL_INFO"
    2.85 -            case .debug:
    2.86 -                return "ASL_LEVEL_DEBUG"
    2.87 -            case .error:
    2.88 -                return "ASL_LEVEL_ERR"
    2.89 -            case .fault:
    2.90 -                return "ASL_LEVEL_CRIT"
    2.91 -            }
    2.92 -        }
    2.93 -    }
    2.94 -
    2.95 -    // move this loggers to the app
    2.96 -
    2.97 -    public static let frontendLogger = Logger(category: "frontend")
    2.98 -    public static let backendLogger = Logger(category: "backend")
    2.99 -    public static let utilLogger = Logger(category: "util")
   2.100 -    public static let htmlParsingLogger = Logger(category: "htmlParsing")
   2.101 -    public static let modelLogger = Logger(category: "model")
   2.102 -    public static let appDelegateLogger = Logger(category: "appDelegate")
   2.103 -
   2.104 -    public init(subsystem: String = "security.pEp.app.iOS", category: String) {
   2.105 -        self.subsystem = subsystem
   2.106 -        self.category = category
   2.107 -        if #available(iOS 10.0, macOS 10.12, tvOS 10.0, watchOS 3.0, *) {
   2.108 -            osLogger = OSLog(subsystem: subsystem, category: category)
   2.109 -        } else {
   2.110 -            osLogger = nil
   2.111 -        }
   2.112 -    }
   2.113 -
   2.114 -    /**
   2.115 -     Logs to default.
   2.116 -     */
   2.117 -    public func log(function: String = #function,
   2.118 -                    filePath: String = #file,
   2.119 -                    fileLine: Int = #line,
   2.120 -                    _ message: StaticString,
   2.121 -                    _ args: CVarArg...) {
   2.122 -        saveLog(message: message,
   2.123 -                severity: .default,
   2.124 -                function: function,
   2.125 -                filePath: filePath,
   2.126 -                fileLine: fileLine,
   2.127 -                args: args)
   2.128 -    }
   2.129 -
   2.130 -    /**
   2.131 -     os_log doesn't have a warn per se, but default is coming close.
   2.132 -     This is the same as log.
   2.133 -     */
   2.134 -    public func warn(function: String = #function,
   2.135 -                     filePath: String = #file,
   2.136 -                     fileLine: Int = #line,
   2.137 -                     _ message: StaticString,
   2.138 -                     _ args: CVarArg...) {
   2.139 -        saveLog(message: message,
   2.140 -                severity: .default,
   2.141 -                function: function,
   2.142 -                filePath: filePath,
   2.143 -                fileLine: fileLine,
   2.144 -                args: args)
   2.145 -    }
   2.146 -
   2.147 -    /**
   2.148 -     Logs to info.
   2.149 -     */
   2.150 -    public func info(function: String = #function,
   2.151 -                     filePath: String = #file,
   2.152 -                     fileLine: Int = #line,
   2.153 -                     _ message: StaticString,
   2.154 -                     _ args: CVarArg...) {
   2.155 -        saveLog(message: message,
   2.156 -                severity: .info,
   2.157 -                function: function,
   2.158 -                filePath: filePath,
   2.159 -                fileLine: fileLine,
   2.160 -                args: args)
   2.161 -    }
   2.162 -
   2.163 -    /**
   2.164 -     Logs to debug.
   2.165 -     */
   2.166 -    public func debug(function: String = #function,
   2.167 -                      filePath: String = #file,
   2.168 -                      fileLine: Int = #line,
   2.169 -                      _ message: StaticString,
   2.170 -                      _ args: CVarArg...) {
   2.171 -        saveLog(message: message,
   2.172 -                severity: .debug,
   2.173 -                function: function,
   2.174 -                filePath: filePath,
   2.175 -                fileLine: fileLine,
   2.176 -                args: args)
   2.177 -    }
   2.178 -
   2.179 -    /**
   2.180 -     Logs to error.
   2.181 -     */
   2.182 -    public func error(function: String = #function,
   2.183 -                      filePath: String = #file,
   2.184 -                      fileLine: Int = #line,
   2.185 -                      _ message: StaticString,
   2.186 -                      _ args: CVarArg...) {
   2.187 -        saveLog(message: message,
   2.188 -                severity: .error,
   2.189 -                function: function,
   2.190 -                filePath: filePath,
   2.191 -                fileLine: fileLine,
   2.192 -                args: args)
   2.193 -    }
   2.194 -
   2.195 -    /**
   2.196 -     Logs to fault.
   2.197 -     */
   2.198 -    public func fault(function: String = #function,
   2.199 -                      filePath: String = #file,
   2.200 -                      fileLine: Int = #line,
   2.201 -                      _ message: StaticString,
   2.202 -                      _ args: CVarArg...) {
   2.203 -        saveLog(message: message,
   2.204 -                severity: .fault,
   2.205 -                function: function,
   2.206 -                filePath: filePath,
   2.207 -                fileLine: fileLine,
   2.208 -                args: args)
   2.209 -    }
   2.210 -
   2.211 -    public func errorAndCrash(function: String = #function,
   2.212 -                              filePath: String = #file,
   2.213 -                              fileLine: Int = #line,
   2.214 -                              _ message: StaticString,
   2.215 -                              _ args: CVarArg...) {
   2.216 -        saveLog(message: message,
   2.217 -                severity: .fault,
   2.218 -                function: function,
   2.219 -                filePath: filePath,
   2.220 -                fileLine: fileLine,
   2.221 -                args: args)
   2.222 -
   2.223 -        // This will omit the arguments, but it's still matchable
   2.224 -        SystemUtils.crash("\(message)")
   2.225 -    }
   2.226 -
   2.227 -    /**
   2.228 -     Logs an error.
   2.229 -     */
   2.230 -    public func log(function: String = #function,
   2.231 -                    filePath: String = #file,
   2.232 -                    fileLine: Int = #line,
   2.233 -                    error: Error) {
   2.234 -        // Error is not supported by "%@", because it doesn't conform to CVArg
   2.235 -        // and CVArg is only meant for internal types.
   2.236 -        // An alternative would be to use localizedDescription(),
   2.237 -        // but if they are indeed localized you end up with international
   2.238 -        // log messages.
   2.239 -        // So we wrap it into an NSError which does suppord CVArg.
   2.240 -        let nsErr = NSError(domain: subsystem, code: 0, userInfo: [NSUnderlyingErrorKey: error])
   2.241 -
   2.242 -        saveLog(message: "%{public}@",
   2.243 -                severity: .default,
   2.244 -                function: function,
   2.245 -                filePath: filePath,
   2.246 -                fileLine: fileLine,
   2.247 -                args: [nsErr])
   2.248 -    }
   2.249 -
   2.250 -    /**
   2.251 -     Testing only. If you want to test the fallback to ASL logging you may have to call
   2.252 -     this, as all the logging is deferred to a serial queue.
   2.253 -     */
   2.254 -    public func testFlush() {
   2.255 -        if #available(iOS 10.0, macOS 10.12, tvOS 10.0, watchOS 3.0, *) {
   2.256 -            // no sense on these versions
   2.257 -        } else {
   2.258 -            aslLogQueue.sync {
   2.259 -                // nothing
   2.260 -            }
   2.261 -        }
   2.262 -    }
   2.263 -
   2.264 -    /**
   2.265 -     Since this kind of logging is used so often in the codebase, it has its
   2.266 -     own method.
   2.267 -     */
   2.268 -    public func lostMySelf() {
   2.269 -        errorAndCrash("Lost MySelf")
   2.270 -    }
   2.271 -
   2.272 -    private let subsystem: String
   2.273 -    private let category: String
   2.274 -
   2.275 -    private let osLogger: Any?
   2.276 -
   2.277 -    private func saveLog(message: StaticString,
   2.278 -                         severity: Severity,
   2.279 -                         function: String = #function,
   2.280 -                         filePath: String = #file,
   2.281 -                         fileLine: Int = #line,
   2.282 -                         args: [CVarArg]) {
   2.283 -        if #available(iOS 10.0, macOS 10.12, tvOS 10.0, watchOS 3.0, *) {
   2.284 -            osLog(message: message,
   2.285 -                  severity: severity,
   2.286 -                  function: function,
   2.287 -                  filePath: filePath,
   2.288 -                  fileLine: fileLine,
   2.289 -                  args: args)
   2.290 -        } else {
   2.291 -            aslLog(message: message,
   2.292 -                   severity: severity,
   2.293 -                   function: function,
   2.294 -                   filePath: filePath,
   2.295 -                   fileLine: fileLine,
   2.296 -                   args: args)
   2.297 -        }
   2.298 -    }
   2.299 -
   2.300 -    /**
   2.301 -     - Note: If the number of arguments to the format string exceeds 10,
   2.302 -     the logging doesn't work correctly. Can be easily fixed though, if really needed.
   2.303 -     */
   2.304 -    @available(iOS 10.0, macOS 10.12, tvOS 10.0, watchOS 3.0, *)
   2.305 -    private func osLog(message: StaticString,
   2.306 -                       severity: Severity,
   2.307 -                       function: String = #function,
   2.308 -                       filePath: String = #file,
   2.309 -                       fileLine: Int = #line,
   2.310 -                       args: [CVarArg]) {
   2.311 -        let theLog = osLogger as! OSLog
   2.312 -        let theType = severity.osLogType()
   2.313 -
   2.314 -        // I haven't found a way of injecting `function` etc. into the original message for
   2.315 -        // just one call to `os_log`, so the 'position' is logged on a separate line.
   2.316 -        os_log("%@:%d %@:",
   2.317 -               log: theLog,
   2.318 -               type: theType,
   2.319 -               filePath,
   2.320 -               fileLine,
   2.321 -               function)
   2.322 -
   2.323 -        // We have to expand the array of arguments into positional ones.
   2.324 -        // There is no attempt of trying to format the string on our side
   2.325 -        // in order to make use of `os_log`'s fast 'offline' formatting
   2.326 -        // (that is, the work is delayed until actual log display).
   2.327 -        switch args.count {
   2.328 -        case 0:
   2.329 -            os_log(message,
   2.330 -                   log: theLog,
   2.331 -                   type: theType)
   2.332 -        case 1:
   2.333 -            os_log(message,
   2.334 -                   log: theLog,
   2.335 -                   type: theType,
   2.336 -                   args[0])
   2.337 -        case 2:
   2.338 -            os_log(message,
   2.339 -                   log: theLog,
   2.340 -                   type: theType,
   2.341 -                   args[0], args[1])
   2.342 -        case 3:
   2.343 -            os_log(message,
   2.344 -                   log: theLog,
   2.345 -                   type: theType,
   2.346 -                   args[0], args[1], args[2])
   2.347 -        case 4:
   2.348 -            os_log(message,
   2.349 -                   log: theLog,
   2.350 -                   type: theType,
   2.351 -                   args[0], args[1], args[2], args[3])
   2.352 -        case 5:
   2.353 -            os_log(message,
   2.354 -                   log: theLog,
   2.355 -                   type: theType,
   2.356 -                   args[0], args[1], args[2], args[3], args[4])
   2.357 -        case 6:
   2.358 -            os_log(message,
   2.359 -                   log: theLog,
   2.360 -                   type: theType,
   2.361 -                   args[0], args[1], args[2], args[3], args[4], args[5])
   2.362 -        case 7:
   2.363 -            os_log(message,
   2.364 -                   log: theLog,
   2.365 -                   type: theType,
   2.366 -                   args[0], args[1], args[2], args[3], args[4], args[5], args[6])
   2.367 -        case 8:
   2.368 -            os_log(message,
   2.369 -                   log: theLog,
   2.370 -                   type: theType,
   2.371 -                   args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7])
   2.372 -        case 9:
   2.373 -            os_log(message,
   2.374 -                   log: theLog,
   2.375 -                   type: theType,
   2.376 -                   args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7],
   2.377 -                   args[8])
   2.378 -        case 10:
   2.379 -            os_log(message,
   2.380 -                   log: theLog,
   2.381 -                   type: theType,
   2.382 -                   args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7],
   2.383 -                   args[8], args[9])
   2.384 -        default:
   2.385 -            os_log("Using more than 10 parameters",
   2.386 -                   log: theLog,
   2.387 -                   type: .error)
   2.388 -            os_log(message,
   2.389 -                   log: theLog,
   2.390 -                   type: theType,
   2.391 -                   args)
   2.392 -        }
   2.393 -    }
   2.394 -
   2.395 -    private func aslLog(message: StaticString,
   2.396 -                        severity: Severity,
   2.397 -                        function: String = #function,
   2.398 -                        filePath: String = #file,
   2.399 -                        fileLine: Int = #line,
   2.400 -                        args: [CVarArg]) {
   2.401 -        aslLogQueue.async { [weak self] in
   2.402 -            if let theSelf = self {
   2.403 -                let logMessage = asl_new(UInt32(ASL_TYPE_MSG))
   2.404 -
   2.405 -                theSelf.checkASLSuccess(asl_set(logMessage, ASL_KEY_SENDER, theSelf.subsystem))
   2.406 -
   2.407 -                theSelf.checkASLSuccess(asl_set(logMessage, ASL_KEY_FACILITY, theSelf.category))
   2.408 -
   2.409 -                theSelf.checkASLSuccess(asl_set(
   2.410 -                    logMessage,
   2.411 -                    ASL_KEY_MSG,
   2.412 -                    "\(filePath):\(fileLine) \(function): \(message) \(args)"))
   2.413 -
   2.414 -                theSelf.checkASLSuccess(asl_set(logMessage, ASL_KEY_LEVEL, "ASL_LEVEL_ERROR"))
   2.415 -
   2.416 -                let nowDate = Date()
   2.417 -                let dateString = "\(Int(nowDate.timeIntervalSince1970))"
   2.418 -                theSelf.checkASLSuccess(asl_set(logMessage, ASL_KEY_TIME, dateString))
   2.419 -
   2.420 -                theSelf.checkASLSuccess(asl_set(logMessage, ASL_KEY_READ_UID, "-1"))
   2.421 -
   2.422 -                theSelf.checkASLSuccess(asl_send(theSelf.consoleLogger(), logMessage))
   2.423 -
   2.424 -                asl_free(logMessage)
   2.425 -            }
   2.426 -        }
   2.427 -    }
   2.428 -
   2.429 -    private var consoleClient: aslclient?
   2.430 -
   2.431 -    private lazy var aslLogQueue = DispatchQueue(label: "security.pEp.asl.log")
   2.432 -
   2.433 -    private let sender = "security.pEp.app.iOS"
   2.434 -
   2.435 -    private func createConsoleLogger() -> asl_object_t {
   2.436 -        return asl_open(self.sender, subsystem, 0)
   2.437 -    }
   2.438 -
   2.439 -    private func consoleLogger() -> aslclient? {
   2.440 -        if consoleClient == nil {
   2.441 -            consoleClient = createConsoleLogger()
   2.442 -        }
   2.443 -        return consoleClient
   2.444 -    }
   2.445 -
   2.446 -    deinit {
   2.447 -        if consoleClient != nil {
   2.448 -            asl_free(consoleClient)
   2.449 -        }
   2.450 -    }
   2.451 -
   2.452 -    private func checkASLSuccess(_ result: Int32, comment: String = "no comment") {
   2.453 -        if result != 0 {
   2.454 -            print("*** error: \(comment)")
   2.455 -        }
   2.456 -    }
   2.457 -}