11/**
2- * Copyright IBM Corporation 2016, 2017
2+ * Copyright IBM Corporation 2016 - 2019
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
1414 * limitations under the License.
1515 **/
1616
17+ import Logging
18+ import Foundation
19+
1720/// Implement the `CustomStringConvertible` protocol for the `LoggerMessageType` enum
1821extension LoggerMessageType : CustomStringConvertible {
1922 /// Convert a `LoggerMessageType` into a printable format.
@@ -64,12 +67,49 @@ public protocol Logger {
6467
6568}
6669
70+ extension NSLock {
71+ func withLock< T> ( _ body: ( ) throws -> T ) rethrows -> T {
72+ self . lock ( )
73+ defer {
74+ self . unlock ( )
75+ }
76+ return try body ( )
77+ }
78+ }
79+
6780/// A class of static members used by anyone who wants to log messages.
6881public class Log {
6982
83+ private static var _logger : Logger ?
84+ private static var _loggerLock : NSLock = NSLock ( )
85+
7086 /// An instance of the logger. It should usually be the one and only reference
7187 /// of the `Logger` protocol implementation in the system.
72- public static var logger : Logger ?
88+ /// This can be used in addition to `swiftLogger`, in which case log messages
89+ /// will be sent to both loggers.
90+ public static var logger : Logger ? {
91+ get {
92+ return self . _loggerLock. withLock { self . _logger }
93+ }
94+ set {
95+ self . _loggerLock. withLock { self . _logger = newValue }
96+ }
97+ }
98+
99+ private static var _swiftLogger : Logging . Logger ?
100+ private static var _swiftLoggerLock : NSLock = NSLock ( )
101+
102+ /// An instance of a swift-log Logger. If set, LoggerAPI will direct log messages
103+ /// to swift-log. This can be used in addition to `logger`, in which case log
104+ /// messages will be sent to both loggers.
105+ public static var swiftLogger : Logging . Logger ? {
106+ get {
107+ return self . _swiftLoggerLock. withLock { self . _swiftLogger }
108+ }
109+ set {
110+ self . _swiftLoggerLock. withLock { self . _swiftLogger = newValue }
111+ }
112+ }
73113
74114 /// Log a message for use when in verbose logging mode.
75115 ///
@@ -89,6 +129,7 @@ public class Log {
89129 logger. log ( . verbose, msg: msg ( ) ,
90130 functionName: functionName, lineNum: lineNum, fileName: fileName)
91131 }
132+ swiftLogger? . info ( " \( msg ( ) ) " )
92133 }
93134
94135 /// Log an informational message.
@@ -109,6 +150,7 @@ public class Log {
109150 logger. log ( . info, msg: msg ( ) ,
110151 functionName: functionName, lineNum: lineNum, fileName: fileName)
111152 }
153+ swiftLogger? . notice ( " \( msg ( ) ) " )
112154 }
113155
114156 /// Log a warning message.
@@ -127,8 +169,9 @@ public class Log {
127169 lineNum: Int = #line, fileName: String = #file) {
128170 if let logger = logger, logger. isLogging ( . warning) {
129171 logger. log ( . warning, msg: msg ( ) ,
130- functionName: functionName, lineNum: lineNum, fileName: fileName)
172+ functionName: functionName, lineNum: lineNum, fileName: fileName)
131173 }
174+ swiftLogger? . warning ( " \( msg ( ) ) " )
132175 }
133176
134177 /// Log an error message.
@@ -147,8 +190,9 @@ public class Log {
147190 lineNum: Int = #line, fileName: String = #file) {
148191 if let logger = logger, logger. isLogging ( . error) {
149192 logger. log ( . error, msg: msg ( ) ,
150- functionName: functionName, lineNum: lineNum, fileName: fileName)
193+ functionName: functionName, lineNum: lineNum, fileName: fileName)
151194 }
195+ swiftLogger? . error ( " \( msg ( ) ) " )
152196 }
153197
154198 /// Log a debugging message.
@@ -167,8 +211,9 @@ public class Log {
167211 lineNum: Int = #line, fileName: String = #file) {
168212 if let logger = logger, logger. isLogging ( . debug) {
169213 logger. log ( . debug, msg: msg ( ) ,
170- functionName: functionName, lineNum: lineNum, fileName: fileName)
214+ functionName: functionName, lineNum: lineNum, fileName: fileName)
171215 }
216+ swiftLogger? . debug ( " \( msg ( ) ) " )
172217 }
173218
174219 /// Log a message when entering a function.
@@ -187,8 +232,9 @@ public class Log {
187232 lineNum: Int = #line, fileName: String = #file) {
188233 if let logger = logger, logger. isLogging ( . entry) {
189234 logger. log ( . entry, msg: msg ( ) ,
190- functionName: functionName, lineNum: lineNum, fileName: fileName)
235+ functionName: functionName, lineNum: lineNum, fileName: fileName)
191236 }
237+ swiftLogger? . trace ( " \( msg ( ) ) " )
192238 }
193239
194240 /// Log a message when exiting a function.
@@ -207,23 +253,77 @@ public class Log {
207253 lineNum: Int = #line, fileName: String = #file) {
208254 if let logger = logger, logger. isLogging ( . exit) {
209255 logger. log ( . exit, msg: msg ( ) ,
210- functionName: functionName, lineNum: lineNum, fileName: fileName)
256+ functionName: functionName, lineNum: lineNum, fileName: fileName)
211257 }
258+ swiftLogger? . trace ( " \( msg ( ) ) " )
212259 }
213260
214- /// Indicates if a message with a specified type (`LoggerMessageType`) will be in the logger
215- /// output (i.e. will not be filtered out).
261+ /// Indicates if a message with a specified type (`LoggerMessageType`) will be logged
262+ /// by some configured logger (i.e. will not be filtered out). This could be a Logger
263+ /// conforming to LoggerAPI, swift-log or both.
216264 ///
217- /// - Parameter type: The type of message (`LoggerMessageType`).
265+ /// Note that due to differences in the log levels defined by LoggerAPI and swift-log,
266+ /// their equivalence is mapped as follows:
267+ /// ```
268+ /// LoggerAPI: swift-log:
269+ /// .error -> .error
270+ /// .warning -> .warning
271+ /// .info -> .notice
272+ /// .verbose -> .info
273+ /// .debug -> .debug
274+ /// .entry -> .trace
275+ /// .exit -> .trace
276+ /// ```
277+ ///
278+ /// For example, a swift-log Logger configured to log at the `.notice` level will log
279+ /// messages from LoggerAPI at a level of `.info` or higher.
280+ ///
281+ /// - Parameter level: The type of message (`LoggerMessageType`).
218282 ///
219283 /// - Returns: A Boolean indicating whether a message of the specified type
220- /// (`LoggerMessageType`) will be in the logger output .
284+ /// (`LoggerMessageType`) will be logged .
221285 public class func isLogging( _ level: LoggerMessageType ) -> Bool {
286+ return isLoggingToLoggerAPI ( level) || isLoggingToSwiftLog ( level)
287+ }
288+
289+ /// Indicates whether a LoggerAPI Logger is configured to log at the specified level.
290+ ///
291+ /// - Parameter level: The type of message (`LoggerMessageType`).
292+ ///
293+ /// - Returns: A Boolean indicating whether a message of the specified type
294+ /// will be logged via the registered `LoggerAPI.Logger`.
295+ private class func isLoggingToLoggerAPI( _ level: LoggerMessageType ) -> Bool {
222296 guard let logger = logger else {
223297 return false
224298 }
225299 return logger. isLogging ( level)
226300 }
301+
302+ /// Indicates whether a swift-log Logger is configured to log at the specified level.
303+ ///
304+ /// - Parameter level: The type of message (`LoggerMessageType`).
305+ ///
306+ /// - Returns: A Boolean indicating whether a message of the specified type
307+ /// will be logged via the registered `Logging.Logger`.
308+ private class func isLoggingToSwiftLog( _ level: LoggerMessageType ) -> Bool {
309+ guard let logger = swiftLogger else {
310+ return false
311+ }
312+ switch level {
313+ case . error:
314+ return logger. logLevel <= . error
315+ case . warning:
316+ return logger. logLevel <= . warning
317+ case . info:
318+ return logger. logLevel <= . notice
319+ case . verbose:
320+ return logger. logLevel <= . info
321+ case . debug:
322+ return logger. logLevel <= . debug
323+ case . entry, . exit:
324+ return logger. logLevel <= . trace
325+ }
326+ }
227327}
228328
229329/// The type of a particular log message. It is passed with the message to be logged to the
0 commit comments