Skip to content
/ log Public

Log is a lightweight, flexible Swift logging framework that provides elegant and customizable logging capabilities for iOS, macOS, tvOS, watchOS, and visionOS applications.

License

Notifications You must be signed in to change notification settings

space-code/log

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

65 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

A lightweight logging framework written in Swift

log

License Swift Compatibility Platform Compatibility CI CodeCov GitHub release; latest by date GitHub commit activity

Description

Log is a lightweight, flexible Swift logging framework that provides elegant and customizable logging capabilities for iOS, macOS, tvOS, watchOS, and visionOS applications. With support for multiple output destinations and custom formatting, Log makes debugging and monitoring your apps easier than ever.

Features

✨ Multiple Output Destinations - Console, system log (os_log), and custom printers
🎨 Customizable Formatting - Prefix, timestamp, and custom formatters
πŸ“Š Log Levels - Fine-grained control over message severity
πŸ”§ Extensible - Easy to create custom printers and formatters
πŸ“± Cross-Platform - Works on iOS, macOS, tvOS, watchOS, and visionOS
⚑ Lightweight - Minimal footprint with zero dependencies
🎯 Type-Safe - Leverages Swift's type system for compile-time safety

Table of Contents

Requirements

Platform Minimum Version
iOS 13.0+
macOS 10.15+
tvOS 13.0+
watchOS 7.0+
visionOS 1.0+
Xcode 15.3+
Swift 5.10+

Installation

Swift Package Manager

Add the following dependency to your Package.swift:

dependencies: [
    .package(url: "https://github.com/space-code/log.git", from: "1.3.0")
]

Or add it through Xcode:

  1. File > Add Package Dependencies
  2. Enter package URL: https://github.com/space-code/log.git
  3. Select version requirements

Quick Start

import Log

// Create printers
let consolePrinter = ConsolePrinter()
let osPrinter = OSPrinter()

// Create logger
let log = Logger(
    printers: [consolePrinter, osPrinter],
    logLevel: .all
)

// Start logging
log.info(message: "Application started")
log.debug(message: "Debug information")
log.error(message: "Something went wrong")

Usage

Creating a Logger

Log provides two main printer implementations out of the box:

import Log

// Console printer for Xcode console output
let consolePrinter = ConsolePrinter()

// OS printer for system console (Console.app)
let osPrinter = OSPrinter()

// Create logger with multiple printers
let log = Logger(
    printers: [consolePrinter, osPrinter],
    logLevel: .all
)

Log Levels

Log supports various severity levels for organizing your messages:

import Log

let log = Logger(printers: [ConsolePrinter()], logLevel: .all)

// Different log levels
log.debug(message: "Debug information")
log.info(message: "General informational messages")
log.error(message: "Error messages")
log.fault(message: "Critical fault messages")

Available Log Levels:

  • .debug - Debug information
  • .info - General informational messages
  • .error - Error messages
  • .fault - Critical system faults
  • .all - Log all messages

Filtering by Level:

// Only log errors
let log = Logger(
    printers: [ConsolePrinter()],
    logLevel: .errors
)

log.debug(message: "This won't be printed")
log.error(message: "This will be printed")

Printers

Printers determine where your log messages are output:

ConsolePrinter - Outputs to Xcode console:

let consolePrinter = ConsolePrinter(
    formatters: [
        PrefixLogFormatter(name: "MyApp"),
        TimestampLogFormatter(dateFormat: "HH:mm:ss")
    ]
)

OSPrinter - Outputs to system log (viewable in Console.app):

let osPrinter = OSPrinter(
    formatters: [
        PrefixLogFormatter(name: "MyApp")
    ]
)

Using Multiple Printers:

// Log to both Xcode console and system log
let log = Logger(
    printers: [
        ConsolePrinter(formatters: [TimestampLogFormatter()]),
        OSPrinter(formatters: [PrefixLogFormatter(name: "MyApp")])
    ],
    logLevel: .all
)

Message Formatting

Formatters transform your log messages before they're printed. Log includes two built-in formatters:

Formatter Description
PrefixLogFormatter Adds a specified prefix to messages
TimestampLogFormatter Adds a timestamp based on date format

Using Formatters:

import Log

// Prefix formatter
let prefixFormatter = PrefixLogFormatter(name: "NetworkLayer")
let printer = ConsolePrinter(formatters: [prefixFormatter])

let log = Logger(printers: [printer], logLevel: .all)
log.info(message: "Request started")
// Output: ℹ️ [NetworkLayer] => Request started

// Timestamp formatter
let timestampFormatter = TimestampLogFormatter(dateFormat: "yyyy-MM-dd HH:mm:ss")
let printer2 = ConsolePrinter(formatters: [timestampFormatter])

let log2 = Logger(printers: [printer2], logLevel: .all)
log2.info(message: "User logged in")
// Output: ℹ️ 2025-12-22 15:56:42 User logged in

// Combining formatters
let combinedPrinter = ConsolePrinter(formatters: [
    TimestampLogFormatter(dateFormat: "HH:mm:ss"),
    PrefixLogFormatter(name: "API")
])

let log3 = Logger(printers: [combinedPrinter], logLevel: .all)
log3.error(message: "Connection failed")
// Output: ⚠️ [API] => 15:56:42 Connection failed

Custom Formatters

Create custom formatters by conforming to the ILogFormatter protocol:

import Log

struct EnvironmentFormatter: ILogFormatter {
    let environment: String
    
    func format(message: String, with logLevel: LogLevel) -> String {
        return "[\(environment.uppercased())] \(message)"
    }
}

// Usage
let formatter = EnvironmentFormatter(environment: "production")
let printer = ConsolePrinter(formatters: [formatter])
let log = Logger(printers: [printer], logLevel: .all)

log.info(message: "Server started")
// Output: [PRODUCTION] Server started

Advanced Custom Formatter:

struct ContextualFormatter: ILogFormatter {
    let includeThread: Bool
    let includeFile: Bool
    
    func format(message: String, with logLevel: LogLevel) -> String {
        var components: [String] = []
        
        if includeThread {
            components.append("[Thread: \(Thread.current.threadName)]")
        }
        
        if includeFile {
            components.append("[File: \(#file)]")
        }
        
        components.append(message)
        return components.joined(separator: " ")
    }
}

Custom Printer:

import Log

final class FilePrinter: IPrinter {
    let formatters: [ILogFormatter]
    let fileURL: URL
            
    init(formatters: [ILogFormatter] = [], fileURL: URL) {
        self.formatters = formatters
        self.fileURL = fileURL
    }

    func log(_ message: String, logLevel: Log.LogLevel) {
        var formattedMessage = message
                
        for formatter in formatters {
            formattedMessage = formatter.format(
                message: formattedMessage,
                with: logLevel
            )
        }
                
        if let data = (formattedMessage + "\n").data(using: .utf8) {
            // Write to file
        }
    }
}

Common Use Cases

Application Logging

import Log

class AppDelegate: UIResponder, UIApplicationDelegate {
    private let log = Logger(
        printers: [
            ConsolePrinter(formatters: [
                TimestampLogFormatter(dateFormat: "HH:mm:ss.SSS"),
                PrefixLogFormatter(name: "MyApp")
            ]),
            OSPrinter(formatters: [
                PrefixLogFormatter(name: "MyApp")
            ])
        ],
        logLevel: .all
    )
    
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        log.info(message: "Application launched")
        setupApplication()
        return true
    }
    
    private func setupApplication() {
        log.debug(message: "Configuring application")
        // Configuration code
        log.info(message: "Application configured successfully")
    }
}

Network Layer Logging

import Log

class NetworkManager {
    private let log = Logger(
        printers: [
            ConsolePrinter(formatters: [
                TimestampLogFormatter(),
                PrefixLogFormatter(name: "Network")
            ])
        ],
        logLevel: .debug
    )
    
    func fetchData(from url: URL) async throws -> Data {
        log.debug(message: "Requesting: \(url.absoluteString)")
        
        do {
            let (data, response) = try await URLSession.shared.data(from: url)
            
            if let httpResponse = response as? HTTPURLResponse {
                log.info(message: "Response: \(httpResponse.statusCode)")
            }
            
            return data
        } catch {
            log.error(message: "Request failed: \(error.localizedDescription)")
            throw error
        }
    }
}

Database Operations

import Log

class DatabaseManager {
    private let log = Logger(
        printers: [
            ConsolePrinter(formatters: [
                PrefixLogFormatter(name: "Database")
            ])
        ],
        logLevel: .all
    )
    
    func saveRecord(_ record: Record) throws {
        log.debug(message: "Attempting to save record: \(record.id)")
        
        do {
            try database.insert(record)
            log.info(message: "Record saved successfully: \(record.id)")
        } catch {
            log.error(message: "Failed to save record: \(error)")
            throw error
        }
    }
    
    func deleteRecord(id: String) throws {
        log.info(message: "Deleting record: \(id)")
        try database.delete(id)
        log.info(message: "Record deleted: \(id)")
    }
}

Debug vs Production Logging

import Log

class LoggerFactory {
    static func createLogger() -> Logger {
        #if DEBUG
        return Logger(
            printers: [
                ConsolePrinter(formatters: [
                    TimestampLogFormatter(dateFormat: "HH:mm:ss.SSS"),
                    PrefixLogFormatter(name: "Debug")
                ])
            ],
            logLevel: .all
        )
        #else
        return Logger(
            printers: [
                OSPrinter(formatters: [
                    PrefixLogFormatter(name: "Production")
                ])
            ],
            logLevel: .error  // Only log errors in production
        )
        #endif
    }
}

// Usage
let log = LoggerFactory.createLogger()

Communication

Contributing

We love contributions! Please feel free to help out with this project. If you see something that could be made better or want a new feature, open up an issue or send a Pull Request.

Development Setup

Bootstrap the development environment:

make bootstrap

For detailed contribution guidelines, see CONTRIBUTING.md.

Author

Nikita Vasilev

License

Log is released under the MIT license. See LICENSE for details.


⬆ back to top

Made with ❀️ by space-code

About

Log is a lightweight, flexible Swift logging framework that provides elegant and customizable logging capabilities for iOS, macOS, tvOS, watchOS, and visionOS applications.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •