Taking Mojtaba Hosseini's answer, I have incorporated it into a Log class to have very detailed logging:
The class is as follows:
import Foundation
import OSLog
class Log {
#if DEBUG
static let logLevel = "deiwv"
#else
static let logLevel = "e"
#endif
static var subsystem = Bundle.main.bundleIdentifier ?? ""
static var flags = [ "e" : "",
"w" : "",
"i" : "",
"d" : "",
"v" : ""
]
static func setup(_ fileStr: String, _ funcStr: String, _ line: Int, _ level: String) -> String {
var fileName = fileStr.components(separatedBy: "/").last ?? ""
fileName = fileName.components(separatedBy:".").first ?? ""
fileName = fileName.padding(toLength: 20, withPad: " ", startingAt: 0)
let funcString = funcStr.padding(toLength: 10, withPad: " ", startingAt: 0)
let lineNum = "\(line)".padding(toLength: 4, withPad: " ", startingAt: 0)
let flag = flags[level] ?? ""
return "\(flag)\(level.uppercased()) \(fileName):\(funcString):\(lineNum)"
}
static func i(_ msg: String, fileStr: String = #file, funcStr: String = #function, line: Int = #line) {
if(logLevel.contains("i")) {
Logger(subsystem: subsystem, category: setup(fileStr, funcStr, line, "i")).info("\(msg)")
}
}
static func e(_ msg: String, fileStr: String = #file, funcStr: String = #function, line: Int = #line) {
if(logLevel.contains("e")) {
Logger(subsystem: subsystem, category: setup(fileStr, funcStr, line, "e")).error("\(msg)")
}
}
static func d(_ msg: String, fileStr: String = #file, funcStr: String = #function, line: Int = #line) {
if(logLevel.contains("d")) {
Logger(subsystem: subsystem, category: setup(fileStr, funcStr, line, "d")).debug("\(msg)")
}
}
static func w(_ msg: String, fileStr: String = #file, funcStr: String = #function, line: Int = #line) {
if(logLevel.contains("w")) {
Logger(subsystem: subsystem, category: setup(fileStr, funcStr, line, "w")).warning("\(msg)")
}
}
static func v(_ msg: String, fileStr: String = #file, funcStr: String = #function, line: Int = #line) {
if(logLevel.contains("v")) {
Logger(subsystem: subsystem, category: setup(fileStr, funcStr, line, "v")).log("\(msg)")
}
}
}
This allows logging i.e. as follows:
Log.i("This is the logged comment")
or
Log.e("This is an error")
Output is tagged and shows the filename, the function name and the line number where the logging occurs, making it much easier to find something in a larger project:
2023-04-12 19:03:22.006185+0100 OOHSystem[34170:6047034] [I InitialViewControlle:viewDidLoa:27 ] Loaded
2023-04-12 19:03:22.006766+0100 OOHSystem[34170:6047034] [I InitialViewControlle:viewWillAp:33 ] Started
2023-04-12 19:03:22.007867+0100 OOHSystem[34170:6047034] [I InitialViewControlle:viewWillAp:47 ] Called from startup
2023-04-12 19:03:22.078324+0100 OOHSystem[34170:6047034] [I UIDeviceExtensions :UIDevice :110 ] identfied: arm64
2023-04-12 19:03:22.079177+0100 OOHSystem[34170:6047034] [V Globals :token :17 ] 3ae51797ac5a8619010352's
By default, production only logs errors but of course that is easy to configure.
There may be better or more elegant ways of achieving this, but it works for me.