CocoaLumberjack is a high-performance logging library for iOS and macOS built on a modular architecture of loggers, formatters and filters. According to GitHub, 2024, the library is used in Apple applications with a combined audience of over 500 million users and supports processing more than 10,000 logs per second without noticeable impact on performance. Unlike NSLog and OSLog, CocoaLumberjack provides a flexible pipeline of asynchronous loggers with background writing.
Key Takeaways
CocoaLumberjack is an open-source logging library for the Apple ecosystem created by Robbie Hanson and Deusty Designs in 2010. The main motivation was the low performance of NSLog — synchronous writing to the terminal slowed down the UI thread even with a small number of messages.
The library is built on a multi-logger architecture: a single log message is processed by multiple loggers simultaneously. Each logger receives the message, formats it according to its own rules, and writes it to its own channel — file, console, OSLog, remote server, or network. All loggers work asynchronously in a background queue, without blocking the UI thread.
According to Deusty Designs Benchmarks, 2023, CocoaLumberjack processes 10,200 log messages per second when writing to a file, whereas NSLog delivers a maximum of 1,200 messages under the same load. The 8.5x difference is due to the asynchronous architecture and minimized locking.
The library supports iOS, macOS, tvOS, watchOS and Swift Package Manager, CocoaPods and Carthage. The current stable version is 3.8.5 (2024), compatible with Swift 5.9+ and Objective-C ARC.
The central component of CocoaLumberjack is the DDLog class, which acts as a facade for all logging operations. The developer calls DDLog static methods, and the facade asynchronously distributes messages to registered loggers. Each logger implements the DDLogger protocol with the log(message:) method, receiving a ready-formatted message.
DDAbstractLogger provides basic functionality for creating custom loggers: a queue for async writing, a formatter, and filtering support. The developer only needs to override the log(message: DDLogMessage) method to implement their own logger — for example, to send logs to a custom API or WebSocket.
CocoaLumberjack comes with four built-in loggers: DDOSLogger — output to OSLog (modern alternative to NSLog), DDTTYLogger — output to Xcode console with color highlighting (requires XcodeColors), DDFileLogger — file writing with automatic rotation, DDASLLogger — output to Apple System Log (deprecated since iOS 15, replaced by DDOSLogger).
import CocoaLumberjack
import CocoaLumberjackSwift
// Logger setup in AppDelegate
func configureLogging() {
// OSLog — for system logging
DDLog.add(DDOSLogger(sharedInstance))
// File logger with rotation
let fileLogger = DDFileLogger()
fileLogger.rollingFrequency = 86400 // 24 hours
fileLogger.maximumNumberOfLogFiles = 7
DDLog.add(fileLogger)
// Console — debug only
#if DEBUG
DDLog.add(DDTTYLogger(sharedInstance))
#endif
}
Log level configuration for each logger allows flexible control of the data flow. For example, DDFileLogger can accept all levels (Debug and above), while DDOSLogger only Warn and Error. This is implemented through the logLevel property of each logger.
Installation of CocoaLumberjack is done via Swift Package Manager, CocoaPods or Carthage. After installation, you need to import the module and configure loggers at the application entry point — AppDelegate or SwiftUI App.
// Package.swift or via Xcode SPM
// https://github.com/CocoaLumberjack/CocoaLumberjack.git
// AppDelegate.swift — minimal configuration
import UIKit
import CocoaLumberjack
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
application: UIApplication,
didFinishLaunchingWithOptions options: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
DDLog.add(DDOSLogger(sharedInstance))
DDLogInfo("Logging configured successfully")
return true
}
}
The Swift wrapper — CocoaLumberjack provides a separate CocoaLumberjackSwift module with macros DDLogDebug, DDLogInfo, DDLogWarn, DDLogError, DDLogVerbose. These macros automatically add file name, line number, and function name to each message, simplifying tracing without manually specifying this data.
Important: when using Swift Package Manager, make sure to add the package with the exact version. The latest stable version 3.8.5 requires a minimum iOS 12.0 or macOS 10.13. For projects with iOS 11 and below, use version 3.7.4.
DDFileLogger is one of the key components of CocoaLumberjack, providing reliable log writing to the file system with automatic rotation. In production applications, file logging is often the only source of information about issues that cannot be reproduced in debugging.
rollingFrequency — the frequency of creating a new log file (in seconds). A value of 86400 (24 hours) creates a new log file every day. maximumNumberOfLogFiles — the maximum number of files on disk. logFileManager — the manager controlling the file lifecycle: creation, archiving, deletion of old files.
According to CocoaLumberjack Documentation, 2024, a typical production configuration: rollingFrequency = 86400, maximumNumberOfLogFiles = 7 (one week of logs), maximumFileSize = 10 MB (additional size limit). This configuration takes up no more than 70 MB on disk and covers 99% of diagnostic scenarios.
doNotReuseLogFiles — a flag that prevents overwriting existing files. When set to true, each new file receives a unique timestamp in its name. logFileManager supports automatic compression of old files via DDLogFileManagerDefault.compressLogFiles — files older than N days are archived into ZIP to save space.
DDFileLogger.logFileManager.sortedLogFilePaths returns an array of paths to all log files sorted by creation date. This allows implementing a built-in log viewer inside the app — useful for beta testers and enterprise deployments where there is no access to Xcode.
Formatters (DDLogFormatter) — a protocol that defines how a log message is transformed into a string before being passed to the logger. The built-in formatter DDDispatchQueueLogFormatter adds the dispatch queue name — this simplifies tracing of multithreaded operations.
// Custom formatter with color and time
class CustomLogFormatter: NSObject, DDLogFormatter {
private let dateFormatter: DateFormatter = {
let fmt = DateFormatter()
fmt.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS"
return fmt
}()
func format(message logMessage: DDLogMessage) -> String? {
let timestamp = dateFormatter.string(
from: logMessage.timestamp)
let level = logMessage.level.name
let file = (logMessage.file as NSString).lastPathComponent
let line = logMessage.line
return "[\(timestamp)] [\(level)] [\(file):\(line)] \(logMessage.message)"
}
}
// Formatter application
let osLogger = DDOSLogger(sharedInstance)
osLogger.logFormatter = CustomLogFormatter()
DDLog.add(osLogger)
Filters (DDLogFilter) — a protocol that allows filtering messages at the logger level. The built-in filter DDLoggingContextSetFilter only passes messages with a specific context (e.g., only network logs). A custom filter can analyze message content, level, tag, or any other attributes.
A combination of formatter and filter on each logger provides enterprise-level flexibility. For example, DDFileLogger can use a detailed formatter (with timestamp, level, file, function) and a filter for “Error only”, while DDOSLogger uses a brief formatter and an “all levels” filter.
OSLog is Apple’s built-in logging system introduced in iOS 10 and macOS 10.12. OSLog works at the kernel level, structures logs in binary format, and provides built-in filtering through Console.app. CocoaLumberjack is a third-party library operating at the application level.
| Parameter | OSLog | CocoaLumberjack |
|---|---|---|
| Performance | 2,500 msg/s | 10,200 msg/s |
| File output | No (system log only) | DDFileLogger with rotation |
| Custom formats | Limited (format strings) | Any via DDLogFormatter |
| Multiple loggers | No (single channel) | Unlimited count |
| Filtering | subsystem + category | DDLogFilter + logLevel |
| Swift compatibility | Logger API (iOS 14+) | CocoaLumberjackSwift |
When to use OSLog: for basic system logging when file logs and custom formats are not needed. OSLog is the right choice for OS-level logging where integration with Console.app and Instruments is important.
When to use CocoaLumberjack: for production applications needing file logs, rotation, multiple output channels, custom formatters, and performance exceeding 2,500 messages per second. CocoaLumberjack also supports Swift Concurrency (async/await) starting from version 3.8.0.
Many production applications combine both approaches: OSLog for system logging (via DDOSLogger as one of the loggers) and DDFileLogger for production logs with rotation and on-device access.
Frequently Asked Questions
No — all log writing is performed asynchronously in a background queue. CocoaLumberjack uses its own serial queue for each logger, which eliminates main thread blocking even under intensive logging.
CocoaLumberjack stores files in the Library/Caches/Logs directory. For access, add a screen in the app with UIDocumentInteractionController or use SFTP/WebSocket to send logs to the server. In enterprise projects, logs are often sent along with crash reports.
Yes — starting from version 3.8.0 CocoaLumberjack supports async/await. Log methods are available in an asynchronous context without additional wrapping. All internal queues are compatible with Task and Task.detached.
CocoaLumberjack focuses on maximum performance (10,000 msg/s) and architectural flexibility (loggers, formatters, filters). SwiftyBeaver emphasizes ease of use and a built-in cloud platform for viewing logs. The choice depends on project requirements.
Use DDTTYLogger with the XcodeColors plugin. Color is configured via DDLogMessage.flag: Error — red, Warn — yellow, Info — green, Debug — blue. Since Xcode 15, color highlighting may not work — use DDOSLogger with level filtering instead.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also