Does Swift Compiler Remove `OSLog` Debug Logs in Release Builds, or Is `#if DEBUG` Necessary to Avoid Overhead?

I'm working on an iOS app using Swift and leveraging OSLog
for logging debug information during development. I’ve been using OSLog
like this:
import OSLog
let logger = Logger(subsystem: "com.example.app", category: "General")
func someFunction() {
logger.debug("Debugging someFunction execution")
// Function logic
}
1. Is #if DEBUG
necessary for debug logs with OSLog
?
I’ve seen some codebases wrap debug log statements in #if DEBUG
preprocessor directives to ensure they’re only included in debug builds, like this:
#if DEBUG
logger.debug("Debugging someFunction execution")
#endif
Is this necessary when using OSLog
? Does the Swift compiler (or OSLog itself) automatically strip out debug-level log calls in release builds, or do I need to explicitly use #if DEBUG
to prevent them from executing?
2. Is there any function call overhead or other performance impact for debug logs in release mode?
If debug logs (e.g., logger.debug
) are not stripped out by the compiler in release builds, is there a measurable overhead (e.g., function call overhead, memory usage, or logging system initialization)? Or does the Swift compiler’s optimization process (or OSLog’s implementation) ensure that debug logs have no impact in release builds?
3. What’s a good practice to avoid writing #if DEBUG
everywhere?
If #if DEBUG
is needed, is there a way to avoid wrapping every log statement with preprocessor directives? For example, can I conditionally define a no-op logger or empty content for release mode to simplify the code? I’m looking for a clean, maintainable approach to handle debug logging globally without repetitive #if DEBUG
checks.
I’m targeting iOS 14+ and using Swift 5.7+. I’d appreciate any insights into how the Swift compiler handles OSLog calls in release builds and whether wrapping debug logs in #if DEBUG
is a best practice or redundant.
Answer
i have one logger file which have function as you want and that function contains DEBUG
condition you can use i easily. check with given code below:
//
// RBLogger.swift
//
// Created by JatinRB.
//
import UIKit
import Foundation
class RBLogger {
static var logFile: URL? {
guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return nil }
let formatter = DateFormatter()
formatter.dateFormat = "dd-MM-yyyy"
let dateString = formatter.string(from: Date())
let fileName = "\(dateString).log"
return documentsDirectory.appendingPathComponent(fileName)
}
static func log(_ message: String) {
#if DEBUG
guard let logFile = logFile else {
return
}
print("FILE URL:",logFile)
let formatter = DateFormatter()
formatter.dateFormat = "HH:mm:ss"
let timestamp = formatter.string(from: Date())
guard let data = (timestamp + ": " + message + "\n").data(using: String.Encoding.utf8) else { return }
if FileManager.default.fileExists(atPath: logFile.path) {
if let fileHandle = try? FileHandle(forWritingTo: logFile) {
fileHandle.seekToEndOfFile()
fileHandle.write(data)
fileHandle.closeFile()
}
} else {
try? data.write(to: logFile, options: .atomicWrite)
}
#else
#endif
}
}
Usage:
RBLogger.log("\(self) ==> \(#line) ==> \(#function)")
What you want to print in debug you can print it using this function and it also avoid debug everywhere.
Location(Where it's store):
it will store logfile in your running device Documents
folder you can access it using Supports Document Browser
to YES
in info.plist
Result