1616
1717import OSLog
1818internal import LiveKitWebRTC
19+ internal import LiveKitFFI
1920
2021// MARK: - Logger
2122
@@ -69,30 +70,36 @@ public struct DisabledLogger: Logger {
6970/// A logger that logs to OSLog
7071/// - Parameter minLevel: The minimum level to log
7172/// - Parameter rtc: Whether to log WebRTC output
73+ /// - Parameter ffi: Whether to log Rust FFI output
7274open class OSLogger : Logger , @unchecked Sendable {
7375 private static let subsystem = " io.livekit.sdk "
7476
75- private let queue = DispatchQueue ( label: " io.livekit.oslogger " , qos: . utility)
77+ private static let queue = DispatchQueue ( label: " io.livekit.oslogger " , qos: . utility)
78+
79+ private nonisolated ( unsafe) static var ffiBootstrapped = false
80+
7681 private var logs : [ String : OSLog ] = [ : ]
7782
7883 private lazy var rtcLogger = LKRTCCallbackLogger ( )
84+ private var ffiLogForwardTask : Task < Void , Never > ?
7985
8086 private let minLevel : LogLevel
8187
82- public init ( minLevel: LogLevel = . info, rtc: Bool = false ) {
88+ public init ( minLevel: LogLevel = . info, rtc: Bool = false , ffi : Bool = true ) {
8389 self . minLevel = minLevel
8490
85- guard rtc else { return }
91+ if rtc {
92+ startRTCLogForwarding ( minLevel: minLevel)
93+ }
8694
87- let rtcLog = OSLog ( subsystem: Self . subsystem, category: " WebRTC " )
88- rtcLogger. severity = minLevel. rtcSeverity
89- rtcLogger. start { message, severity in
90- os_log ( " %{public}@ " , log: rtcLog, type: severity. osLogType, message)
95+ if ffi {
96+ startFFILogForwarding ( minLevel: minLevel)
9197 }
9298 }
9399
94100 deinit {
95101 rtcLogger. stop ( )
102+ ffiLogForwardTask? . cancel ( )
96103 }
97104
98105 public func log(
@@ -116,7 +123,7 @@ open class OSLogger: Logger, @unchecked Sendable {
116123
117124 let metadata = buildScopedMetadataString ( )
118125
119- queue. async {
126+ Self . queue. async {
120127 func getOSLog( for type: Any . Type ) -> OSLog {
121128 let typeName = String ( describing: type)
122129
@@ -132,6 +139,36 @@ open class OSLogger: Logger, @unchecked Sendable {
132139 os_log ( " %{public}@ " , log: getOSLog ( for: type) , type: level. osLogType, " \( type) . \( function) \( message) \( metadata) " )
133140 }
134141 }
142+
143+ private func startRTCLogForwarding( minLevel: LogLevel ) {
144+ let rtcLog = OSLog ( subsystem: Self . subsystem, category: " WebRTC " )
145+
146+ rtcLogger. severity = minLevel. rtcSeverity
147+ rtcLogger. start { message, severity in
148+ os_log ( " %{public}@ " , log: rtcLog, type: severity. osLogType, message)
149+ }
150+ }
151+
152+ private func startFFILogForwarding( minLevel: LogLevel ) {
153+ Self . queue. sync {
154+ if !Self. ffiBootstrapped {
155+ logForwardBootstrap ( level: minLevel. logForwardFilter)
156+ Self . ffiBootstrapped = true
157+ }
158+ }
159+
160+ let ffiLog = OSLog ( subsystem: Self . subsystem, category: " FFI " )
161+
162+ ffiLogForwardTask = Task ( priority: . utility) {
163+ for await entry in AsyncStream ( unfolding: logForwardReceive) {
164+ guard !Task. isCancelled else { break }
165+
166+ let message = " \( entry. target) \( entry. message) "
167+
168+ os_log ( " %{public}@ " , log: ffiLog, type: entry. level. osLogType, message)
169+ }
170+ }
171+ }
135172}
136173
137174// MARK: - Loggable
@@ -196,6 +233,15 @@ public enum LogLevel: Int, Sendable, Comparable {
196233 }
197234 }
198235
236+ var logForwardFilter : LogForwardFilter {
237+ switch self {
238+ case . debug: . debug
239+ case . info: . info
240+ case . warning: . warn
241+ case . error: . error
242+ }
243+ }
244+
199245 @inlinable
200246 public static func < ( lhs: LogLevel , rhs: LogLevel ) -> Bool {
201247 lhs. rawValue < rhs. rawValue
@@ -214,3 +260,14 @@ extension LKRTCLoggingSeverity {
214260 }
215261 }
216262}
263+
264+ extension LogForwardLevel {
265+ var osLogType : OSLogType {
266+ switch self {
267+ case . error: . error
268+ case . warn: . default
269+ case . info: . info
270+ case . debug, . trace: . debug
271+ }
272+ }
273+ }
0 commit comments