From 928f651e0ff034eeaea762c84821ae1191184597 Mon Sep 17 00:00:00 2001 From: Nikita Vasilev Date: Thu, 18 Jan 2024 19:34:37 +0100 Subject: [PATCH 1/4] Hide some implementation details --- .../Core/Printers/ConsolePrinter.swift | 15 ++++- .../Log/Classes/Core/Printers/OSPrinter.swift | 37 +++++------ .../Writers/ConsoleWriter/ConsoleWriter.swift | 8 +-- .../ConsoleWriter/IConsoleWriter.swift | 4 +- .../Helpers/Writers/OSWriter/IOSWriter.swift | 8 +-- .../Helpers/Writers/OSWriter/OSWriter.swift | 61 ++++++++++++++++--- .../Strategies/IOSWriterStrategy.swift | 27 ++++++++ Tests/LogTests/Mocks/ConsoleWriterMock.swift | 4 +- Tests/LogTests/Mocks/OSWriterMock.swift | 14 ++--- .../UnitTests/ConsolePrinterTests.swift | 4 +- Tests/LogTests/UnitTests/OSPrinterTests.swift | 16 +++-- 11 files changed, 140 insertions(+), 58 deletions(-) create mode 100644 Sources/Log/Classes/Helpers/Writers/OSWriter/Strategies/IOSWriterStrategy.swift diff --git a/Sources/Log/Classes/Core/Printers/ConsolePrinter.swift b/Sources/Log/Classes/Core/Printers/ConsolePrinter.swift index 103e162..cb3018d 100644 --- a/Sources/Log/Classes/Core/Printers/ConsolePrinter.swift +++ b/Sources/Log/Classes/Core/Printers/ConsolePrinter.swift @@ -1,6 +1,6 @@ // // log -// Copyright © 2023 Space Code. All rights reserved. +// Copyright © 2024 Space Code. All rights reserved. // import Foundation @@ -15,16 +15,25 @@ public final class ConsolePrinter { public let formatters: [ILogFormatter] /// The console writer. - public let consoleWriter: IConsoleWriter + private let consoleWriter: IConsoleWriter // MARK: Initialization + /// Creates a new `ConsolePrinter` instance. + /// + /// - Parameters: + /// - formatters: An array of log formatters for customizing log messages. + public init(formatters: [ILogFormatter]) { + self.formatters = formatters + consoleWriter = ConsoleWriter() + } + /// Creates a new `ConsolePrinter` instance. /// /// - Parameters: /// - formatters: An array of log formatters for customizing log messages. /// - consoleWriter: The console writer. - public init(formatters: [ILogFormatter], consoleWriter: IConsoleWriter = ConsoleWriter()) { + init(formatters: [ILogFormatter], consoleWriter: IConsoleWriter) { self.formatters = formatters self.consoleWriter = consoleWriter } diff --git a/Sources/Log/Classes/Core/Printers/OSPrinter.swift b/Sources/Log/Classes/Core/Printers/OSPrinter.swift index 1964c56..10bcb55 100644 --- a/Sources/Log/Classes/Core/Printers/OSPrinter.swift +++ b/Sources/Log/Classes/Core/Printers/OSPrinter.swift @@ -1,6 +1,6 @@ // // log -// Copyright © 2023 Space Code. All rights reserved. +// Copyright © 2024 Space Code. All rights reserved. // import Foundation @@ -14,15 +14,9 @@ public final class OSPrinter { /// An array of log formatters used to customize log message output. public let formatters: [ILogFormatter] - /// The optional subsystem for categorizing log messages. - public let subsystem: String - /// The optional category for categorizing log messages. - public let category: String - /// The os writer. - public let osWriter: IOSWriter - /// An internal lazy property for initializing the OSLog instance. - private lazy var osLog: OSLog = .init(subsystem: subsystem, category: category) + /// An os writer. + private let osWriter: IOSWriter // MARK: Initialization @@ -32,15 +26,24 @@ public final class OSPrinter { /// - subsystem: An optional subsystem for categorizing log messages. /// - category: An optional category for categorizing log messages. /// - formatters: An array of log formatters for customizing log messages. - /// - osWriter: An os writer. public init( - subsystem: String = "os_printer", - category: String = "", - formatters: [ILogFormatter], - osWriter: IOSWriter = OSWriter() + subsystem: String, + category: String, + formatters: [ILogFormatter] ) { - self.subsystem = subsystem - self.category = category + self.formatters = formatters + osWriter = OSWriter( + subsystem: subsystem, + category: category + ) + } + + /// Creates a new `OSPrinter` instance. + /// + /// - Parameters: + /// - formatters: An array of log formatters for customizing log messages. + /// - osWriter: An os writer. + init(formatters: [ILogFormatter], osWriter: IOSWriter) { self.formatters = formatters self.osWriter = osWriter } @@ -52,7 +55,7 @@ extension OSPrinter: IStyleLogStrategy { public func log(_ message: String, logLevel: LogLevel) { let message = formatMessage(message, logLevel: logLevel) let type = sysLogPriority(logLevel) - osWriter.log("%s", log: osLog, type: type, message) + osWriter.log(type: type, message) } } diff --git a/Sources/Log/Classes/Helpers/Writers/ConsoleWriter/ConsoleWriter.swift b/Sources/Log/Classes/Helpers/Writers/ConsoleWriter/ConsoleWriter.swift index 1549580..adaf162 100644 --- a/Sources/Log/Classes/Helpers/Writers/ConsoleWriter/ConsoleWriter.swift +++ b/Sources/Log/Classes/Helpers/Writers/ConsoleWriter/ConsoleWriter.swift @@ -1,6 +1,6 @@ // // log -// Copyright © 2023 Space Code. All rights reserved. +// Copyright © 2024 Space Code. All rights reserved. // import Foundation @@ -8,15 +8,15 @@ import Foundation // MARK: - ConsoleWriter /// A class that conforms to the IConsoleWriter protocol and writes messages to the console output. -public final class ConsoleWriter: IConsoleWriter { +final class ConsoleWriter: IConsoleWriter { // MARK: Initialization /// Initializes a new ConsoleWriter instance. - public init() {} + init() {} // MARK: IConsoleWriter - public func print(_ message: String) { + func print(_ message: String) { Swift.print(message) } } diff --git a/Sources/Log/Classes/Helpers/Writers/ConsoleWriter/IConsoleWriter.swift b/Sources/Log/Classes/Helpers/Writers/ConsoleWriter/IConsoleWriter.swift index 09d5a93..b0b5b6c 100644 --- a/Sources/Log/Classes/Helpers/Writers/ConsoleWriter/IConsoleWriter.swift +++ b/Sources/Log/Classes/Helpers/Writers/ConsoleWriter/IConsoleWriter.swift @@ -1,12 +1,12 @@ // // log -// Copyright © 2023 Space Code. All rights reserved. +// Copyright © 2024 Space Code. All rights reserved. // import Foundation /// A protocol for writing messages to the console. -public protocol IConsoleWriter { +protocol IConsoleWriter { /// Prints a message to the console output. /// /// - Parameter message: The message to be printed as a String. diff --git a/Sources/Log/Classes/Helpers/Writers/OSWriter/IOSWriter.swift b/Sources/Log/Classes/Helpers/Writers/OSWriter/IOSWriter.swift index ec2fcab..29aa5f9 100644 --- a/Sources/Log/Classes/Helpers/Writers/OSWriter/IOSWriter.swift +++ b/Sources/Log/Classes/Helpers/Writers/OSWriter/IOSWriter.swift @@ -1,6 +1,6 @@ // // log -// Copyright © 2023 Space Code. All rights reserved. +// Copyright © 2024 Space Code. All rights reserved. // import Foundation @@ -11,9 +11,7 @@ public protocol IOSWriter { /// Writes a log message to the specified OSLog. /// /// - Parameters: - /// - message: A StaticString containing the log message format. - /// - log: An OSLog object representing the log subsystem and category. /// - type: An OSLogType indicating the log message type. - /// - args: A variadic list of CVarArg values to fill in the message format. - func log(_ message: StaticString, log: OSLog, type: OSLogType, _ args: CVarArg...) + /// - message: A variadic list of String values to fill in the message format. + func log(type: OSLogType, _ message: String) } diff --git a/Sources/Log/Classes/Helpers/Writers/OSWriter/OSWriter.swift b/Sources/Log/Classes/Helpers/Writers/OSWriter/OSWriter.swift index a4ad3ad..8af506b 100644 --- a/Sources/Log/Classes/Helpers/Writers/OSWriter/OSWriter.swift +++ b/Sources/Log/Classes/Helpers/Writers/OSWriter/OSWriter.swift @@ -1,6 +1,6 @@ // // log -// Copyright © 2023 Space Code. All rights reserved. +// Copyright © 2024 Space Code. All rights reserved. // import Foundation @@ -8,16 +8,63 @@ import OSLog // MARK: - OSWriter -/// A class that conforms to the IOSWriter protocol and writes log messages to the Apple OSLog system. -public final class OSWriter: IOSWriter { +final class OSWriter: IOSWriter { + // MARK: Properties + + /// The optional subsystem for categorizing log messages. + private let subsystem: String + /// The optional category for categorizing log messages. + private let category: String + + /// An internal lazy property for initializing the OSLog instance. + private var osLog: OSLog { OSLog(subsystem: subsystem, category: category) } + + /// An internal lazy property for initializing WriteStrategy instance. + private lazy var writerStrategy: IOSWriterStrategy = { + if #available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *) { + return os.Logger(osLog) + } else { + return LegacyOSLogger(osLog: osLog) + } + }() + // MARK: Initialization - /// Creates a new `OSWriter` instance. - public init() {} + /// Creates a `OSWriter` instance. + /// + /// - Parameters: + /// - subsystem: An optional subsystem for categorizing log messages. + /// - category: An optional category for categorizing log messages. + init(subsystem: String, category: String) { + self.subsystem = subsystem + self.category = category + } // MARK: IOSWriter - public func log(_ message: StaticString, log: OSLog, type: OSLogType, _ args: CVarArg...) { - os_log(message, log: log, type: type, args) + func log(type: OSLogType, _ message: String) { + writerStrategy.log(type: type, message) + } +} + +// MARK: OSWriter.LegacyOSLogger + +private extension OSWriter { + struct LegacyOSLogger: IOSWriterStrategy { + // MARK: Private + + private let osLog: OSLog + + // MARK: Initialization + + init(osLog: OSLog) { + self.osLog = osLog + } + + // MARK: IOSWriterStrategy + + func log(type: OSLogType, _ message: String) { + os_log("%s", log: osLog, type: type, message) + } } } diff --git a/Sources/Log/Classes/Helpers/Writers/OSWriter/Strategies/IOSWriterStrategy.swift b/Sources/Log/Classes/Helpers/Writers/OSWriter/Strategies/IOSWriterStrategy.swift new file mode 100644 index 0000000..bb8f3ed --- /dev/null +++ b/Sources/Log/Classes/Helpers/Writers/OSWriter/Strategies/IOSWriterStrategy.swift @@ -0,0 +1,27 @@ +// +// log +// Copyright © 2024 Space Code. All rights reserved. +// + +import os + +// MARK: - IOSWriterStrategy + +/// Protocol defining the contract for a logger strategy that writes logs to the iOS system logs using OSLog. +protocol IOSWriterStrategy { + /// Writes a log message to the iOS system logs with the specified log type. + /// + /// - Parameters: + /// - type: The type of the log message (debug, info, error, etc.). + /// - message: The message to be logged. + func log(type: OSLogType, _ message: String) +} + +// MARK: - os.Logger + IOSWriterStrategy + +@available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *) +extension os.Logger: IOSWriterStrategy { + func log(type: OSLogType, _ message: String) { + log(level: type, "\(message)") + } +} diff --git a/Tests/LogTests/Mocks/ConsoleWriterMock.swift b/Tests/LogTests/Mocks/ConsoleWriterMock.swift index 7b0cec8..620f81b 100644 --- a/Tests/LogTests/Mocks/ConsoleWriterMock.swift +++ b/Tests/LogTests/Mocks/ConsoleWriterMock.swift @@ -1,10 +1,10 @@ // // log -// Copyright © 2023 Space Code. All rights reserved. +// Copyright © 2024 Space Code. All rights reserved. // import Foundation -import Log +@testable import Log final class ConsoleWriterMock: IConsoleWriter { var invokedPrint = false diff --git a/Tests/LogTests/Mocks/OSWriterMock.swift b/Tests/LogTests/Mocks/OSWriterMock.swift index 165dc09..0d00eb1 100644 --- a/Tests/LogTests/Mocks/OSWriterMock.swift +++ b/Tests/LogTests/Mocks/OSWriterMock.swift @@ -1,21 +1,21 @@ // // log -// Copyright © 2023 Space Code. All rights reserved. +// Copyright © 2024 Space Code. All rights reserved. // -import Log +@testable import Log import OSLog final class OSWriterMock: IOSWriter { var invokedLog = false var invokedLogCount = 0 - var invokedLogParameters: (message: StaticString, log: OSLog, type: OSLogType, args: CVarArg)? - var invokedLogParametersList = [(message: StaticString, log: OSLog, type: OSLogType, args: CVarArg)]() + var invokedLogParameters: (type: OSLogType, message: String)? + var invokedLogParametersList = [(type: OSLogType, message: String)]() - func log(_ message: StaticString, log: OSLog, type: OSLogType, _ args: CVarArg...) { + func log(type: OSLogType, _ message: String) { invokedLog = true invokedLogCount += 1 - invokedLogParameters = (message, log, type, args) - invokedLogParametersList.append((message, log, type, args)) + invokedLogParameters = (type, message) + invokedLogParametersList.append((type, message)) } } diff --git a/Tests/LogTests/UnitTests/ConsolePrinterTests.swift b/Tests/LogTests/UnitTests/ConsolePrinterTests.swift index 4478dfd..c14640a 100644 --- a/Tests/LogTests/UnitTests/ConsolePrinterTests.swift +++ b/Tests/LogTests/UnitTests/ConsolePrinterTests.swift @@ -1,9 +1,9 @@ // // log -// Copyright © 2023 Space Code. All rights reserved. +// Copyright © 2024 Space Code. All rights reserved. // -import Log +@testable import Log import XCTest // MARK: - ConsolePrinterTests diff --git a/Tests/LogTests/UnitTests/OSPrinterTests.swift b/Tests/LogTests/UnitTests/OSPrinterTests.swift index f4175a5..d3a69fd 100644 --- a/Tests/LogTests/UnitTests/OSPrinterTests.swift +++ b/Tests/LogTests/UnitTests/OSPrinterTests.swift @@ -1,9 +1,9 @@ // // log -// Copyright © 2023 Space Code. All rights reserved. +// Copyright © 2024 Space Code. All rights reserved. // -import Log +@testable import Log import XCTest // MARK: - OSPrinterTests @@ -23,8 +23,6 @@ final class OSPrinterTests: XCTestCase { formatterMock = LogFormatterMock() osWriterMock = OSWriterMock() sut = OSPrinter( - subsystem: .subsystem, - category: .category, formatters: [formatterMock], osWriter: osWriterMock ) @@ -47,7 +45,7 @@ final class OSPrinterTests: XCTestCase { sut.log(.message, logLevel: .all) // then - XCTAssertEqual((osWriterMock.invokedLogParameters?.args as? [String])?.first, .message) + XCTAssertEqual(osWriterMock.invokedLogParameters?.message, .message) } func test_thatConsolePrinterLogsMessage_whenLogLevelIsDebug() { @@ -58,7 +56,7 @@ final class OSPrinterTests: XCTestCase { sut.log(.message, logLevel: .debug) // then - XCTAssertEqual((osWriterMock.invokedLogParameters?.args as? [String])?.first, .message) + XCTAssertEqual(osWriterMock.invokedLogParameters?.message, .message) } func test_thatConsolePrinterLogsMessage_whenLogLevelIsInfo() { @@ -69,7 +67,7 @@ final class OSPrinterTests: XCTestCase { sut.log(.message, logLevel: .info) // then - XCTAssertEqual((osWriterMock.invokedLogParameters?.args as? [String])?.first, .message) + XCTAssertEqual(osWriterMock.invokedLogParameters?.message, .message) } func test_thatConsolePrinterLogsMessage_whenLogLevelIsError() { @@ -80,7 +78,7 @@ final class OSPrinterTests: XCTestCase { sut.log(.message, logLevel: .error) // then - XCTAssertEqual((osWriterMock.invokedLogParameters?.args as? [String])?.first, .message) + XCTAssertEqual(osWriterMock.invokedLogParameters?.message, .message) } func test_thatConsolePrinterLogsMessage_whenLogLevelIsFault() { @@ -91,7 +89,7 @@ final class OSPrinterTests: XCTestCase { sut.log(.message, logLevel: .fault) // then - XCTAssertEqual((osWriterMock.invokedLogParameters?.args as? [String])?.first, .message) + XCTAssertEqual(osWriterMock.invokedLogParameters?.message, .message) } } From 2cc139d70bf720e21abdecda939a35d0b95fec33 Mon Sep 17 00:00:00 2001 From: Nikita Vasilev Date: Thu, 18 Jan 2024 19:37:01 +0100 Subject: [PATCH 2/4] Update `CHANGELOG.md` --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ddaa57c..b054eea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ All notable changes to this project will be documented in this file. #### Added - Update GitHub Actions workflow - Added in Pull Request [#3](https://github.com/space-code/log/pull/3). +- Hide `IOSWriter` & `IConsoleWriter` from the public interface + - Added in Pull Request [#2](https://github.com/space-code/log/pull/2). #### 1.x Releases - `1.0.x` Releases - [1.0.0](#100) From d048f7ce3bf5d794060675cb26fe181c1ab835b2 Mon Sep 17 00:00:00 2001 From: Nikita Vasilev Date: Fri, 19 Jan 2024 07:44:52 +0100 Subject: [PATCH 3/4] Add a test The test just checks that the methods don't cause a crash when printing a message to different outputs. --- .../LogIntegrationTests.swift | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 Tests/LogTests/IntegrationTests/LogIntegrationTests.swift diff --git a/Tests/LogTests/IntegrationTests/LogIntegrationTests.swift b/Tests/LogTests/IntegrationTests/LogIntegrationTests.swift new file mode 100644 index 0000000..c87b149 --- /dev/null +++ b/Tests/LogTests/IntegrationTests/LogIntegrationTests.swift @@ -0,0 +1,70 @@ +// +// log +// Copyright © 2024 Space Code. All rights reserved. +// + +import Log +import XCTest + +// MARK: - LogIntegrationTests + +final class LogIntegrationTests: XCTestCase { + // MARK: Properties + + private var sut: Logger! + + // MARK: XCTestCase + + override func setUp() { + super.setUp() + let formatters: [ILogFormatter] = [ + TimestampLogFormatter(dateFormat: "dd/MM/yyyy"), + PrefixLogFormatter(name: "LogIntegrationTests"), + ] + + sut = Logger( + printers: [ + ConsolePrinter( + formatters: formatters + ), + OSPrinter( + subsystem: .subsystem, + category: .category, + formatters: formatters + ), + ], + logLevel: .all + ) + } + + override func tearDown() { + sut = nil + super.tearDown() + } + + // MARK: Tests + + // The test just checks that the methods don't cause a crash + // when printing a message to different outputs. + func test_logDoesNotThrowUnexpectedBehavior_whenLogMessages() { + // 1. Print an info message + sut.info(message: .message) + + // 2. Print a debug message + sut.debug(message: .message) + + // 3. Print an error message + sut.error(message: .message) + + // 4. Print a fault message + sut.fault(message: .message) + } +} + +// MARK: - Constants + +private extension String { + static let subsystem = "subsystem" + static let category = "category" + static let message = "text" +} From f013ca532ff5c8e04622e53291c9fd9b79286000 Mon Sep 17 00:00:00 2001 From: Nikita Vasilev Date: Fri, 19 Jan 2024 07:57:54 +0100 Subject: [PATCH 4/4] Update `codecov.yml` --- codecov.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codecov.yml b/codecov.yml index b415604..8bb858a 100644 --- a/codecov.yml +++ b/codecov.yml @@ -32,7 +32,7 @@ coverage: target: 85% # Allow coverage to drop by X% - threshold: 5% + threshold: 50% changes: no comment: