| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309 |
- import os.log
- import os.signpost
- import UIKit
- var LoggerTestMode = false
- private let baseReporter = FreeAPSApp.resolver.resolve(GroupedIssueReporter.self)!
- private let router = FreeAPSApp.resolver.resolve(Router.self)!
- let loggerLock = NSRecursiveLock()
- func debug(
- _ category: Logger.Category,
- _ message: @autoclosure () -> String,
- printToConsole: Bool = true,
- file: String = #file,
- function: String = #function,
- line: UInt = #line
- ) {
- let msg = message()
- DispatchWorkItem(qos: .userInteractive, flags: .enforceQoS) {
- loggerLock.perform {
- category.logger.debug(msg, printToConsole: printToConsole, file: file, function: function, line: line)
- }
- }.perform()
- }
- func info(
- _ category: Logger.Category,
- _ message: String,
- file: String = #file,
- function: String = #function,
- line: UInt = #line
- ) {
- DispatchWorkItem(qos: .userInteractive, flags: .enforceQoS) {
- loggerLock.perform {
- category.logger.info(message, file: file, function: function, line: line)
- }
- }.perform()
- }
- func warning(
- _ category: Logger.Category,
- _ message: String,
- description: String? = nil,
- error maybeError: Swift.Error? = nil,
- file: String = #file,
- function: String = #function,
- line: UInt = #line
- ) {
- DispatchWorkItem(qos: .userInteractive, flags: .enforceQoS) {
- loggerLock.perform {
- category.logger.warning(
- message,
- description: description,
- error: maybeError,
- file: file,
- function: function,
- line: line
- )
- }
- }.perform()
- }
- func error(
- _ category: Logger.Category,
- _ message: String,
- description: String? = nil,
- error maybeError: Swift.Error? = nil,
- file: String = #file,
- function: String = #function,
- line: UInt = #line
- ) -> Never {
- loggerLock.perform {
- category.logger.errorWithoutFatalError(
- message,
- description: description,
- error: maybeError,
- file: file,
- function: function,
- line: line
- )
- fatalError(
- "\(message) @ \(String(describing: description)) @ \(String(describing: maybeError)) @ \(file) @ \(function) @ \(line)"
- )
- }
- }
- func check(
- _ condition: @autoclosure () -> Bool,
- _ message: @autoclosure () -> String,
- description: @autoclosure () -> String? = nil,
- file: String = #file,
- function: String = #function,
- line: UInt = #line
- ) {
- guard !condition() else { return }
- let msg = message()
- let descr = description()
- loggerLock.perform {
- warning(.default, msg, description: descr, file: file.file, function: function, line: line)
- }
- }
- final class Logger {
- static let `default` = Logger(category: .default, reporter: baseReporter)
- static let service = Logger(category: .service, reporter: baseReporter)
- static let businessLogic = Logger(category: .businessLogic, reporter: baseReporter)
- static let openAPS = Logger(category: .openAPS, reporter: baseReporter)
- static let deviceManager = Logger(category: .deviceManager, reporter: baseReporter)
- static let apsManager = Logger(category: .apsManager, reporter: baseReporter)
- static let nightscout = Logger(category: .nightscout, reporter: baseReporter)
- enum Category: String {
- case `default`
- case service
- case businessLogic
- case openAPS
- case deviceManager
- case apsManager
- case nightscout
- var name: String {
- rawValue.capitalizingFirstLetter()
- }
- var logger: Logger {
- switch self {
- case .default: return .default
- case .service: return .service
- case .businessLogic: return .businessLogic
- case .openAPS: return .openAPS
- case .deviceManager: return .deviceManager
- case .apsManager: return .apsManager
- case .nightscout: return .nightscout
- }
- }
- fileprivate var log: OSLog {
- let subsystem = Bundle.main.bundleIdentifier!
- switch self {
- case .default: return OSLog.default
- case .apsManager,
- .businessLogic,
- .deviceManager,
- .nightscout,
- .openAPS,
- .service:
- return OSLog(subsystem: subsystem, category: name)
- }
- }
- }
- fileprivate enum Error: Swift.Error {
- case error(String)
- case errorWithInnerError(String, Swift.Error)
- case errorWithDescription(String, String)
- case errorWithDescriptionAndInnerError(String, String, Swift.Error)
- private func domain() -> String {
- switch self {
- case let .error(domain),
- let .errorWithDescription(domain, _),
- let .errorWithDescriptionAndInnerError(domain, _, _),
- let .errorWithInnerError(domain, _):
- return domain
- }
- }
- private func innerError() -> Swift.Error? {
- switch self {
- case let .errorWithDescriptionAndInnerError(_, _, error),
- let .errorWithInnerError(_, error):
- return error
- default: return nil
- }
- }
- func asNSError() -> NSError {
- var info: [String: Any] = ["Description": String(describing: self)]
- if let error = innerError() {
- info["Error"] = String(describing: error)
- }
- return NSError(domain: domain(), code: -1, userInfo: info)
- }
- }
- private let category: Category
- private let reporter: IssueReporter
- let log: OSLog
- private init(category: Category, reporter: IssueReporter) {
- self.category = category
- self.reporter = reporter
- log = category.log
- }
- static func setup() {
- loggerLock.perform {
- baseReporter.setup()
- }
- }
- func debug(
- _ message: @autoclosure () -> String,
- printToConsole: Bool = true,
- file: String = #file,
- function: String = #function,
- line: UInt = #line
- ) {
- let message = "DEV: \(message())"
- if printToConsole {
- os_log("%@ - %@ - %d %{public}@", log: log, type: .debug, file.file, function, line, message)
- }
- reporter.log(category.name, message, file: file, function: function, line: line)
- }
- func info(
- _ message: String,
- file: String = #file,
- function: String = #function,
- line: UInt = #line
- ) {
- let printedMessage = "INFO: \(message)"
- os_log("%@ - %@ - %d %{public}@", log: log, type: .info, file.file, function, line, printedMessage)
- reporter.log(category.name, printedMessage, file: file, function: function, line: line)
- showAlert(message, type: .info)
- }
- func warning(
- _ message: String,
- description: String? = nil,
- error maybeError: Swift.Error? = nil,
- file: String = #file,
- function: String = #function,
- line: UInt = #line
- ) {
- let loggerError = maybeError.loggerError(message: message, withDescription: description)
- let message = "WARN: \(String(describing: loggerError))"
- os_log("%@ - %@ - %d %{public}@", log: log, type: .default, file.file, function, line, message)
- reporter.log(category.name, message, file: file, function: function, line: line)
- if !LoggerTestMode, maybeError?.shouldReportNonFatalIssue ?? true {
- reporter.reportNonFatalIssue(withError: loggerError.asNSError())
- }
- }
- func error(
- _ message: String,
- description: String? = nil,
- error maybeError: Swift.Error? = nil,
- file: String = #file,
- function: String = #function,
- line: UInt = #line
- ) -> Never {
- errorWithoutFatalError(message, description: description, error: maybeError, file: file, function: function, line: line)
- fatalError(
- "\(message) @ \(String(describing: description)) @ \(String(describing: maybeError)) @ \(file) @ \(function) @ \(line)"
- )
- }
- private func showAlert(_ message: String, type: MessageType = .info) {
- DispatchQueue.main.async {
- let messageCont = MessageContent(content: message, type: type)
- router.alertMessage.send(messageCont)
- }
- }
- fileprivate func errorWithoutFatalError(
- _ message: String,
- description: String? = nil,
- error maybeError: Swift.Error? = nil,
- file: String = #file,
- function: String = #function,
- line: UInt = #line
- ) {
- let loggerError = maybeError.loggerError(message: message, withDescription: description)
- let message = "ERR: \(String(describing: loggerError))"
- os_log("%@ - %@ - %d %{public}@", log: log, type: .error, file.file, function, line, message)
- reporter.log(category.name, message, file: file, function: function, line: line)
- reporter.reportNonFatalIssue(withError: loggerError.asNSError())
- }
- }
- private extension Optional where Wrapped == Swift.Error {
- func loggerError(message: String, withDescription description: String?) -> Logger.Error {
- switch (description, self) {
- case (nil, nil):
- return .error(message)
- case let (descr?, nil):
- return .errorWithDescription(message, descr)
- case let (nil, error?):
- return .errorWithInnerError(message, error)
- case let (descr?, error?):
- return .errorWithDescriptionAndInnerError(message, descr, error)
- }
- }
- }
- private extension String {
- var file: String { components(separatedBy: "/").last ?? "" }
- }
|