diff --git a/BlackBox-Carthage/BlackBox-Carthage.xcodeproj/project.pbxproj b/BlackBox-Carthage/BlackBox-Carthage.xcodeproj/project.pbxproj index 6283a04..c801a37 100644 --- a/BlackBox-Carthage/BlackBox-Carthage.xcodeproj/project.pbxproj +++ b/BlackBox-Carthage/BlackBox-Carthage.xcodeproj/project.pbxproj @@ -7,6 +7,10 @@ objects = { /* Begin PBXBuildFile section */ + 15C3EC6F2B3028A200A79B8B /* BBLogFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15C3EC6E2B3028A200A79B8B /* BBLogFormat.swift */; }; + 15C3EC702B3028A200A79B8B /* BBLogFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15C3EC6E2B3028A200A79B8B /* BBLogFormat.swift */; }; + 15C3EC712B3028A200A79B8B /* BBLogFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15C3EC6E2B3028A200A79B8B /* BBLogFormat.swift */; }; + 15C3EC722B3028A200A79B8B /* BBLogFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15C3EC6E2B3028A200A79B8B /* BBLogFormat.swift */; }; 1E4AC26B27A7F221009F0981 /* BBLogLevel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E4AC25D27A7F221009F0981 /* BBLogLevel.swift */; }; 1E4AC26C27A7F221009F0981 /* FSLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E4AC25F27A7F221009F0981 /* FSLogger.swift */; }; 1E4AC26D27A7F221009F0981 /* BBLoggerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E4AC26027A7F221009F0981 /* BBLoggerProtocol.swift */; }; @@ -46,6 +50,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 15C3EC6E2B3028A200A79B8B /* BBLogFormat.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BBLogFormat.swift; sourceTree = ""; }; 1E4AC25D27A7F221009F0981 /* BBLogLevel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BBLogLevel.swift; sourceTree = ""; }; 1E4AC25F27A7F221009F0981 /* FSLogger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FSLogger.swift; sourceTree = ""; }; 1E4AC26027A7F221009F0981 /* BBLoggerProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BBLoggerProtocol.swift; sourceTree = ""; }; @@ -105,6 +110,7 @@ 1E4AC25C27A7F221009F0981 /* BlackBox */ = { isa = PBXGroup; children = ( + 15C3EC6E2B3028A200A79B8B /* BBLogFormat.swift */, 1E4AC25D27A7F221009F0981 /* BBLogLevel.swift */, 1E4AC28F27A7FE52009F0981 /* BlackBox.h */, 1E4AC26027A7F221009F0981 /* BBLoggerProtocol.swift */, @@ -338,6 +344,7 @@ 1E4AC27327A7F221009F0981 /* BBHelpers.swift in Sources */, 1E4AC26D27A7F221009F0981 /* BBLoggerProtocol.swift in Sources */, 1E4AC27127A7F221009F0981 /* BlackBoxEvents.swift in Sources */, + 15C3EC6F2B3028A200A79B8B /* BBLogFormat.swift in Sources */, 1E4AC26F27A7F221009F0981 /* OSLogger.swift in Sources */, 1E4AC27427A7F221009F0981 /* BlackBox.swift in Sources */, 1E4AC26E27A7F221009F0981 /* OSSignpostLogger.swift in Sources */, @@ -353,6 +360,7 @@ 9C0C4DE528FDC6B40062AF73 /* BBHelpers.swift in Sources */, 9C0C4DE628FDC6B40062AF73 /* BBLoggerProtocol.swift in Sources */, 9C0C4DE728FDC6B40062AF73 /* BlackBoxEvents.swift in Sources */, + 15C3EC702B3028A200A79B8B /* BBLogFormat.swift in Sources */, 9C0C4DE828FDC6B40062AF73 /* OSLogger.swift in Sources */, 9C0C4DE928FDC6B40062AF73 /* BlackBox.swift in Sources */, 9C0C4DEA28FDC6B40062AF73 /* OSSignpostLogger.swift in Sources */, @@ -368,6 +376,7 @@ 9C0C4DF728FE43380062AF73 /* BBHelpers.swift in Sources */, 9C0C4DF828FE43380062AF73 /* BBLoggerProtocol.swift in Sources */, 9C0C4DF928FE43380062AF73 /* BlackBoxEvents.swift in Sources */, + 15C3EC712B3028A200A79B8B /* BBLogFormat.swift in Sources */, 9C0C4DFA28FE43380062AF73 /* OSLogger.swift in Sources */, 9C0C4DFB28FE43380062AF73 /* BlackBox.swift in Sources */, 9C0C4DFC28FE43380062AF73 /* OSSignpostLogger.swift in Sources */, @@ -383,6 +392,7 @@ 9C0C4E0928FE436E0062AF73 /* BBHelpers.swift in Sources */, 9C0C4E0A28FE436E0062AF73 /* BBLoggerProtocol.swift in Sources */, 9C0C4E0B28FE436E0062AF73 /* BlackBoxEvents.swift in Sources */, + 15C3EC722B3028A200A79B8B /* BBLogFormat.swift in Sources */, 9C0C4E0C28FE436E0062AF73 /* OSLogger.swift in Sources */, 9C0C4E0D28FE436E0062AF73 /* BlackBox.swift in Sources */, 9C0C4E0E28FE436E0062AF73 /* OSSignpostLogger.swift in Sources */, diff --git a/Sources/BlackBox/BBLogFormat.swift b/Sources/BlackBox/BBLogFormat.swift new file mode 100644 index 0000000..4ba43d3 --- /dev/null +++ b/Sources/BlackBox/BBLogFormat.swift @@ -0,0 +1,26 @@ +import Foundation + +public struct BBLogFormat { + let userInfoFormatOptions: JSONSerialization.WritingOptions + let sourceSectionInline: Bool + let showLevelIcon: Bool + + /// Creates `BBLogFormat` instance + /// - Parameters: + /// - userInfoFormatOptions:Options for output JSON data. + /// - sourceSectionInline: Print `Source` section in console inline + /// - showLevelIcon: Boolean value defines showing log level icon in console + public init( + userInfoFormatOptions: JSONSerialization.WritingOptions, + sourceSectionInline: Bool, + showLevelIcon: Bool + ) { + self.userInfoFormatOptions = userInfoFormatOptions + self.sourceSectionInline = sourceSectionInline + self.showLevelIcon = showLevelIcon + } + + public static let `default` = BBLogFormat(userInfoFormatOptions: .prettyPrinted, + sourceSectionInline: false, + showLevelIcon: false) +} diff --git a/Sources/BlackBox/BlackBox.swift b/Sources/BlackBox/BlackBox.swift index acf8df9..aad5122 100644 --- a/Sources/BlackBox/BlackBox.swift +++ b/Sources/BlackBox/BlackBox.swift @@ -322,7 +322,7 @@ extension BlackBox { public static var defaultLoggers: [BBLoggerProtocol] { [ - OSLogger(levels: .allCases), + OSLogger(levels: .allCases, logFormat: .default), OSSignpostLogger(levels: .allCases) ] } diff --git a/Sources/BlackBox/BlackBoxEvents.swift b/Sources/BlackBox/BlackBoxEvents.swift index 55f579b..62e0c9b 100644 --- a/Sources/BlackBox/BlackBoxEvents.swift +++ b/Sources/BlackBox/BlackBoxEvents.swift @@ -24,7 +24,7 @@ extension BlackBox { public let parentEvent: GenericEvent? /// From where log originated public let source: Source - + public init( id: UUID = .init(), timestamp: Date = .init(), diff --git a/Sources/BlackBox/Helpers/BBHelpers.swift b/Sources/BlackBox/Helpers/BBHelpers.swift index 86b61eb..b01dfc6 100644 --- a/Sources/BlackBox/Helpers/BBHelpers.swift +++ b/Sources/BlackBox/Helpers/BBHelpers.swift @@ -1,10 +1,10 @@ import Foundation extension Dictionary where Key == String, Value == Any { - var bbLogDescription: String { + func bbLogDescription(with options: JSONSerialization.WritingOptions?) -> String { guard JSONSerialization.isValidJSONObject(self), let jsonData = try? JSONSerialization.data(withJSONObject: self, - options: .prettyPrinted), + options: options ?? []), let jsonString = String(data: jsonData, encoding: .utf8) else { return String(describing: self) } diff --git a/Sources/BlackBox/Loggers/FSLogger.swift b/Sources/BlackBox/Loggers/FSLogger.swift index 994a19c..465b192 100644 --- a/Sources/BlackBox/Loggers/FSLogger.swift +++ b/Sources/BlackBox/Loggers/FSLogger.swift @@ -6,6 +6,7 @@ public class FSLogger: BBLoggerProtocol { private let fullpath: URL private let levels: [BBLogLevel] private let queue: DispatchQueue + private let logFormat: BBLogFormat /// Creates FS logger /// - Parameters: @@ -17,11 +18,13 @@ public class FSLogger: BBLoggerProtocol { path: URL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!, name: String = "BlackBox_FSLogger", levels: [BBLogLevel], - queue: DispatchQueue = DispatchQueue(label: String(describing: FSLogger.self)) + queue: DispatchQueue = DispatchQueue(label: String(describing: FSLogger.self)), + logFormat: BBLogFormat ) { self.fullpath = path.appendingPathComponent(name) self.levels = levels self.queue = queue + self.logFormat = logFormat } public func log(_ event: BlackBox.GenericEvent) { @@ -51,7 +54,7 @@ extension FSLogger { private func fsLog(_ event: BlackBox.GenericEvent) { guard levels.contains(event.level) else { return } - let userInfo = event.userInfo?.bbLogDescription ?? "nil" + let userInfo = event.userInfo?.bbLogDescription(with: logFormat.userInfoFormatOptions) ?? "nil" let title = event.level.icon + " " + String(describing: Date()) let subtitle = event.source.filename + ", " + event.source.function.description diff --git a/Sources/BlackBox/Loggers/OSLogger.swift b/Sources/BlackBox/Loggers/OSLogger.swift index 898b2c2..1392c44 100644 --- a/Sources/BlackBox/Loggers/OSLogger.swift +++ b/Sources/BlackBox/Loggers/OSLogger.swift @@ -4,11 +4,14 @@ import os /// Redirects logs to Console.app and to Xcode console public class OSLogger: BBLoggerProtocol { let levels: [BBLogLevel] + let logFormat: BBLogFormat public init( - levels: [BBLogLevel] + levels: [BBLogLevel], + logFormat: BBLogFormat ){ self.levels = levels + self.logFormat = logFormat } public func log(_ event: BlackBox.GenericEvent) { @@ -30,7 +33,7 @@ public class OSLogger: BBLoggerProtocol { private func osLog(event: BlackBox.GenericEvent) { guard levels.contains(event.level) else { return } - let data = LogData(from: event) + let data = LogData(from: event, logFormat: logFormat) osLog(data) } @@ -68,7 +71,7 @@ extension OSLogger { self.message = message } - init(from event: BlackBox.GenericEvent) { + init(from event: BlackBox.GenericEvent, logFormat: BBLogFormat) { let subsystem = event.source.module let category = event.category ?? "" @@ -76,11 +79,11 @@ extension OSLogger { logType: OSLogType(event.level), subsystem: subsystem, category: category, - message: Self.message(from: event) + message: Self.message(from: event, logFormat: logFormat) ) } - private static func message(from event: BlackBox.GenericEvent) -> String { + private static func message(from event: BlackBox.GenericEvent, logFormat: BBLogFormat) -> String { func source(from event: BlackBox.GenericEvent) -> String { let fileWithLine = [event.source.filename, String(event.source.line)].joined(separator: ":") @@ -88,7 +91,7 @@ extension OSLogger { "[Source]", fileWithLine, event.source.function.description - ].joined(separator: "\n") + ].joined(separator: logFormat.sourceSectionInline ? " " : "\n") } func userInfo(from event: BlackBox.GenericEvent) -> String? { @@ -96,12 +99,13 @@ extension OSLogger { return [ "[User Info]", - userInfo.bbLogDescription + userInfo.bbLogDescription(with: logFormat.userInfoFormatOptions) ].joined(separator: "\n") } // newline at the beginning increments readability in Xcode's console while not decrementing reading in Console.app - let message = "\n" + event.formattedMessage + let prefixString = logFormat.showLevelIcon ? "\n\(event.level.icon) " : "\n" + let message = prefixString + event.formattedMessage return [ message, diff --git a/Tests/BlackBoxTests/OSLoggerTests.swift b/Tests/BlackBoxTests/OSLoggerTests.swift index e2a4791..6f61e69 100644 --- a/Tests/BlackBoxTests/OSLoggerTests.swift +++ b/Tests/BlackBoxTests/OSLoggerTests.swift @@ -24,8 +24,8 @@ class OSLoggerTests: BlackBoxTestCase { try super.tearDownWithError() } - private func createOSLogger(levels: [BBLogLevel]) { - osLogger = .init(levels: levels) + private func createOSLogger(levels: [BBLogLevel], logFormat: BBLogFormat = .default) { + osLogger = .init(levels: levels, logFormat: logFormat) BlackBox.instance = .init(loggers: [osLogger]) logger = osLogger @@ -219,3 +219,67 @@ class OSLoggerMock: OSLogger, TestableLoggerProtocol { super.osLog(data) } } + + + // MARK: - BBLogFormat +extension OSLoggerTests { + func test_whenLogFormatApplied_showingLevelIcon() { + let customLogFormat = BBLogFormat(userInfoFormatOptions: [], sourceSectionInline: false, showLevelIcon: true) + createOSLogger(levels: .allCases, logFormat: customLogFormat) + + waitForLog { BlackBox.log("Hello there") } + + let expectedResult = """ + +🛠 Hello there + +[Source] +OSLoggerTests:230 +test_whenLogFormatApplied_showingLevelIcon() +""" + XCTAssertEqual(osLogger.data?.message, expectedResult) + + } + + func test_whenLogFormatApplied_outputSourceSectionInline() { + let customLogFormat = BBLogFormat(userInfoFormatOptions: [], sourceSectionInline: true, showLevelIcon: false) + createOSLogger(levels: .allCases, logFormat: customLogFormat) + + waitForLog { BlackBox.log("Hello there") } + + let expectedResult = """ + +Hello there + +[Source] OSLoggerTests:248 test_whenLogFormatApplied_outputSourceSectionInline() +""" + XCTAssertEqual(osLogger.data?.message, expectedResult) + + } + + @available(iOS 13.0, tvOS 13.0, watchOS 13.0, *) + func test_whenLogFormatApplied_userInfoFormatted() { + let customLogFormat = BBLogFormat(userInfoFormatOptions: [.prettyPrinted, .withoutEscapingSlashes], + sourceSectionInline: false, + showLevelIcon: false) + createOSLogger(levels: .allCases, logFormat: customLogFormat) + + waitForLog { BlackBox.log("Hello there", userInfo: ["path": "/api/v1/getData"]) } + + let expectedResult = """ + +Hello there + +[Source] +OSLoggerTests:267 +test_whenLogFormatApplied_userInfoFormatted() + +[User Info] +{ + \"path\" : \"/api/v1/getData\" +} +""" + XCTAssertEqual(osLogger.data?.message, expectedResult) + + } +}