Consider the Logger
class from the OSLog
framework: Logger
Since the OSLog API doesn't allow querying for the information such as the name of the file, the line and the function where the log commands have been invoked, I'd like to "embed" those values into the log entry itself.
This can be easily accomplished by adding a new method to the Logger
:
extension Logger {
func d_debug(_ message: @autoclosure () -> Any, _ file: String = #file, _ function: String = #function, line: Int = #line, context: Any? = nil) {
let converted = (file as NSString).lastPathComponent + ":" + String(line) + ":" + function + ": " + "\(message())"
debug("\(converted)")
}
}
The problem with this approach is that I'll have to use the d_debug
method instead of the standard debug
method used by default. Therefore, this modified method will "leak" the implementation details outside of the extension.
What I'm looking for is an option to leverage method overloading and use a different type, i.e. a String
as an input parameter so that my method will be preferred and not the original log method of the Logger
.
For example, the original signature looks like this:
///
/// - Warning: Do not explicity create OSLogMessage. Instead pass a string interpolation.
///
/// - Parameter message: A string interpolation.
public func debug(_ message: OSLogMessage)
However, I'd like to have a method like this:
func debug(_ message: @autoclosure () -> String, _ file: String = #file, _ function: String = #function, line: Int = #line) {
and to keep the notion that this method even exists completely hidden from the call site (if possible).
Ideally, if I remove the extension, the code should still complile.
Are there any options of achieving this behavior? Or anything like this would involve dynamic patching at runtime?
If I understand correctly, you can just name your method debug
, and use the log(level:_:)
method to avoid infinite recursion.
log(level: .debug, "\(custom)")
Swift will resolve debug(...)
calls to your own method instead of the built-in one, as long as you are in the same module as the extension.
Also consider using the custom string interpolation provided by OSLogMessage
.
func debug(_ message: @autoclosure () -> String, _ file: String = #file, _ function: String = #function, line: Int = #line) {
log(level: .debug, "\((file as NSString).lastPathComponent):\(line):\(function):\(message())")
}
Either way though, the caller cannot make use of the custom string interpolation provided by OSLogMessage
, such as custom formats, alignments and privacy. I don't think there is a way to implement that.