NSLog-как основа ведения журнала для iOS


Я пишу лесозаготовки рамок для iOS. Идея в том, чтобы создать поведение, сходное с NSLog чтобы напечатать журнал сообщений и некоторые метаданные в консоли.

Следующие структуры должна содержать данные записи журнала:

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): "
    }

}

Эта структура затем может быть напечатано с помощью следующей функции (упрощенная):

public class QLog {

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

}

Конечно, я хочу войти с любой точки в моем коде, как QLogDebug("Test"). Итак, я добавил следующие глобальные функции (я получил идею от https://github.com/goktugyil/QorumLogs):

public func QLogHighlight<T>(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<T>(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<T>(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<T>(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<T>(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)"))
}

Теперь, это немного некрасиво, потому что функция подписи очень долго, а при инициализации объекта экземпляр logentry. Кроме того, все пять функций одинаковы, за исключением имени функции и уровень журнала.

Итак, есть ли возможность укоротить / упростить этот код? Можно ли как-то сократить подписей? Я могу определить функции без копирования-вставки?



325
3
задан 15 февраля 2018 в 06:02 Источник Поделиться
Комментарии
1 ответ

Все ваши лесозаготовки функцию взять Date в качестве первого аргумента, по умолчанию
значение текущей даты. Если нет особых причин, почему абонент
должны пройти определенную дату, вы можете удалить этот аргумент и вычислить
дата внутри функции ведения журналов:

public func qLogHighlight<T>(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)"))
}

или даже дать LogEntry конструктор по умолчанию для date
параметр, так что можно опустить это здесь:

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

Отметим также, что


  • имена функций должны начинаться с Буквы в нижнем регистре (сравните с общими конвенциями в быстром проектировании API руководящие принципы),

  • достаточно пройти .highlight к QLog.log() вызов вместо
    из LogLevel.hightlightтип автоматически выводится из
    контексте.

Если вы хотите пять отдельных входа функций, по одной для каждого уровня, тогда
Я не вижу больше возможностей для сокращения. Альтернативой было бы
определить только одну функцию ведения журнала, которая принимает уровень журнала как
аргумент:

public func qLog<T>(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)"))
}

Это позволит удалить полностью дублирование кода.

Еще несколько мыслей:

Создание дата праматерия - “дорого”, то лучше создать его один раз
и использовать его (сравните, например, “повторное использование форматирования экземпляры” раздела NSFormatter на NSHipster.

Это можно сделать с статическое свойство (которое вычисляется лениво и
только один раз):

public struct LogEntry {

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

...

}

Вместо моста NSString можно использовать

URL(fileURLWithPath: file).lastPathComponent

чтобы получить последний компонент пути к файлам.

За исключением специальных случаев (например, экранирование затвора), свойства
быть доступна без использования self:

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

2
ответ дан 3 марта 2018 в 09:03 Источник Поделиться