diff --git a/.swiftlint.yml b/.swiftlint.yml index 6d90edc..58036d3 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -16,7 +16,6 @@ opt_in_rules: # some rules are only opt-in - attributes - closure_body_length - closure_end_indentation - - closure_spacing - collection_alignment - contains_over_filter_count - contains_over_filter_is_empty diff --git a/Sources/Log/Classes/Core/Logger/Logger.swift b/Sources/Log/Classes/Core/Logger/Logger.swift index b6a0a22..2af975c 100644 --- a/Sources/Log/Classes/Core/Logger/Logger.swift +++ b/Sources/Log/Classes/Core/Logger/Logger.swift @@ -1,8 +1,10 @@ // // log -// Copyright © 2023 Space Code. All rights reserved. +// Copyright © 2024 Space Code. All rights reserved. // +import Foundation + // MARK: - Logger /// A class responsible for logging functionality. @@ -10,7 +12,14 @@ open class Logger { // MARK: Properties /// The current log level for this logger. - let logLevel: LogLevel + private var _logLevel: Atomic + + /// The current log level for this logger. + public var logLevel: LogLevel { + get { _logLevel.value } + set { _logLevel.value = newValue } + } + /// An array of printer strategies to handle the log output. let printers: [IPrinterStrategy] @@ -26,7 +35,7 @@ open class Logger { logLevel: LogLevel ) { self.printers = printers - self.logLevel = logLevel + _logLevel = Atomic(value: logLevel) } // MARK: Private diff --git a/Sources/Log/Classes/Helpers/Atomic/Atomic.swift b/Sources/Log/Classes/Helpers/Atomic/Atomic.swift new file mode 100644 index 0000000..6d0b4cb --- /dev/null +++ b/Sources/Log/Classes/Helpers/Atomic/Atomic.swift @@ -0,0 +1,43 @@ +// +// log +// Copyright © 2024 Space Code. All rights reserved. +// + +import Foundation + +// MARK: - Atomic + +/// The Atomic class is designed to provide thread-safe access to a mutable value. +final class Atomic { + // MARK: Properties + + /// NSLock instance for synchronization. + private let lock = NSLock() + /// The actual mutable value. + private var _value: Value + + /// Computed property to get and set the value atomically + var value: Value { + get { lock.synchronized { _value } } + set { lock.synchronized { _value = newValue }} + } + + // MARK: Initialization + + /// Initializes the Atomic instance with an initial value. + init(value: Value) { + _value = value + } +} + +// MARK: - Extensions + +private extension NSLock { + /// Synchronizes a code block using the NSLock instance. + /// This helps ensure that only one thread can access the critical section at a time. + func synchronized(block: () throws -> T) rethrows -> T { + lock() + defer { unlock() } + return try block() + } +} diff --git a/Tests/LogTests/UnitTests/LogTests.swift b/Tests/LogTests/UnitTests/LogTests.swift index 4284ac4..a9bf700 100644 --- a/Tests/LogTests/UnitTests/LogTests.swift +++ b/Tests/LogTests/UnitTests/LogTests.swift @@ -1,6 +1,6 @@ // // log -// Copyright © 2023 Space Code. All rights reserved. +// Copyright © 2024 Space Code. All rights reserved. // import Log @@ -119,6 +119,21 @@ final class LogTests: XCTestCase { XCTAssertNil(printerMock.invokedLogParameters?.message) } + func test_thatLoggerDoesNotPrintAnything_whenLogLevelValueDidChange() { + // given + let sut = prepareSut() + + // when + sut.logLevel = .info + sut.debug(message: .message) + sut.info(message: .message) + + // then + XCTAssertEqual(sut.logLevel, .info) + XCTAssertEqual(printerMock.invokedLogCount, 1) + XCTAssertEqual(printerMock.invokedLogParameters?.message, .message) + } + // MARK: Private private func prepareSut(logLevel: LogLevel = .all) -> Logger {