From c10ec2936e77959f828a041b71ea56e454e39ff2 Mon Sep 17 00:00:00 2001 From: Todd Anderson Date: Thu, 30 May 2024 15:11:00 -0500 Subject: [PATCH] feat: adds ability to provide a OSLog instance via the Config.logger property --- Source/LDSwiftEventSource.swift | 29 ++++++++++++++--- Source/Logs.swift | 58 ++++++++++++++++++++------------- 2 files changed, 61 insertions(+), 26 deletions(-) diff --git a/Source/LDSwiftEventSource.swift b/Source/LDSwiftEventSource.swift index 86952d2..1225e5b 100644 --- a/Source/LDSwiftEventSource.swift +++ b/Source/LDSwiftEventSource.swift @@ -4,6 +4,12 @@ import Foundation import FoundationNetworking #endif +#if canImport(os) +// os_log is not supported on some platforms, but we want to use it for most of our customer's +// use cases that use Apple OSs +import os.log +#endif + /** Provides an EventSource client for consuming Server-Sent Events. @@ -51,12 +57,18 @@ public class EventSource { public var method: String = "GET" /// Optional HTTP body to be included in the API request. public var body: Data? - /// An initial value for the last-event-id header to be sent on the initial request - public var lastEventId: String = "" /// Additional HTTP headers to be set on the request public var headers: [String: String] = [:] /// Transform function to allow dynamically configuring the headers on each API request. public var headerTransform: HeaderTransform = { $0 } + /// An initial value for the last-event-id header to be sent on the initial request + public var lastEventId: String = "" + +#if canImport(os) + /// Configure the logger that will be used. + public var logger: OSLog = OSLog(subsystem: "com.launchdarkly.swift-eventsource", category: "LDEventSource") +#endif + /// The minimum amount of time to wait before reconnecting after a failure public var reconnectTime: TimeInterval = 1.0 /// The maximum amount of time to wait before reconnecting after a failure @@ -152,8 +164,9 @@ class ReconnectionTimer { // MARK: EventSourceDelegate class EventSourceDelegate: NSObject, URLSessionDataDelegate { private let delegateQueue: DispatchQueue = DispatchQueue(label: "ESDelegateQueue") - private let logger = Logs() - + + public var logger: InternalLogging + private let config: EventSource.Config private var readyState: ReadyState = .raw { @@ -170,6 +183,14 @@ class EventSourceDelegate: NSObject, URLSessionDataDelegate { init(config: EventSource.Config) { self.config = config + +#if canImport(os) + self.logger = OSLogAdapter(osLog: config.logger) +#else + self.logger = NoOpLogging() +#endif + + self.eventParser = EventParser(handler: config.handler, initialEventId: config.lastEventId, initialRetry: config.reconnectTime) diff --git a/Source/Logs.swift b/Source/Logs.swift index ec0abd8..46d62bd 100644 --- a/Source/Logs.swift +++ b/Source/Logs.swift @@ -1,38 +1,52 @@ import Foundation -#if !os(Linux) && !os(Windows) +#if canImport(os) import os.log #endif -class Logs { - enum Level { - case debug, info, warn, error +protocol InternalLogging { + func log(_ level: Level, _ staticMsg: StaticString) + func log(_ level: Level, _ staticMsg: StaticString, _ arg: CVarArg) + func log(_ level: Level, _ staticMsg: StaticString, _ arg1: CVarArg, _ arg2: CVarArg) +} -#if !os(Linux) && !os(Windows) - private static let osLogTypes = [ Level.debug: OSLogType.debug, - Level.info: OSLogType.info, - Level.warn: OSLogType.default, - Level.error: OSLogType.error] - var osLogType: OSLogType { Level.osLogTypes[self]! } -#endif - } +enum Level { + case debug, info, warn, error -#if !os(Linux) && !os(Windows) - private let logger: OSLog = OSLog(subsystem: "com.launchdarkly.swift-eventsource", category: "LDEventSource") +#if canImport(os) + private static let osLogTypes = [ Level.debug: OSLogType.debug, + Level.info: OSLogType.info, + Level.warn: OSLogType.default, + Level.error: OSLogType.error] + var osLogType: OSLogType { Level.osLogTypes[self]! } +#endif +} +#if canImport(os) +class OSLogAdapter: InternalLogging { + + private let osLog: OSLog + + init(osLog: OSLog) { + self.osLog = osLog + } + func log(_ level: Level, _ staticMsg: StaticString) { - os_log(staticMsg, log: logger, type: level.osLogType) + os_log(staticMsg, log: self.osLog, type: level.osLogType) } - + func log(_ level: Level, _ staticMsg: StaticString, _ arg: CVarArg) { - os_log(staticMsg, log: logger, type: level.osLogType, arg) + os_log(staticMsg, log: self.osLog, type: level.osLogType, arg) } - + func log(_ level: Level, _ staticMsg: StaticString, _ arg1: CVarArg, _ arg2: CVarArg) { - os_log(staticMsg, log: logger, type: level.osLogType, arg1, arg2) + os_log(staticMsg, log: self.osLog, type: level.osLogType, arg1, arg2) } -#else - // We use Any over CVarArg here, because on Linux prior to Swift 5.4 String does not conform to CVarArg - func log(_ level: Level, _ staticMsg: StaticString, _ args: Any...) { } +} #endif + +class NoOpLogging: InternalLogging { + func log(_ level: Level, _ staticMsg: StaticString) {} + func log(_ level: Level, _ staticMsg: StaticString, _ arg: CVarArg) {} + func log(_ level: Level, _ staticMsg: StaticString, _ arg1: CVarArg, _ arg2: CVarArg) {} }