Swift Runtime Logging: Revealing Hidden Bugs

Mukhammadjon Tokhirov
2 min readMay 25, 2023

As developers, we all know the challenges of debugging runtime issues in Swift applications. Those elusive bugs that surface intermittently or seem impossible to reproduce can bring our productivity to a halt. However, fear not! In this article, we’ll explore a Swift code snippet that introduces a runtime logging mechanism. By this approach, we can gain valuable insights into our application’s behavior and unravel those hidden bugs that have been causing headaches.

Generally it is a simple code

public struct Logging {
public static func l(_ message: @autoclosure () -> Any, _ write: Bool = true) {
#if DEBUG
print(message())
#endif

if AppConfig.environment != .production, write {
print(message())
}
}

// Write log to file
public static func lf(tag: @autoclosure () -> String = "Log", _ message: @autoclosure () -> Any) {
if let path = FileManager.default.urls(for: .documentDirectory, in: .allDomainsMask).first {
if !path.exists {
FileManager.default.createFile(atPath: path.absoluteString, contents: nil)
}

let logURL = path.appendingPathComponent("\(Date().toString(format: "dd:MM:yyyy"))_falconLog_\(AppConfig.sessionNumber ?? 0).txt")
do {
let timestamp = Date().toString(format: "HH:mm:ss")
let log = "\(timestamp) [\(tag())]: \(message())\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n"
try log.append(to: logURL)
} catch {
print("Error writing to log file: \(error)")
}
}
}
}

You may have some missing class, objects or extensions. For my case they are in the following code snippet.

enum Environment {
case production
case development
}

// Application config struct that holds static properties
struct AppConfig {
static var environment: Environment = .development
static var sessionNumber: Int = 0
}

fileprivate extension String {
func append(to url: URL) throws {
let data = self.data(using: .utf8)
try data?.append(fileURL: url)
}
}

fileprivate extension Data {
func append(fileURL: URL) throws {
if let fileHandle = FileHandle(forWritingAtPath: fileURL.path) {
defer {
fileHandle.closeFile()
}
fileHandle.seekToEndOfFile()
fileHandle.write(self)
} else {
try write(to: fileURL, options: .atomic)
}
}
}

Integrating this logging mechanism into your development workflow can save you countless hours of frustration, allowing you to identify and resolve bugs more effectively.

--

--