Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
signalapp
GitHub Repository: signalapp/Signal-iOS
Path: blob/main/SignalServiceKit/Debugging/LogFormatter.swift
1 views
//
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//

import CocoaLumberjack
import Foundation

final class LogFormatter: NSObject, DDLogFormatter {
    func format(message logMessage: DDLogMessage) -> String? {
        return Self.formatLogMessage(logMessage, modifiedMessage: nil)
    }

    static func formatLogMessage(_ logMessage: DDLogMessage, modifiedMessage: String?) -> String {
        let timestamp = dateFormatter.string(from: logMessage.timestamp)
        let level = Self.formattedLevel(for: logMessage.flag)
        let location = Self.formattedLocation(logMessage: logMessage)
        let message = modifiedMessage ?? logMessage.message

        return "\(timestamp)  \(level) \(location)\(message)"
    }

    private static let dateFormatter: DateFormatter = {
        // Copied from DDLogFileFormatterDefault.
        let formatter = DateFormatter()
        formatter.formatterBehavior = .behavior10_4
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.timeZone = TimeZone(secondsFromGMT: 0)
        formatter.dateFormat = "yyyy/MM/dd HH:mm:ss:SSS"
        return formatter
    }()

    private static func formattedLevel(for flag: DDLogFlag) -> String {
        if flag.contains(.error) { return "ERR❤️" } // Error
        if flag.contains(.warning) { return "WRN🧡" } // Warning
        if flag.contains(.info) { return "INF💛" } // Info
        if flag.contains(.debug) { return "DBG💚" } // Debug
        if flag.contains(.verbose) { return "VRB💙" } // Verbose
        return "UNK💜" // Unknown
    }

    private static func formattedLocation(logMessage: DDLogMessage) -> String {
        var file = logMessage.file
        file = file.replacingOccurrences(of: ".swift", with: "")

        let line = logMessage.line

        // Drop the arguments from the function name.
        var function = logMessage.function ?? ""
        if let parensIndex = function.firstIndex(of: "(") {
            function = String(function[..<parensIndex])
        }

        if file.isEmpty, line == 0, function.isEmpty {
            return ""
        }

        return "[\(file):\(line)\(function.isEmpty ? "" : " ")\(function)]: "
    }
}