NSLog-like logging framework for iOS I am writing a logging framework for iOS. The idea is to create a behavior similar to NSLog to print the log message and some metadata to the console.

The following struct shall hold the data of a log entry:

public enum LogLevel: Int {

    case highlight = 4
    case debug = 3
    case info = 2
    case warning = 1
    case error = 0

}

public struct LogEntry {

    let date: Date
    let file: String
    let function: String
    let line: Int
    let logLevel: LogLevel
    let text: String

    var metaText: String {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "HH:mm:ss"
        return "\(dateFormatter.string(from: self.date)): \((self.file as NSString).lastPathComponent):\(self.line) \(self.function): "
    }

}


The struct can then be printed with the following function (simplified):

public class QLog {

    static func log(_ logEntry: LogEntry) {
        print("\(logEntry.metaText)\(logEntry.text)")
    }

}


Of course I want to log from any point in my code like QLogDebug("Test"). So, I added the following global functions (I got the idea from https://github.com/goktugyil/QorumLogs):

public func QLogHighlight&lt;T&gt;(date: Date = Date(), file: String = #file, function: String = #function, line: Int = #line, _ object: T) {
    QLog.log(LogEntry(date: date, file: file, function: function, line: line, logLevel: LogLevel.highlight, text: "\(object)"))
}

public func QLogDebug&lt;T&gt;(date: Date = Date(), file: String = #file, function: String = #function, line: Int = #line, _ object: T) {
    QLog.log(LogEntry(date: date, file: file, function: function, line: line, logLevel: LogLevel.debug, text: "\(object)"))
}

public func QLogInfo&lt;T&gt;(date: Date = Date(), file: String = #file, function: String = #function, line: Int = #line, _ object: T) {
    QLog.log(LogEntry(date: date, file: file, function: function, line: line, logLevel: LogLevel.info, text: "\(object)"))
}

public func QLogWarning&lt;T&gt;(date: Date = Date(), file: String = #file, function: String = #function, line: Int = #line, _ object: T) {
    QLog.log(LogEntry(date: date, file: file, function: function, line: line, logLevel: LogLevel.warning, text: "\(object)"))
}

public func QLogError&lt;T&gt;(date: Date = Date(), file: String = #file, function: String = #function, line: Int = #line, _ object: T) {
    QLog.log(LogEntry(date: date, file: file, function: function, line: line, logLevel: LogLevel.error, text: "\(object)"))
}


Now, this is a bit ugly because the function signatures are very long as well as the initialization of the LogEntry object. Also, all five functions are the same except the function name and the log level.

So, are there any possibilities to shorten / simplify this code? Can I somehow shorten the signatures? Can I define the functions without copy-pasting them?
All your logging function take a Date as the first argument, with a default
value of the current date. Unless there is a special reason why a caller
should pass a custom date, you can remove that argument and compute the
date inside the logging function:

public func qLogHighlight&lt;T&gt;(file: String = #file, function: String = #function,
                             line: Int = #line, _ object: T) {
    QLog.log(LogEntry(date: Date(), file: file, function: function, line: line,
                      logLevel: .highlight, text: "\(object)"))
}


or even give the LogEntry constructor a default value for the date
parameter, so that you can omit it here:

public func qLogHighlight&lt;T&gt;(file: String = #file, function: String = #function,
                             line: Int = #line, _ object: T) {
    QLog.log(LogEntry(file: file, function: function, line: line,
                      logLevel: .highlight, text: "\(object)"))
}


Note also that


function names should start with a lowercase letter (compare General Conventions in the Swift API Design Guidelines),
it suffices to pass .highlight to the QLog.log() call instead
of LogLevel.hightlight, the type is automatically inferred from the
context.


If you want five separate logging functions, one for each level, then
I do not see more room for shortening. An alternative would be to
define just one logging function which takes the log level as an
argument:

public func qLog&lt;T&gt;(level: LogLevel, file: String = #file, function: String = #function,
                    line: Int = #line, _ object: T) {
    QLog.log(LogEntry(date: Date(), file: file, function: function, line: line,
                      logLevel: level, text: "\(object)"))
}


This would remove to code duplication completely.

Some more thoughts:

Creating a date formatter is “expensive,” it is better to create it once
and reuse it (compare e.g. the “Re-Using Formatter Instances” section in NSFormatter on NSHipster.

This can be done with a static property (which is computed lazily and
only once):

public struct LogEntry {

    static var formatter: DateFormatter = {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "HH:mm:ss"
        return dateFormatter
    }()

    ...

}


Instead of bridging to NSString one can use

URL(fileURLWithPath: file).lastPathComponent


to get the last path component of a file path.

Apart from special cases (such as escaping closures), properties can
be accessed without using self:

var metaText: String {
    return "\(LogEntry.formatter.string(from: date)): \(URL(fileURLWithPath: file).lastPathComponent):\(line) \(function): "
}