Logging in Swift Applications: Best Practices in Practice

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Logging in Swift Applications: Best Practices in Practice

Logging is not just about writing messages to the console. In professional iOS/macOS development, properly configured logging becomes an indispensable tool for debugging, monitoring, and analyzing application behavior in production. In this article, we will break down best practices for logging in Swift, explore modern tools (os_log, SwiftyBeaver), and write real code examples that you can implement in your project today.



Why print() is Bad for Production

Many beginner developers use print() for debugging. However, in production applications, this leads to problems:

  • Performance: print() synchronously blocks the thread, slowing down the UI.
  • Security: Sensitive data (tokens, passwords) can end up in system logs.
  • Lack of filtering: You cannot separate debug messages from errors.
  • No structure: Each message is just a string without metadata (level, category, file, function).

Instead of print(), use the system framework os_log (Unified Logging) or third-party libraries such as SwiftyBeaver.



Best Practice #1: Using os_log (Unified Logging System)

Starting with iOS 10 / macOS 10.12, Apple recommends using os_log from the OSLog framework. This is a built-in mechanism that works asynchronously, does not affect performance, and automatically collects metadata.



Basic os_log Setup

import OSLog

// Create a logger for the "Network" modulelet networkLogger = Logger(subsystem: "com.yourapp.network", category: "HTTP")

// Log different levelsnetworkLogger.debug("Request sent: \\(url)")networkLogger.info("Response received: \\(statusCode)")networkLogger.error("Connection error: \\(error.localizedDescription)")networkLogger.fault("Critical error: data loss")


Advantages of os_log:

  • Asynchronous: Does not block the main thread.
  • Levels: debug, info, error, fault — can be filtered in the Xcode console.
  • Security: Sensitive data is automatically masked in release builds.
  • Integration with Console.app: All logs are available on the user's device (with their permission).


Dynamic Levels for Debugging

For convenience, you can create a wrapper that allows enabling/disabling debug logs depending on the build scheme:

import OSLog

struct AppLogger { private static let subsystem = "com.yourapp.main" static let general = Logger(subsystem: subsystem, category: "General") static let network = Logger(subsystem: subsystem, category: "Network") static let database = Logger(subsystem: subsystem, category: "Database") static func debug(_ message: String, file: String = #file, function: String = #function, line: Int = #line) { #if DEBUG let fileName = (file as NSString).lastPathComponent general.debug("[\\(fileName):\\(line)] \\(function) - \\(message)") #endif }}

// UsageAppLogger.debug("User tapped login button")AppLogger.network.info("API call started")


Best Practice #2: SwiftyBeaver — Flexible Logging for Complex Projects

If you need advanced functionality (logging to a file, sending to a server, colored console output), check out SwiftyBeaver. It is one of the most popular libraries for logging in Swift.



Installation via Swift Package Manager

// In Package.swift or via Xcode -> File -> Add Packages// URL: ht                

Blogs

Book Recommendations