diff --git a/Assets/Xcode Templates/ZamzamKit/Clean Worker.xctemplate/___FILEBASENAME___NetworkStore.swift b/Assets/Xcode Templates/ZamzamKit/Clean Worker.xctemplate/___FILEBASENAME___NetworkStore.swift
index ad843467..efedd7df 100644
--- a/Assets/Xcode Templates/ZamzamKit/Clean Worker.xctemplate/___FILEBASENAME___NetworkStore.swift
+++ b/Assets/Xcode Templates/ZamzamKit/Clean Worker.xctemplate/___FILEBASENAME___NetworkStore.swift
@@ -1,11 +1,12 @@
//___FILEHEADER___
-import ZamzamKit
+import ZamzamCore
-public struct ___VARIABLE_productName:identifier___NetworkStore: ___VARIABLE_productName:identifier___Store, Loggable {
+public struct ___VARIABLE_productName:identifier___NetworkStore: ___VARIABLE_productName:identifier___Store {
+ private let log: LogWorkerType
- public init() {
-
+ public init(log: LogWorkerType) {
+ self.log = log
}
}
@@ -16,7 +17,7 @@ public extension ___VARIABLE_productName:identifier___NetworkStore {
// Handle errors if applicable
guard let value = $0.value, $0.isSuccess else {
let error = DataError(from: $0.error)
- self.Log(error: "An error occured while fetching ___VARIABLE_productName:identifier___: \($0.error?.serverDescription ?? "unknown")")
+ self.log.error("An error occured while fetching ___VARIABLE_productName:identifier___: \($0.error?.serverDescription ?? "unknown")")
return completion(.failure(error))
}
@@ -34,7 +35,7 @@ public extension ___VARIABLE_productName:identifier___NetworkStore {
)
guard let data = payload.data, payload.status == .success else {
- self.Log(error: "An error occured while fetching ___VARIABLE_productName:identifier___, data nil or server status error: \(String(describing: payload.errors)).")
+ self.log.error("An error occured while fetching ___VARIABLE_productName:identifier___, data nil or server status error: \(String(describing: payload.errors)).")
return DispatchQueue.main.async { completion(.failure(.unknownReason(nil))) }
}
@@ -42,7 +43,7 @@ public extension ___VARIABLE_productName:identifier___NetworkStore {
completion(.success(data.objects))
}
} catch {
- self.Log(error: "An error occured while parsing ___VARIABLE_productName:identifier___: \(error).")
+ self.log.error("An error occured while parsing ___VARIABLE_productName:identifier___: \(error).")
return DispatchQueue.main.async { completion(.failure(.parseFailure(error))) }
}
}
diff --git a/README.md b/README.md
index 19c9c1a5..4b0e78bd 100644
--- a/README.md
+++ b/README.md
@@ -622,21 +622,16 @@ someStruct.isRunningOnSimulator -> false
```swift
// Subclass and install to pass lifecycle events to loaded plugins
@UIApplicationMain
-class AppDelegate: ApplicationPluginDelegate {
+class AppDelegate: ApplicationPluggableDelegate {
- private(set) lazy var plugins: [ApplicationPlugin] = [
+ override func plugins() -> [ApplicationPlugin] {[
LoggerPlugin(),
NotificationPlugin()
- ]
-
- override init() {
- super.init()
- install(plugins)
- }
+ ]}
}
```
```swift
-// Each application plugin has access to the AppDelegate lifecycle events
+// Each application plugin has access to the `AppDelegate` lifecycle events
final class LoggerPlugin: ApplicationPlugin {
private let log = Logger()
@@ -659,6 +654,32 @@ final class LoggerPlugin: ApplicationPlugin {
}
}
```
+
+> Split up `SceneDelegate` into plugins:
+```swift
+// Subclass and install to pass lifecycle events to loaded plugins
+class SceneDelegate: ScenePluggableDelegate {
+
+ override func plugins() -> [ScenePlugin] {[
+ LoggerPlugin(),
+ NotificationPlugin()
+ ]}
+}
+```
+```swift
+// Each application plugin has access to the `SceneDelegate` lifecycle events
+final class LoggerPlugin: ScenePlugin {
+ private let log = Logger()
+
+ func sceneWillEnterForeground() {
+ log.info("Scene will enter foreground.")
+ }
+
+ func sceneDidEnterBackground() {
+ log.info("Scene did enter background.")
+ }
+}
+```
@@ -761,6 +782,27 @@ myLabel3.text = .localized(.next)
```
+
+Logger
+
+> Create loggers that conform to `LogStore` and add to `LogWorker` (console and `os_log` are included):
+```swift
+let log: LogWorkerType = LogWorker(
+ stores: [
+ LogConsoleStore(minLevel: .debug),
+ LogOSStore(
+ minLevel: .warning,
+ subsystem: "io.zamzam.Basem-Emara",
+ category: "Application"
+ ),
+ MyCustomLogger()
+ ]
+)
+
+log.error("There was an error.")
+```
+
+
SystemConfiguration
@@ -999,8 +1041,8 @@ UNUserNotificationCenter.current().register(
authorizations: [.alert, .badge, .sound],
completion: { granted in
granted
- ? log(debug: "Authorization for notification succeeded.")
- : log(warn: "Authorization for notification not given.")
+ ? log.debug("Authorization for notification succeeded.")
+ : log.warn("Authorization for notification not given.")
}
)
```
@@ -1085,7 +1127,7 @@ UNUserNotificationCenter.current().add(
```swift
UNNotificationAttachment.download(from: urlString) {
guard $0.isSuccess, let attachment = $0.value else {
- return log(error: "Could not download the remote resource (\(urlString)): \($0.error.debugDescription).")
+ return log.error("Could not download the remote resource (\(urlString)): \($0.error.debugDescription).")
}
UNUserNotificationCenter.current().add(
diff --git a/Sources/ZamzamCore/Application/ApplicationPluggableDelegate.swift b/Sources/ZamzamCore/Application/ApplicationPluggableDelegate.swift
index 2adbf6ef..fd6dcba1 100644
--- a/Sources/ZamzamCore/Application/ApplicationPluggableDelegate.swift
+++ b/Sources/ZamzamCore/Application/ApplicationPluggableDelegate.swift
@@ -17,7 +17,7 @@ import UIKit
/// @UIApplicationMain
/// class AppDelegate: ApplicationPluggableDelegate {
///
-/// override func application() -> [ApplicationPlugin] {[
+/// override func plugins() -> [ApplicationPlugin] {[
/// LoggerPlugin(),
/// NotificationPlugin()
/// ]}
@@ -46,21 +46,21 @@ import UIKit
/// log.warn("App will terminate.")
/// }
/// }
-open class ApplicationPluggableDelegate: UIResponder, UIApplicationDelegate {
+open class ApplicationPluggableDelegate: UIResponder, UIApplicationDelegate, WindowDelegate {
public var window: UIWindow?
/// List of application plugins for binding to `AppDelegate` events
- public private(set) lazy var plugins: [ApplicationPlugin] = { application() }()
+ public private(set) lazy var pluginInstances: [ApplicationPlugin] = { plugins() }()
public override init() {
super.init()
// Load lazy property early
- _ = plugins
+ _ = pluginInstances
}
/// List of application plugins for binding to `AppDelegate` events
- open func application() -> [ApplicationPlugin] {[]} // Override
+ open func plugins() -> [ApplicationPlugin] {[]} // Override
}
extension ApplicationPluggableDelegate {
@@ -68,7 +68,7 @@ extension ApplicationPluggableDelegate {
open func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
// Ensure all delegates called even if condition fails early
//swiftlint:disable reduce_boolean
- plugins.reduce(true) {
+ pluginInstances.reduce(true) {
$0 && $1.application(application, willFinishLaunchingWithOptions: launchOptions)
}
}
@@ -76,7 +76,7 @@ extension ApplicationPluggableDelegate {
open func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Ensure all delegates called even if condition fails early
//swiftlint:disable reduce_boolean
- plugins.reduce(true) {
+ pluginInstances.reduce(true) {
$0 && $1.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
@@ -85,41 +85,49 @@ extension ApplicationPluggableDelegate {
extension ApplicationPluggableDelegate {
open func applicationWillEnterForeground(_ application: UIApplication) {
- plugins.forEach { $0.applicationWillEnterForeground(application) }
+ pluginInstances
+ .compactMap { $0 as? ScenePlugin }
+ .forEach { $0.sceneWillEnterForeground() }
}
open func applicationDidEnterBackground(_ application: UIApplication) {
- plugins.forEach { $0.applicationDidEnterBackground(application) }
+ pluginInstances
+ .compactMap { $0 as? ScenePlugin }
+ .forEach { $0.sceneDidEnterBackground() }
}
open func applicationDidBecomeActive(_ application: UIApplication) {
- plugins.forEach { $0.applicationDidBecomeActive(application) }
+ pluginInstances
+ .compactMap { $0 as? ScenePlugin }
+ .forEach { $0.sceneDidBecomeActive() }
}
open func applicationWillResignActive(_ application: UIApplication) {
- plugins.forEach { $0.applicationWillResignActive(application) }
+ pluginInstances
+ .compactMap { $0 as? ScenePlugin }
+ .forEach { $0.sceneWillResignActive() }
}
}
extension ApplicationPluggableDelegate {
open func applicationProtectedDataWillBecomeUnavailable(_ application: UIApplication) {
- plugins.forEach { $0.applicationProtectedDataWillBecomeUnavailable(application) }
+ pluginInstances.forEach { $0.applicationProtectedDataWillBecomeUnavailable(application) }
}
open func applicationProtectedDataDidBecomeAvailable(_ application: UIApplication) {
- plugins.forEach { $0.applicationProtectedDataDidBecomeAvailable(application) }
+ pluginInstances.forEach { $0.applicationProtectedDataDidBecomeAvailable(application) }
}
}
extension ApplicationPluggableDelegate {
open func applicationWillTerminate(_ application: UIApplication) {
- plugins.forEach { $0.applicationWillTerminate(application) }
+ pluginInstances.forEach { $0.applicationWillTerminate(application) }
}
open func applicationDidReceiveMemoryWarning(_ application: UIApplication) {
- plugins.forEach { $0.applicationDidReceiveMemoryWarning(application) }
+ pluginInstances.forEach { $0.applicationDidReceiveMemoryWarning(application) }
}
}
@@ -128,11 +136,6 @@ public protocol ApplicationPlugin {
func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
- func applicationWillEnterForeground(_ application: UIApplication)
- func applicationDidEnterBackground(_ application: UIApplication)
- func applicationDidBecomeActive(_ application: UIApplication)
- func applicationWillResignActive(_ application: UIApplication)
-
func applicationProtectedDataWillBecomeUnavailable(_ application: UIApplication)
func applicationProtectedDataDidBecomeAvailable(_ application: UIApplication)
@@ -146,11 +149,6 @@ public extension ApplicationPlugin {
func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { return true }
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { return true }
- func applicationWillEnterForeground(_ application: UIApplication) {}
- func applicationDidEnterBackground(_ application: UIApplication) {}
- func applicationDidBecomeActive(_ application: UIApplication) {}
- func applicationWillResignActive(_ application: UIApplication) {}
-
func applicationProtectedDataWillBecomeUnavailable(_ application: UIApplication) {}
func applicationProtectedDataDidBecomeAvailable(_ application: UIApplication) {}
diff --git a/Sources/ZamzamCore/Application/ExtensionPluggableDelegate.swift b/Sources/ZamzamCore/Application/ExtensionPluggableDelegate.swift
index 506efd95..d5cecaf1 100644
--- a/Sources/ZamzamCore/Application/ExtensionPluggableDelegate.swift
+++ b/Sources/ZamzamCore/Application/ExtensionPluggableDelegate.swift
@@ -15,7 +15,7 @@ import WatchKit
///
/// class ExtensionDelegate: ExtensionPluggableDelegate {
///
-/// override func application() -> [ExtensionPlugin] {[
+/// override func plugins() -> [ExtensionPlugin] {[
/// LoggerPlugin(),
/// LocationPlugin()
/// ]}
@@ -49,42 +49,42 @@ import WatchKit
open class ExtensionPluggableDelegate: NSObject, WKExtensionDelegate {
/// List of application plugins for binding to `ExtensionDelegate` events
- public private(set) lazy var plugins: [ExtensionPlugin] = { application() }()
+ public private(set) lazy var pluginInstances: [ExtensionPlugin] = { plugins() }()
public override init() {
super.init()
// Load lazy property early
- _ = plugins
+ _ = pluginInstances
}
/// List of application plugins for binding to `ExtensionDelegate` events
- open func application() -> [ExtensionPlugin] {[]} // Override
+ open func plugins() -> [ExtensionPlugin] {[]} // Override
}
public extension ExtensionPluggableDelegate {
func applicationDidFinishLaunching() {
- plugins.forEach { $0.applicationDidFinishLaunching(.shared()) }
+ pluginInstances.forEach { $0.applicationDidFinishLaunching(.shared()) }
}
}
public extension ExtensionPluggableDelegate {
func applicationDidBecomeActive() {
- plugins.forEach { $0.applicationDidBecomeActive(.shared()) }
+ pluginInstances.forEach { $0.applicationDidBecomeActive(.shared()) }
}
func applicationWillResignActive() {
- plugins.forEach { $0.applicationWillResignActive(.shared()) }
+ pluginInstances.forEach { $0.applicationWillResignActive(.shared()) }
}
func applicationWillEnterForeground() {
- plugins.forEach { $0.applicationWillEnterForeground(.shared()) }
+ pluginInstances.forEach { $0.applicationWillEnterForeground(.shared()) }
}
func applicationDidEnterBackground() {
- plugins.forEach { $0.applicationDidEnterBackground(.shared()) }
+ pluginInstances.forEach { $0.applicationDidEnterBackground(.shared()) }
}
}
diff --git a/Sources/ZamzamCore/Application/ScenePluggableDelegate.swift b/Sources/ZamzamCore/Application/ScenePluggableDelegate.swift
new file mode 100644
index 00000000..5e80b57c
--- /dev/null
+++ b/Sources/ZamzamCore/Application/ScenePluggableDelegate.swift
@@ -0,0 +1,121 @@
+//
+// File.swift
+//
+//
+// Created by Basem Emara on 2019-10-28.
+//
+
+#if os(iOS)
+import UIKit
+
+/// Subclassed by the `SceneDelegate` to pass lifecycle events to loaded plugins.
+///
+/// The scene plugins will be processed in sequence after calling `plugins() -> [ScenePlugin]`.
+///
+/// class SceneDelegate: ScenePluggableDelegate {
+///
+/// override func plugins() -> [ScenePlugin] {[
+/// LoggerPlugin(),
+/// NotificationPlugin()
+/// ]}
+/// }
+///
+/// Each scene plugin has access to the `SceneDelegate` lifecycle events:
+///
+/// final class LoggerPlugin: ScenePlugin {
+/// private let log = Logger()
+///
+/// func sceneWillEnterForeground() {
+/// log.info("Scene will enter foreground.")
+/// }
+///
+/// func sceneDidEnterBackground() {
+/// log.info("Scene did enter background.")
+/// }
+/// }
+@available(iOS 13.0, *)
+open class ScenePluggableDelegate: UIResponder, UIWindowSceneDelegate, WindowDelegate {
+ public var window: UIWindow?
+
+ /// List of scene plugins for binding to `SceneDelegate` events
+ public private(set) lazy var pluginInstances: [ScenePlugin] = { plugins() }()
+
+ public override init() {
+ super.init()
+
+ // Load lazy property early
+ _ = pluginInstances
+ }
+
+ /// List of scene plugins for binding to `SceneDelegate` events
+ open func plugins() -> [ScenePlugin] {[]} // Override
+}
+
+@available(iOS 13.0, *)
+extension ScenePluggableDelegate {
+
+ open func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
+ pluginInstances.forEach { $0.scene(scene, willConnectTo: session, options: connectionOptions) }
+ }
+
+ open func sceneWillEnterForeground(_ scene: UIScene) {
+ pluginInstances.forEach { $0.sceneWillEnterForeground() }
+ }
+
+ open func sceneDidEnterBackground(_ scene: UIScene) {
+ pluginInstances.forEach { $0.sceneDidEnterBackground() }
+ }
+
+ open func sceneDidBecomeActive(_ scene: UIScene) {
+ pluginInstances.forEach { $0.sceneDidBecomeActive() }
+ }
+
+ open func sceneWillResignActive(_ scene: UIScene) {
+ pluginInstances.forEach { $0.sceneWillResignActive() }
+ }
+
+ open func sceneDidDisconnect(_ scene: UIScene) {
+ pluginInstances.forEach { $0.sceneDidDisconnect() }
+ }
+}
+
+/// Conforming to an scene module and added to `SceneDelegate.plugins()` will trigger events.
+public protocol ScenePlugin {
+
+ /// Tells the delegate that the scene is about to begin running in the foreground and become visible to the user.
+ func sceneWillEnterForeground()
+
+ /// Tells the delegate that the scene is running in the background and is no longer onscreen.
+ func sceneDidEnterBackground()
+
+ /// Tells the delegate that the scene became active and is now responding to user events.
+ func sceneDidBecomeActive()
+
+ /// Tells the delegate that the scene is about to resign the active state and stop responding to user events.
+ func sceneWillResignActive()
+
+ /// Tells the delegate that UIKit removed a scene from your app.
+ func sceneDidDisconnect()
+
+ /// Tells the delegate about the addition of a scene to the app.
+ @available(iOS 13.0, *)
+ func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions)
+}
+
+// MARK: - Optionals
+
+public extension ScenePlugin {
+ func sceneWillEnterForeground() {}
+ func sceneDidEnterBackground() {}
+ func sceneDidBecomeActive() {}
+ func sceneWillResignActive() {}
+ func sceneDidDisconnect() {}
+
+ @available(iOS 13.0, *)
+ func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {}
+}
+
+public protocol WindowDelegate: class {
+ var window: UIWindow? { get set }
+}
+#endif
diff --git a/Sources/ZamzamCore/Logging/LogAPI.swift b/Sources/ZamzamCore/Logging/LogAPI.swift
new file mode 100644
index 00000000..3e9ccee9
--- /dev/null
+++ b/Sources/ZamzamCore/Logging/LogAPI.swift
@@ -0,0 +1,116 @@
+//
+// Loggable.swift
+// ZamzamCore
+//
+// Created by Basem Emara on 2019-06-11.
+// Copyright © 2019 Zamzam Inc. All rights reserved.
+//
+
+import Foundation
+
+// Namespace
+public enum LogAPI {}
+
+public protocol LogStore: AppInfo {
+
+ /**
+ Log something generally unimportant (lowest priority; not written to file)
+
+ - parameter message: Description of the log.
+ - parameter includeMeta: If true, will append the meta data to the log.
+ - parameter path: Path of the caller.
+ - parameter function: Function of the caller.
+ - parameter line: Line of the caller.
+ */
+ func verbose(_ message: String, path: String, function: String, line: Int, context: [String: Any]?)
+
+ /**
+ Log something which help during debugging (low priority; not written to file)
+
+ - parameter message: Description of the log.
+ - parameter includeMeta: If true, will append the meta data to the log.
+ - parameter path: Path of the caller.
+ - parameter function: Function of the caller.
+ - parameter line: Line of the caller.
+ */
+ func debug(_ message: String, path: String, function: String, line: Int, context: [String: Any]?)
+
+ /**
+ Log something which you are really interested but which is not an issue or error (normal priority)
+
+ - parameter message: Description of the log.
+ - parameter includeMeta: If true, will append the meta data to the log.
+ - parameter path: Path of the caller.
+ - parameter function: Function of the caller.
+ - parameter line: Line of the caller.
+ */
+ func info(_ message: String, path: String, function: String, line: Int, context: [String: Any]?)
+
+ /**
+ Log something which may cause big trouble soon (high priority)
+
+ - parameter message: Description of the log.
+ - parameter includeMeta: If true, will append the meta data to the log.
+ - parameter path: Path of the caller.
+ - parameter function: Function of the caller.
+ - parameter line: Line of the caller.
+ */
+ func warning(_ message: String, path: String, function: String, line: Int, context: [String: Any]?)
+
+ /**
+ Log something which will keep you awake at night (highest priority)
+
+ - parameter message: Description of the log.
+ - parameter includeMeta: If true, will append the meta data to the log.
+ - parameter path: Path of the caller.
+ - parameter function: Function of the caller.
+ - parameter line: Line of the caller.
+ */
+ func error(_ message: String, path: String, function: String, line: Int, context: [String: Any]?)
+}
+
+public protocol LogWorkerType: LogStore {}
+public extension LogWorkerType {
+
+ /// Log something generally unimportant (lowest priority; not written to file)
+ func verbose(_ message: String, path: String = #file, function: String = #function, line: Int = #line) {
+ verbose(message, path: path, function: function, line: line, context: nil)
+ }
+
+ /// Log something which help during debugging (low priority; not written to file)
+ func debug(_ message: String, path: String = #file, function: String = #function, line: Int = #line) {
+ debug(message, path: path, function: function, line: line, context: nil)
+ }
+
+ /// Log something which you are really interested but which is not an issue or error (normal priority)
+ func info(_ message: String, path: String = #file, function: String = #function, line: Int = #line) {
+ info(message, path: path, function: function, line: line, context: nil)
+ }
+
+ /// Log something which may cause big trouble soon (high priority)
+ func warn(_ message: String, path: String = #file, function: String = #function, line: Int = #line) {
+ warning(message, path: path, function: function, line: line, context: nil)
+ }
+
+ /// Log something which will keep you awake at night (highest priority)
+ func error(_ message: String, path: String = #file, function: String = #function, line: Int = #line) {
+ error(message, path: path, function: function, line: line, context: nil)
+ }
+}
+
+// MARK: - Types
+
+public extension LogAPI {
+
+ enum Level: Int, Comparable {
+ case verbose
+ case debug
+ case info
+ case warning
+ case error
+
+ public static func < (lhs: Level, rhs: Level) -> Bool {
+ lhs.rawValue < rhs.rawValue
+ }
+ }
+}
diff --git a/Sources/ZamzamCore/Logging/LogWorker.swift b/Sources/ZamzamCore/Logging/LogWorker.swift
new file mode 100644
index 00000000..db61034c
--- /dev/null
+++ b/Sources/ZamzamCore/Logging/LogWorker.swift
@@ -0,0 +1,40 @@
+//
+// Logger.swift
+// ZamzamCore
+//
+// Created by Basem Emara on 2019-06-11.
+// Copyright © 2019 Zamzam Inc. All rights reserved.
+//
+
+import Foundation
+
+public struct LogWorker: LogWorkerType {
+ private let stores: [LogStore]
+
+ public init(stores: [LogStore]) {
+ self.stores = stores
+ }
+}
+
+public extension LogWorker {
+
+ func verbose(_ message: String, path: String, function: String, line: Int, context: [String: Any]?) {
+ stores.forEach { $0.verbose(message, path: path, function: function, line: line, context: context) }
+ }
+
+ func debug(_ message: String, path: String, function: String, line: Int, context: [String: Any]?) {
+ stores.forEach { $0.debug(message, path: path, function: function, line: line, context: context) }
+ }
+
+ func info(_ message: String, path: String, function: String, line: Int, context: [String: Any]?) {
+ stores.forEach { $0.info(message, path: path, function: function, line: line, context: context) }
+ }
+
+ func warning(_ message: String, path: String, function: String, line: Int, context: [String: Any]?) {
+ stores.forEach { $0.warning(message, path: path, function: function, line: line, context: context) }
+ }
+
+ func error(_ message: String, path: String, function: String, line: Int, context: [String: Any]?) {
+ stores.forEach { $0.error(message, path: path, function: function, line: line, context: context) }
+ }
+}
diff --git a/Sources/ZamzamCore/Logging/Stores/LogConsoleStore.swift b/Sources/ZamzamCore/Logging/Stores/LogConsoleStore.swift
new file mode 100644
index 00000000..96ea1a41
--- /dev/null
+++ b/Sources/ZamzamCore/Logging/Stores/LogConsoleStore.swift
@@ -0,0 +1,53 @@
+//
+// File.swift
+//
+//
+// Created by Basem Emara on 2019-10-28.
+//
+
+import Foundation
+
+/// Sends a message to the IDE console.
+public struct LogConsoleStore: LogStore {
+ private let minLevel: LogAPI.Level
+ private let queue = DispatchQueue(label: "io.zamzam.LogConsoleStore", qos: .utility)
+
+ public init(minLevel: LogAPI.Level) {
+ self.minLevel = minLevel
+ }
+}
+
+public extension LogConsoleStore {
+
+ func verbose(_ message: String, path: String = #file, function: String = #function, line: Int = #line, context: [String: Any]? = nil) {
+ guard minLevel <= .verbose else { return }
+ queue.async { print("💜 VERBOSE \(self.output(message, path, function, line, context))") }
+ }
+
+ func debug(_ message: String, path: String = #file, function: String = #function, line: Int = #line, context: [String: Any]? = nil) {
+ guard minLevel <= .debug else { return }
+ queue.async { print("💚 DEBUG \(self.output(message, path, function, line, context))") }
+ }
+
+ func info(_ message: String, path: String = #file, function: String = #function, line: Int = #line, context: [String: Any]? = nil) {
+ guard minLevel <= .info else { return }
+ queue.async { print("💙 INFO \(self.output(message, path, function, line, context))") }
+ }
+
+ func warning(_ message: String, path: String = #file, function: String = #function, line: Int = #line, context: [String: Any]? = nil) {
+ guard minLevel <= .warning else { return }
+ queue.async { print("💛 WARNING \(self.output(message, path, function, line, context))") }
+ }
+
+ func error(_ message: String, path: String = #file, function: String = #function, line: Int = #line, context: [String: Any]? = nil) {
+ guard minLevel <= .error else { return }
+ queue.async { print("❤️ ERROR \(self.output(message, path, function, line, context))") }
+ }
+}
+
+private extension LogConsoleStore {
+
+ func output(_ message: String, _ path: String, _ function: String, _ line: Int, _ context: [String: Any]?) -> String {
+ "\(URL(fileURLWithPath: path).deletingPathExtension().lastPathComponent).\(function):\(line) - \(message)"
+ }
+}
diff --git a/Sources/ZamzamCore/Logging/Stores/LogOSStore.swift b/Sources/ZamzamCore/Logging/Stores/LogOSStore.swift
new file mode 100644
index 00000000..c59bf7c8
--- /dev/null
+++ b/Sources/ZamzamCore/Logging/Stores/LogOSStore.swift
@@ -0,0 +1,54 @@
+//
+// File.swift
+//
+//
+// Created by Basem Emara on 2019-11-01.
+//
+
+import Foundation
+import os
+
+/// Sends a message to the logging system, optionally specifying a custom log object, log level, and any message format arguments.
+public struct LogOSStore: LogStore {
+ private let minLevel: LogAPI.Level
+ private let subsystem: String
+ private let category: String
+ private let log: OSLog
+
+ private let queue = DispatchQueue(label: "io.zamzam.LogOSStore", qos: .utility)
+
+ public init(minLevel: LogAPI.Level, subsystem: String, category: String) {
+ self.minLevel = minLevel
+ self.subsystem = subsystem
+ self.category = category
+ self.log = OSLog(subsystem: subsystem, category: category)
+ }
+}
+
+public extension LogOSStore {
+
+ func verbose(_ message: String, path: String = #file, function: String = #function, line: Int = #line, context: [String: Any]? = nil) {
+ guard minLevel <= .verbose else { return }
+ queue.async { os_log("%@", log: self.log, type: .debug, message) }
+ }
+
+ func debug(_ message: String, path: String = #file, function: String = #function, line: Int = #line, context: [String: Any]? = nil) {
+ guard minLevel <= .debug else { return }
+ queue.async { os_log("%@", log: self.log, type: .debug, message) }
+ }
+
+ func info(_ message: String, path: String = #file, function: String = #function, line: Int = #line, context: [String: Any]? = nil) {
+ guard minLevel <= .info else { return }
+ queue.async { os_log("%@", log: self.log, type: .info, message) }
+ }
+
+ func warning(_ message: String, path: String = #file, function: String = #function, line: Int = #line, context: [String: Any]? = nil) {
+ guard minLevel <= .warning else { return }
+ queue.async { os_log("%@", log: self.log, type: .default, message) }
+ }
+
+ func error(_ message: String, path: String = #file, function: String = #function, line: Int = #line, context: [String: Any]? = nil) {
+ guard minLevel <= .error else { return }
+ queue.async { os_log("%@", log: self.log, type: .error, message) }
+ }
+}
diff --git a/Sources/ZamzamNotification/UNNotificationAttachment.swift b/Sources/ZamzamNotification/UNNotificationAttachment.swift
index df94af3d..0f58f497 100644
--- a/Sources/ZamzamNotification/UNNotificationAttachment.swift
+++ b/Sources/ZamzamNotification/UNNotificationAttachment.swift
@@ -16,7 +16,7 @@ public extension UNNotificationAttachment {
///
/// UNNotificationAttachment.download(from: urlString) {
/// guard $0.isSuccess, let attachment = $0.value else {
- /// return log(error: "Could not download the remote resource (\(urlString)): \($0.error.debugDescription).")
+ /// return log.error("Could not download the remote resource (\(urlString)): \($0.error.debugDescription).")
/// }
///
/// UNUserNotificationCenter.current().add(
diff --git a/Sources/ZamzamNotification/UNUserNotificationCenter.swift b/Sources/ZamzamNotification/UNUserNotificationCenter.swift
index c0b15a2e..dd8a490c 100644
--- a/Sources/ZamzamNotification/UNUserNotificationCenter.swift
+++ b/Sources/ZamzamNotification/UNUserNotificationCenter.swift
@@ -45,8 +45,8 @@ public extension UNUserNotificationCenter {
/// authorizations: [.alert, .badge, .sound],
/// completion: { granted in
/// granted
- /// ? log(debug: "Authorization for notification succeeded.")
- /// : log(warn: "Authorization for notification not given.")
+ /// ? log.debug("Authorization for notification succeeded.")
+ /// : log.warn("Authorization for notification not given.")
/// }
/// )
///
@@ -92,8 +92,8 @@ public extension UNUserNotificationCenter {
/// authorizations: [.alert, .badge, .sound],
/// completion: { granted in
/// granted
- /// ? log(debug: "Authorization for notification succeeded.")
- /// : log(warn: "Authorization for notification not given.")
+ /// ? log.debug("Authorization for notification succeeded.")
+ /// : log.warn("Authorization for notification not given.")
/// }
/// )
///