diff --git a/Sources/Log/Classes/Core/Formatters/Interfaces/ILogFormatter.swift b/Sources/Log/Classes/Core/Formatters/Interfaces/ILogFormatter.swift index 3ebcd8e..ea43183 100644 --- a/Sources/Log/Classes/Core/Formatters/Interfaces/ILogFormatter.swift +++ b/Sources/Log/Classes/Core/Formatters/Interfaces/ILogFormatter.swift @@ -5,12 +5,22 @@ import Foundation -/// Specifies the format to be used in the log message +/// A protocol that defines the interface for transforming and styling log messages. +/// +/// Types conforming to `ILogFormatter` act as individual steps in a formatting pipeline. +/// They are responsible for taking a message string and augmenting it with additional +/// information—such as timestamps, tags, or emojis—based on the message's severity. public protocol ILogFormatter { - /// Concatenates the specified attributes and generates the final log message + /// Processes the input message and returns a decorated version of it. + /// + /// This method is called by a `Logger` or a `Printer` strategy to prepare the + /// message for final output. Since formatters are often used in a chain, + /// the `message` parameter might already contain modifications from previous formatters. /// /// - Parameters: - /// - message: A `String` value that contains the message. - /// - logLevel: A `LogLevel` value that contains the logging level. + /// - message: The current string content of the log message. + /// - logLevel: The `LogLevel` associated with the message, used to determine + /// appropriate styling or metadata. + /// - Returns: A transformed string containing the formatted log message. func format(message: String, with logLevel: LogLevel) -> String } diff --git a/Sources/Log/Classes/Core/Formatters/PrefixLogFormatter.swift b/Sources/Log/Classes/Core/Formatters/PrefixLogFormatter.swift index b06e5b2..bc8fcb1 100644 --- a/Sources/Log/Classes/Core/Formatters/PrefixLogFormatter.swift +++ b/Sources/Log/Classes/Core/Formatters/PrefixLogFormatter.swift @@ -5,32 +5,49 @@ import Foundation -/// A log formatter that adds a custom prefix to log messages. +/// A log formatter that prepends a custom identifier and visual indicators to log messages. +/// +/// `PrefixLogFormatter` is used to categorize logs by adding a string tag (e.g., a module name). +/// It also automatically adds high-visibility emojis for critical levels like `.fault` and `.error` +/// to help them stand out in dense log outputs. public struct PrefixLogFormatter: ILogFormatter { - // MARK: Properties + // MARK: - Properties - /// The custom prefix to be added to log messages. + /// The string identifier (e.g., "Network", "Auth") prepended to every log message. private let name: String - // MARK: Initialization + // MARK: - Initialization - /// Creates a new `PrefixLogFormatter` instance with the specified prefix. + /// Initializes a new formatter with a specific name. /// - /// - Parameter name: The custom prefix to be added to log messages. + /// - Parameter name: The custom prefix string used to identify the source of the log. public init(name: String) { self.name = name } - // MARK: ILogFormatter + // MARK: - ILogFormatter + /// Prepends the prefix and professional severity-based symbols to the log message. + /// + /// The style is optimized for professional environments: + /// - `.fault`: Uses the stop sign (⛔️) to indicate a critical, unrecoverable failure. + /// - `.error`: Uses the warning sign (⚠️) to indicate a significant but recoverable issue. + /// - `.info`: Uses the information circle (ℹ️) for high-level progress tracking. + /// - `.debug`: Uses a simple diamond (🔹) for development-level details. public func format(message: String, with logLevel: LogLevel) -> String { - switch logLevel { + let symbol = switch logLevel { case .fault: - "🚨🚨🚨 [\(name)] => \(message)" + "⛔️ [\(name)]" case .error: - "💣💥💣💥 [\(name)] => \(message)" + "⚠️ [\(name)]" + case .info: + "ℹ️ [\(name)]" + case .debug: + "🔹 [\(name)]" default: - "[\(name)] => \(message)" + "[\(name)]" } + + return "\(symbol) => \(message)" } } diff --git a/Sources/Log/Classes/Core/Formatters/TimestampLogFormatter.swift b/Sources/Log/Classes/Core/Formatters/TimestampLogFormatter.swift index 0e3c227..d651ab8 100644 --- a/Sources/Log/Classes/Core/Formatters/TimestampLogFormatter.swift +++ b/Sources/Log/Classes/Core/Formatters/TimestampLogFormatter.swift @@ -5,31 +5,44 @@ import Foundation -/// A log formatter that adds a timestamp to log messages. +/// A log formatter that prepends a chronological timestamp to log messages. +/// +/// `TimestampLogFormatter` is essential for tracing the sequence of events during +/// application execution. It allows you to define a custom date format to match +/// your specific debugging or analytics requirements. open class TimestampLogFormatter: ILogFormatter { - // MARK: Properties + // MARK: - Properties - /// The date formatter. + /// The internal date formatter used to convert the current system time into a string. + /// + /// This property is lazily initialized to optimize performance and ensure the + /// formatter is only created when the first log message is processed. private lazy var dateFormatter: DateFormatter = { let dateFormatter = DateFormatter() dateFormatter.dateFormat = dateFormat return dateFormatter }() - /// The date format string. + /// The string pattern defining the appearance of the timestamp (e.g., "yyyy-MM-dd HH:mm:ss"). private let dateFormat: String - // MARK: Initialization + // MARK: - Initialization - /// Creates a new `PrefixFormatter` instance with the specified data formmater. + /// Initializes a new `TimestampLogFormatter` with the specified date format. /// - /// - Parameter dateFormat: The date format string. + /// - Parameter dateFormat: A string representing the desired date and time pattern. public init(dateFormat: String) { self.dateFormat = dateFormat } - // MARK: ILogFormatter + // MARK: - ILogFormatter + /// Prepends a timestamp based on the current system time to the log message. + /// + /// - Parameters: + /// - message: The raw or previously formatted log message. + /// - logLevel: The severity level (ignored by this specific formatter). + /// - Returns: A string combining the timestamp and the message, separated by a space. public func format(message: String, with _: LogLevel) -> String { let timestamp = dateFormatter.string(from: Date()) return [timestamp, message].joined(separator: " ") diff --git a/Sources/Log/Classes/Core/Logger/ILogger.swift b/Sources/Log/Classes/Core/Logger/ILogger.swift index ac3053b..af6d686 100644 --- a/Sources/Log/Classes/Core/Logger/ILogger.swift +++ b/Sources/Log/Classes/Core/Logger/ILogger.swift @@ -5,25 +5,37 @@ import Foundation -/// A type that provides logging functionality. +/// A protocol defining the public interface for a logging coordinator. +/// +/// `ILogger` provides a set of methods for dispatching messages at various severity levels. +/// Implementations should handle filtering based on the current configuration and ensure +/// that log production has minimal impact on application performance. public protocol ILogger { - /// Dispatches the given message using the logger if the debug log level is set. + /// Dispatches a message for fine-grained informational events useful for debugging. /// - /// - Parameter message: An autoclosure returning the message to log. + /// - Parameter message: An autoclosure returning the string to log. The closure is + /// evaluated only if the `.debug` log level is active, preventing unnecessary + /// string construction. func debug(message: @autoclosure () -> String) - /// Dispatches the given message using the logger if the info log level is set. + /// Dispatches an informational message that highlights the progress of the application. /// - /// - Parameter message: An autoclosure returning the message to log. + /// - Parameter message: An autoclosure returning the string to log. The closure is + /// evaluated only if the `.info` log level is active. func info(message: @autoclosure () -> String) - /// Dispatches the given message using the logger if the fault log level is set. + /// Dispatches a message about a severe error or system-level fault. /// - /// - Parameter message: An autoclosure returning the message to log. + /// Use this for critical issues that may require system-level attention or indicate + /// a corruption of state. + /// + /// - Parameter message: An autoclosure returning the string to log. The closure is + /// evaluated only if the `.fault` is active. func fault(message: @autoclosure () -> String) - /// Dispatches the given message using the logger if the error log level is set. + /// Dispatches a message about an error event that might still allow the application to continue running. /// - /// - Parameter message: An autoclosure returning the message to log. + /// - Parameter message: An autoclosure returning the string to log. The closure is + /// evaluated only if the `.error` log level is active. func error(message: @autoclosure () -> String) } diff --git a/Sources/Log/Classes/Core/Logger/Logger.swift b/Sources/Log/Classes/Core/Logger/Logger.swift index 51ceeb1..40e3ca1 100644 --- a/Sources/Log/Classes/Core/Logger/Logger.swift +++ b/Sources/Log/Classes/Core/Logger/Logger.swift @@ -7,52 +7,75 @@ import Foundation // MARK: - Logger -/// A class responsible for logging functionality. +/// A high-level logging coordinator responsible for filtering and dispatching log messages. +/// +/// `Logger` acts as the central entry point for the logging system. It evaluates whether a message +/// should be logged based on the current `logLevel` and then broadcasts allowed messages +/// to a collection of `IPrinterStrategy` implementations. open class Logger { // MARK: Properties - /// The current log level for this logger. - private var _logLevel: Atomic + /// A recursive lock used to synchronize access to the logger's mutable state. + private let lock = NSRecursiveLock() - /// The current log level for this logger. + /// Internal storage for the log level, protected by a lock. + private var _logLevel: LogLevel + + /// The active log level configuration for this logger. + /// + /// This property uses a lock to ensure thread-safe read and write access. public var logLevel: LogLevel { - get { _logLevel.value } - set { _logLevel.value = newValue } + lock.lock() + defer { lock.unlock() } + return _logLevel } - /// An array of printer strategies to handle the log output. + /// The collection of output strategies (printers) that handle the actual delivery of log messages. let printers: [IPrinterStrategy] - // MARK: Initialization + // MARK: - Initialization - /// Initializes a new Logger instance. + /// Initializes a new `Logger` instance. /// /// - Parameters: - /// - printers: An array of printer strategies. - /// - logLevel: The initial log level. + /// - printers: An array of strategies defining where logs should be sent (e.g., Console, OSLog, File). + /// - logLevel: The initial set of allowed log levels. Defaults to specific levels if not provided. public init( printers: [IPrinterStrategy], logLevel: LogLevel ) { self.printers = printers - _logLevel = Atomic(value: logLevel) + _logLevel = logLevel + } + + /// Atomically updates the current log level using a transformation closure. + /// + /// This method prevents race conditions that can occur when multiple threads try to + /// modify the `logLevel` simultaneously (e.g., two threads trying to add different flags at once). + /// + /// - Parameter transform: A closure that receives the current `LogLevel` and returns the new desired value. + public func updateLogLevel(_ transform: (LogLevel) -> LogLevel) { + lock.lock() + defer { lock.unlock() } + _logLevel = transform(_logLevel) } - // MARK: Private + // MARK: - Private Methods - /// Passes the message to each receiver's printer. + /// Dispatches a message to all registered printers if the log level is enabled. /// /// - Parameters: - /// - message: The message to dispatch. - /// - logLevel: The message's level. + /// - message: The string content to log. + /// - logLevel: The severity level associated with this message. private func log(_ message: String, logLevel: LogLevel) { guard isLoggerEnabled(for: logLevel) else { return } printers.forEach { $0.log(message, logLevel: logLevel) } } - /// Checks if the given `LogLevel` is allowed by the receiver. + /// Evaluates whether the current logger configuration allows a specific log level. /// - /// - Parameter logLevel: The log level to check. + /// - Parameter logLevel: The level to validate against the current settings. + /// - Returns: `true` if the level is included in the active `logLevel` set. private func isLoggerEnabled(for logLevel: LogLevel) -> Bool { self.logLevel.contains(logLevel) } @@ -61,18 +84,26 @@ open class Logger { // MARK: ILogger extension Logger: ILogger { + /// Logs a message for debugging purposes. + /// - Parameter message: A closure returning the string to log, evaluated only if `.debug` is enabled. public func debug(message: @autoclosure () -> String) { log(message(), logLevel: .debug) } + /// Logs an informational message highlighting application progress. + /// - Parameter message: A closure returning the string to log, evaluated only if `.info` is enabled. public func info(message: @autoclosure () -> String) { log(message(), logLevel: .info) } + /// Logs a critical fault that may require system-level attention. + /// - Parameter message: A closure returning the string to log, evaluated only if `.fault` is enabled. public func fault(message: @autoclosure () -> String) { log(message(), logLevel: .fault) } + /// Logs an error that occurred during execution. + /// - Parameter message: A closure returning the string to log, evaluated only if `.error` is enabled. public func error(message: @autoclosure () -> String) { log(message(), logLevel: .error) } diff --git a/Sources/Log/Classes/Core/Logger/Strategies/IPrinterStrategy.swift b/Sources/Log/Classes/Core/Logger/Strategies/IPrinterStrategy.swift index d790438..60d9ac7 100644 --- a/Sources/Log/Classes/Core/Logger/Strategies/IPrinterStrategy.swift +++ b/Sources/Log/Classes/Core/Logger/Strategies/IPrinterStrategy.swift @@ -5,15 +5,27 @@ import Foundation -/// A protocol that defines the behavior of a logging printer strategy +/// A protocol that defines a strategy for processing and delivering log messages. +/// +/// `IPrinterStrategy` combines the responsibilities of message formatting and +/// final output delivery. Types conforming to this protocol use an array of +/// `ILogFormatter` objects to transform raw messages before writing them +/// to their respective destinations (e.g., Console, System Logs, or Files). public protocol IPrinterStrategy { - /// An array of log formatters to customize log message output. + /// A collection of formatters used to process and style the log message content. + /// + /// The formatters are typically applied in sequence to add metadata such as + /// timestamps, emojis, or thread information. var formatters: [ILogFormatter] { get } - /// Logs a message with a specified log level. + /// Processes and dispatches a log message. + /// + /// Implementation should first pass the raw message through the `formatters` + /// chain and then transmit the resulting string to the specific output target. /// /// - Parameters: - /// - message: A `String` value that contains the message to dispatch. - /// - logLevel: A `LogLevel` value that contains the logging level. + /// - message: The raw string content provided by the logger. + /// - logLevel: The severity level used for both formatting decisions and + /// target-specific severity mapping. func log(_ message: String, logLevel: LogLevel) } diff --git a/Sources/Log/Classes/Core/Logger/Strategies/IStyleLogStrategy.swift b/Sources/Log/Classes/Core/Logger/Strategies/IStyleLogStrategy.swift index cb2fd16..ecf240b 100644 --- a/Sources/Log/Classes/Core/Logger/Strategies/IStyleLogStrategy.swift +++ b/Sources/Log/Classes/Core/Logger/Strategies/IStyleLogStrategy.swift @@ -7,22 +7,31 @@ import Foundation // MARK: - IStyleLogStrategy -/// Specifies the format to be used in the log message +/// A specialized printer strategy that focuses on styling log messages before output. +/// +/// `IStyleLogStrategy` provides a default implementation for taking a raw log string +/// and passing it through a chain of formatters. This ensures consistency in how +/// logs look across different output targets (e.g., Console vs. OSLog). protocol IStyleLogStrategy: IPrinterStrategy { - /// An array of log formatters to customize log message output. + /// A collection of formatters used to customize the visual representation of the log. var formatters: [ILogFormatter] { get } } extension IStyleLogStrategy { - /// Format the message using formatting rules. + /// Transforms a raw message into a formatted string by applying all registered formatters. + /// + /// This method iterates through the `formatters` array in the order they were provided, + /// allowing each formatter to append, prefix, or modify the string from the previous step. /// /// - Parameters: - /// - message: A `String` value that contains the message. - /// - logLevel: A `LogLevel` value that contains the logging level. + /// - message: The original raw string content to be logged. + /// - logLevel: The severity level, which formatters use to determine styling + /// (e.g., adding a 🔴 emoji for errors). /// - /// - Returns: Formatted message. + /// - Returns: A final, fully styled string ready for output. func formatMessage(_ message: String, logLevel: LogLevel) -> String { var message = message + // Sequentially transform the message string using the pipeline of formatters. formatters.forEach { message = $0.format(message: message, with: logLevel) } return message } diff --git a/Sources/Log/Classes/Core/Printers/ConsolePrinter.swift b/Sources/Log/Classes/Core/Printers/ConsolePrinter.swift index 50b36a9..19910f2 100644 --- a/Sources/Log/Classes/Core/Printers/ConsolePrinter.swift +++ b/Sources/Log/Classes/Core/Printers/ConsolePrinter.swift @@ -7,32 +7,39 @@ import Foundation // MARK: - ConsolePrinter -/// A class for logging messages to the console output. +/// A log printer that outputs formatted messages to the standard console. +/// +/// `ConsolePrinter` transforms raw log messages through a chain of formatters +/// and sends the final string to a `IConsoleWriter`. public final class ConsolePrinter { - // MARK: Properties + // MARK: - Properties - /// An array of log formatters used to customize log message output. + /// A collection of formatters applied sequentially to customize the log message string. + /// + /// Each formatter can add metadata like timestamps, log levels, or emojis before the message is printed. public let formatters: [ILogFormatter] - /// The console writer. + /// The underlying writer responsible for the actual delivery of the message to the console output. private let consoleWriter: IConsoleWriter - // MARK: Initialization + // MARK: - Initialization - /// Creates a new `ConsolePrinter` instance. + /// Creates a new `ConsolePrinter` instance with a default console writer. /// - /// - Parameters: - /// - formatters: An array of log formatters for customizing log messages. + /// - Parameter formatters: An array of log formatters used to process and style the log messages. public init(formatters: [ILogFormatter]) { self.formatters = formatters consoleWriter = ConsoleWriter() } - /// Creates a new `ConsolePrinter` instance. + /// Creates a new `ConsolePrinter` instance with a custom console writer. + /// + /// This initializer is primarily used for dependency injection in unit tests to verify output + /// without printing to the real system console. /// /// - Parameters: /// - formatters: An array of log formatters for customizing log messages. - /// - consoleWriter: The console writer. + /// - consoleWriter: An object conforming to `IConsoleWriter` to handle message output. init(formatters: [ILogFormatter], consoleWriter: IConsoleWriter) { self.formatters = formatters self.consoleWriter = consoleWriter @@ -42,6 +49,14 @@ public final class ConsolePrinter { // MARK: IStyleLogStrategy extension ConsolePrinter: IStyleLogStrategy { + /// Processes and prints a log message to the console. + /// + /// The message is first passed through all registered `formatters` before being + /// sent to the `consoleWriter`. + /// + /// - Parameters: + /// - message: The raw string content to be logged. + /// - logLevel: The severity level of the log, used by formatters for styling or prefixing. public func log(_ message: String, logLevel: LogLevel) { let message = formatMessage(message, logLevel: logLevel) consoleWriter.print(message) diff --git a/Sources/Log/Classes/Core/Printers/Interfaces/IPrinter.swift b/Sources/Log/Classes/Core/Printers/Interfaces/IPrinter.swift index 7274b70..c7e7cd1 100644 --- a/Sources/Log/Classes/Core/Printers/Interfaces/IPrinter.swift +++ b/Sources/Log/Classes/Core/Printers/Interfaces/IPrinter.swift @@ -5,12 +5,20 @@ import Foundation -/// A protocol that defines the behavior for logging messages. +/// A protocol defining the base interface for all log output destinations. +/// +/// Types conforming to `IPrinter` act as the final "sinks" for log data, responsible +/// for delivering processed log messages to specific targets like the console, +/// a persistent file, or a remote server. public protocol IPrinter { - /// Logs a message with a specified log level. + /// Records a log message with a specific severity level. + /// + /// This is the primary entry point for a printer to receive data from the `Logger`. + /// Implementations are responsible for the actual storage or display of the message. /// /// - Parameters: - /// - message: The message to log. - /// - logLevel: The log level indicating the importance of the log message. + /// - message: The string content to be recorded. This is typically already + /// formatted if the printer uses a strategy-based approach. + /// - logLevel: The `LogLevel` flag indicating the severity or importance of the message. func log(_ message: String, logLevel: LogLevel) } diff --git a/Sources/Log/Classes/Core/Printers/OSPrinter.swift b/Sources/Log/Classes/Core/Printers/OSPrinter.swift index edf8e17..9e2584f 100644 --- a/Sources/Log/Classes/Core/Printers/OSPrinter.swift +++ b/Sources/Log/Classes/Core/Printers/OSPrinter.swift @@ -8,24 +8,31 @@ import OSLog // MARK: - OSPrinter -/// A class for logging messages using the OSLog system. +/// A log printer that directs messages to Apple's Unified Logging System (OSLog). +/// +/// `OSPrinter` integrates with the system-level logging facility, allowing logs to be +/// viewed in the macOS Console app. It supports categorization via subsystems and categories, +/// making it ideal for production debugging and performance analysis. public final class OSPrinter { - // MARK: Properties + // MARK: - Properties - /// An array of log formatters used to customize log message output. + /// A collection of formatters used to transform the log message before it is sent to the system. + /// + /// Use these to add prefixes, metadata, or to clean strings before they are persisted + /// by the operating system. public let formatters: [ILogFormatter] - /// An os writer. + /// The underlying writer that handles version-specific OS logging APIs. private let osWriter: IOSWriter - // MARK: Initialization + // MARK: - Initialization - /// Creates a new `OSPrinter` instance. + /// Creates a new `OSPrinter` instance configured with a specific subsystem and category. /// /// - Parameters: - /// - 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. + /// - subsystem: A string used to identify a specific app or large functional module (e.g., "com.app.network"). + /// - category: A string used to further distinguish logs within a subsystem (e.g., "Database"). + /// - formatters: An array of log formatters for customizing the final string output. public init( subsystem: String, category: String, @@ -38,11 +45,14 @@ public final class OSPrinter { ) } - /// Creates a new `OSPrinter` instance. + /// Creates a new `OSPrinter` instance using a pre-configured OS writer. + /// + /// This initializer is primarily intended for dependency injection during testing + /// or for advanced configurations where a specific `IOSWriter` implementation is required. /// /// - Parameters: /// - formatters: An array of log formatters for customizing log messages. - /// - osWriter: An os writer. + /// - osWriter: An object conforming to `IOSWriter` that performs the actual system calls. init(formatters: [ILogFormatter], osWriter: IOSWriter) { self.formatters = formatters self.osWriter = osWriter @@ -52,6 +62,14 @@ public final class OSPrinter { // MARK: IStyleLogStrategy extension OSPrinter: IStyleLogStrategy { + /// Formats and dispatches a log message to the OSLog system. + /// + /// The method first processes the message through the formatter chain, maps the + /// internal `LogLevel` to a native `OSLogType`, and then triggers the system log. + /// + /// - Parameters: + /// - message: The raw string content to be logged. + /// - logLevel: The severity level used to determine the system log priority. public func log(_ message: String, logLevel: LogLevel) { let message = formatMessage(message, logLevel: logLevel) let type = sysLogPriority(logLevel) @@ -59,9 +77,13 @@ extension OSPrinter: IStyleLogStrategy { } } -// MARK: - Extension +// MARK: - Private Mapping extension OSPrinter { + /// Maps the internal `LogLevel` flags to the native Apple `OSLogType` severities. + /// + /// - Parameter logLevel: The custom log level used within the application. + /// - Returns: The corresponding `OSLogType` that the system uses for filtering and persistence. private func sysLogPriority(_ logLevel: LogLevel) -> OSLogType { switch logLevel { case .debug: diff --git a/Sources/Log/Classes/Helpers/Atomic/Atomic.swift b/Sources/Log/Classes/Helpers/Atomic/Atomic.swift deleted file mode 100644 index 6d0b4cb..0000000 --- a/Sources/Log/Classes/Helpers/Atomic/Atomic.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// 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/Sources/Log/Classes/Helpers/Writers/ConsoleWriter/ConsoleWriter.swift b/Sources/Log/Classes/Helpers/Writers/ConsoleWriter/ConsoleWriter.swift index 9a408af..6e099eb 100644 --- a/Sources/Log/Classes/Helpers/Writers/ConsoleWriter/ConsoleWriter.swift +++ b/Sources/Log/Classes/Helpers/Writers/ConsoleWriter/ConsoleWriter.swift @@ -7,15 +7,21 @@ import Foundation // MARK: - ConsoleWriter -/// A class that conforms to the IConsoleWriter protocol and writes messages to the console output. +/// A concrete implementation of the `IConsoleWriter` protocol that outputs messages to the standard console. +/// +/// This class provides a simple wrapper around the `Swift.print(_:separator:terminator:)` function, +/// typically used for local debugging or when specialized system logging is not required. final class ConsoleWriter: IConsoleWriter { - // MARK: Initialization + // MARK: - Initialization - /// Initializes a new ConsoleWriter instance. + /// Creates a new instance of `ConsoleWriter`. init() {} - // MARK: IConsoleWriter + // MARK: - IConsoleWriter + /// Writes the specified message to the standard output. + /// + /// - Parameter message: The string content to be displayed in the console. 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 189cbb4..8a6fd7f 100644 --- a/Sources/Log/Classes/Helpers/Writers/ConsoleWriter/IConsoleWriter.swift +++ b/Sources/Log/Classes/Helpers/Writers/ConsoleWriter/IConsoleWriter.swift @@ -5,10 +5,14 @@ import Foundation -/// A protocol for writing messages to the console. +/// A protocol defining an interface for writing simple text messages to a console or standard output. +/// +/// Implementations of `IConsoleWriter` are typically used for basic debugging or +/// environment-specific logging where the overhead of Apple's Unified Logging System +/// is not necessary. protocol IConsoleWriter { - /// Prints a message to the console output. + /// Outputs a message string to the console. /// - /// - Parameter message: The message to be printed as a String. + /// - Parameter message: The string content to be written to the output stream. func print(_ message: String) } diff --git a/Sources/Log/Classes/Helpers/Writers/OSWriter/IOSWriter.swift b/Sources/Log/Classes/Helpers/Writers/OSWriter/IOSWriter.swift index cce7a16..b699d5f 100644 --- a/Sources/Log/Classes/Helpers/Writers/OSWriter/IOSWriter.swift +++ b/Sources/Log/Classes/Helpers/Writers/OSWriter/IOSWriter.swift @@ -3,15 +3,21 @@ // Copyright © 2023 Space Code. All rights reserved. // -import Foundation import OSLog -/// A protocol for writing log messages to the Apple OSLog system. +/// A protocol defining the interface for objects that write log messages to Apple's Unified Logging System. +/// +/// Types conforming to `IOSWriter` provide a standardized way to route log strings into `OSLog`, +/// allowing for consistent categorization and severity filtering across the application. public protocol IOSWriter { - /// Writes a log message to the specified OSLog. + /// Writes a log message to the system logging facility with a specific severity level. + /// + /// Implementations of this method should map the provided message and type + /// to the underlying system logging APIs (like `os_log` or `Logger`). /// /// - Parameters: - /// - type: An OSLogType indicating the log message type. - /// - message: A variadic list of String values to fill in the message format. + /// - type: The `OSLogType` representing the severity level of the message + /// (e.g., `.info`, `.debug`, `.error`, or `.fault`). + /// - message: The formatted string content to be recorded in the log. 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 ae41bf7..fcbab16 100644 --- a/Sources/Log/Classes/Helpers/Writers/OSWriter/OSWriter.swift +++ b/Sources/Log/Classes/Helpers/Writers/OSWriter/OSWriter.swift @@ -8,38 +8,49 @@ import OSLog // MARK: - OSWriter +/// An implementation of `IOSWriter` that directs log messages to the system logging facility (Apple's Unified Logging System). +/// +/// This class acts as a wrapper that automatically chooses the most appropriate logging API +/// based on the operating system version, ensuring backward compatibility with older Apple platforms. final class OSWriter: IOSWriter { - // MARK: Properties + // MARK: - Properties - /// The optional subsystem for categorizing log messages. + /// The identifier for the subsystem that is performing the logging, typically a reverse DNS string (e.g., "com.app.network"). private let subsystem: String - /// The optional category for categorizing log messages. + + /// The category within the subsystem used to further distinguish logs (e.g., "UI" or "Database"). private let category: String - /// An internal lazy property for initializing the OSLog instance. + /// An internal property used to generate an `OSLog` configuration for both legacy and modern logging APIs. private var osLog: OSLog { OSLog(subsystem: subsystem, category: category) } - /// An internal lazy property for initializing WriteStrategy instance. + /// A strategy-based writer that selects between the modern `os.Logger` (iOS 14+) + /// or a legacy `os_log` wrapper for older systems. private lazy var writerStrategy: IOSWriterStrategy = if #available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *) { os.Logger(osLog) } else { LegacyOSLogger(osLog: osLog) } - // MARK: Initialization + // MARK: - Initialization - /// Creates a `OSWriter` instance. + /// Initializes a new `OSWriter` with a specific subsystem and category. /// /// - Parameters: - /// - subsystem: An optional subsystem for categorizing log messages. - /// - category: An optional category for categorizing log messages. + /// - subsystem: The name of the subsystem to categorize messages. + /// - category: The name of the category to categorize messages. init(subsystem: String, category: String) { self.subsystem = subsystem self.category = category } - // MARK: IOSWriter + // MARK: - IOSWriter + /// Writes a log message to the system log using the active version-specific strategy. + /// + /// - Parameters: + /// - type: The severity level of the log (e.g., `.debug`, `.error`, `.fault`). + /// - message: The string content to be logged. func log(type: OSLogType, _ message: String) { writerStrategy.log(type: type, message) } @@ -48,19 +59,27 @@ final class OSWriter: IOSWriter { // MARK: OSWriter.LegacyOSLogger private extension OSWriter { + /// A fallback logging implementation for platforms that do not support the modern `os.Logger` API. struct LegacyOSLogger: IOSWriterStrategy { // MARK: Private + /// The underlying `OSLog` object used for legacy logging. private let osLog: OSLog // MARK: Initialization + /// Initializes the legacy logger with a configured `OSLog` instance. init(osLog: OSLog) { self.osLog = osLog } // MARK: IOSWriterStrategy + /// Forwards the log message to the C-based `os_log` function. + /// + /// - Parameters: + /// - type: The log level. + /// - message: The string to be recorded in the log. 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 index bb8f3ed..1be6d2a 100644 --- a/Sources/Log/Classes/Helpers/Writers/OSWriter/Strategies/IOSWriterStrategy.swift +++ b/Sources/Log/Classes/Helpers/Writers/OSWriter/Strategies/IOSWriterStrategy.swift @@ -7,13 +7,16 @@ import os // MARK: - IOSWriterStrategy -/// Protocol defining the contract for a logger strategy that writes logs to the iOS system logs using OSLog. +/// A protocol that abstracts the specific logging mechanism used to write to Apple's system logs. +/// +/// This serves as the "Strategy" in a Strategy Pattern, allowing the logger to swap between +/// the modern `os.Logger` API and the legacy `os_log` function depending on platform availability. protocol IOSWriterStrategy { - /// Writes a log message to the iOS system logs with the specified log type. + /// Writes a log message to the system logging facility using the underlying strategy. /// /// - Parameters: - /// - type: The type of the log message (debug, info, error, etc.). - /// - message: The message to be logged. + /// - type: The `OSLogType` defining the severity of the log (e.g., `.default`, `.error`). + /// - message: The string content to be recorded. func log(type: OSLogType, _ message: String) } @@ -21,7 +24,14 @@ protocol IOSWriterStrategy { @available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *) extension os.Logger: IOSWriterStrategy { + /// Bridges the `IOSWriterStrategy` to the modern `os.Logger` API. + /// + /// - Parameters: + /// - type: The `OSLogType` which maps directly to the logger's `OSLogLogLevel`. + /// - message: The message string, passed using a string interpolation wrapper. func log(type: OSLogType, _ message: String) { + // We use string interpolation here because os.Logger expects a OSLogMessage + // which is created via ExpressibleByStringInterpolation. log(level: type, "\(message)") } } diff --git a/Sources/Log/Classes/Models/LogLevel.swift b/Sources/Log/Classes/Models/LogLevel.swift index 519e5e8..8f25e84 100644 --- a/Sources/Log/Classes/Models/LogLevel.swift +++ b/Sources/Log/Classes/Models/LogLevel.swift @@ -7,38 +7,47 @@ import Foundation // MARK: - LogLevel -/// A set that includes all log levels. +/// A set of options representing different levels of logging severity. +/// +/// Since `LogLevel` conforms to `OptionSet`, you can use it to specify a single +/// level or a combination of levels (e.g., `[.info, .error]`). public struct LogLevel: OptionSet, Sendable { - // MARK: Initialization + // MARK: - Initialization - /// Creates a new log level. + /// Creates a new log level from a raw bitmask value. /// - /// - Parameter rawValue: The value that indicates a log level. + /// - Parameter rawValue: The bitmask value representing the desired log levels. public init(rawValue: RawValue) { self.rawValue = rawValue } - // MARK: Types + // MARK: - Types + /// The type of the value used to represent the bitmask. public typealias RawValue = UInt - /// Creates a new default `.off` instance with a bitmask of `1 << 0`. + /// No logging. Usually used to disable all log output. public static let off = LogLevel(rawValue: offBitmask) - /// Creates a new default `.debug` instance with a bitmask of `1 << 1`. + + /// Designates fine-grained informational events that are most useful to debug an application. public static let debug = LogLevel(rawValue: debugBitmask) - /// Creates a new default `.info` instance with a bitmask of `1 << 2`. + + /// Designates informational messages that highlight the progress of the application at a high level. public static let info = LogLevel(rawValue: infoBitmask) - /// Creates a new default `.error` instance with a bitmask of `1 << 3`. + + /// Designates error events that might still allow the application to continue running. public static let error = LogLevel(rawValue: errorBitmask) - /// Creates a new default `.fault` instance with a bitmask of `1 << 4`. + + /// Designates severe error events that lead the application to abort or fail critically. public static let fault = LogLevel(rawValue: faultBitmask) - /// Creates a new default `.error` instance. + + /// A set containing all possible log levels. public static let all = LogLevel(rawValue: allBitmask) - /// Returns the raw bitmask value of the LogLevel and satisfies the `RawRepresentable` protocol. + /// The corresponding value of the raw type used to create this instance. public let rawValue: RawValue - // MARK: Private + // MARK: - Private Constants private static let offBitmask: RawValue = 1 << 0 private static let debugBitmask: RawValue = 1 << 1