Logging in Swift Applications: Best Practices for Beginners

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 for Beginners



Logging is one of the most important tools in a developer's arsenal. Without it, debugging complex errors in production turns into a guessing game. In this article, we will cover best practices for logging in Swift applications for iOS and macOS, starting from the basics and moving to advanced techniques. You will learn not just how to output text to the console, but how to build a system that helps you quickly find and fix bugs.



Why shouldn't you use print() in production?



Many beginner developers use print() to output debugging information. This works during development, but in a finished application, this approach creates many problems:



  • No level control: you cannot filter only errors or only warnings.
  • Performance degradation: print() synchronously blocks the thread, which can cause noticeable UI lag.
  • Lack of categorization: all messages are dumped into one pile, making it impossible to understand which module the message came from.
  • No persistence: print() output is not saved on the user's device; you cannot analyze logs after an app crash.
  • Security issues: an accidentally left print() can output sensitive data to the console.


Instead of print(), use os_log from the Unified Logging framework (available since iOS 10 / macOS 10.12).



Setting up OSLog: Basic Example



First, import the os.log framework and create a logger object for your module:



import os.log

let logger = Logger( subsystem: "com.yourapp.networking", category: "API")

func fetchUsers() { logger.info("Starting to load users...") // Request logic logger.debug("Received \\(usersCount) users")}


Parameter breakdown:

  • subsystem — usually your application's identifier (bundle ID). Allows grouping logs by application.
  • category — the name of the module or component (e.g., "UI", "Network", "Database").


In Xcode, you can filter logs by subsystem and category in the console, which greatly simplifies analysis.



Logging Levels: When to Use What?



Unified Logging supports 6 logging levels. Choosing the right level is half the battle:



  • debug — for debugging during development. Not saved on the user's device (unless special profiling is enabled).
  • info — for important events that may be useful during analysis (e.g., screen launch, successful request).
  • notice — the default level. Used for events that are not errors but deserve attention.
  • error — for handled errors (e.g., failed to load data, but the application continues working).
  • fault — for critical failures that lead to app crashes or data loss.
  • critical — rarely used, for particularly severe situations (e.g., database corruption).


import os.log

let logger = Logger(subsystem: "com.yourapp", category: "general")

logger.debug("Debug only: \\(someVariable)")logger.info("User opened the profile screen")logger.notice("Non-standard scenario detected")logger.error("Network error: \\(error.localizedDescription)")logger.fault("Critical error: application b

Blogs

Book Recommendations