You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
session-ios/SessionUtilitiesKit/LibSession/LibSession.swift

118 lines
4.8 KiB
Swift

// Copyright © 2023 Rangeproof Pty Ltd. All rights reserved.
//
// stringlint:disable
import Foundation
import SessionUtil
// MARK: - LibSession
public enum LibSession {
public static var version: String { String(cString: LIBSESSION_UTIL_VERSION_STR) }
}
// MARK: - Log.Category
public extension Log.Category {
static let libSession: Log.Category = .create("LibSession", defaultLevel: .info)
}
// MARK: - Logging
extension LibSession {
public static func setupLogger(using dependencies: Dependencies) {
/// Setup any custom category default log levels for libSession
Log.Category.create("config", defaultLevel: .info)
Log.Category.create("network", defaultLevel: .info)
/// Subscribe for log level changes (this wil' emit an initial event which we can use to set the default log level)
dependencies.publisher(featureGroupChanges: .allLogLevels)
.subscribe(on: DispatchQueue.global(qos: .background), using: dependencies)
.receive(on: DispatchQueue.main, using: dependencies)
.sinkUntilComplete(
receiveValue: {
let currentLogLevels: [Log.Category: Log.Level] = dependencies[feature: .allLogLevels]
.currentValues(using: dependencies)
let cDefaultLevel: LOG_LEVEL = (currentLogLevels[.default]?.libSession ?? LOG_LEVEL_OFF)
session_logger_set_level_default(cDefaultLevel)
session_logger_reset_level(cDefaultLevel)
/// Update all explicit log levels (we don't want to register a listener for each individual one so just re-apply all)
///
/// If the conversation to the libSession `LOG_LEVEL` fails then it means we should use the default log level
currentLogLevels.forEach { (category: Log.Category, level: Log.Level) in
guard
let cCat: [CChar] = category.rawValue.cString(using: .utf8),
let cLogLevel: LOG_LEVEL = level.libSession
else { return }
session_logger_set_level(cCat, cLogLevel)
}
}
)
/// Finally register the actual logger callback
session_add_logger_full({ msgPtr, msgLen, catPtr, catLen, lvl in
guard
let msg: String = String(pointer: msgPtr, length: msgLen, encoding: .utf8),
let cat: String = String(pointer: catPtr, length: catLen, encoding: .utf8)
else { return }
/// Dispatch to another thread so we don't block thread triggering the log
DispatchQueue.global(qos: .background).async {
/// Logs from libSession come through in the format:
/// `[yyyy-MM-dd hh:mm:ss] [+{lifetime}s] [{cat}:{lvl}|log.hpp:{line}] {message}`
/// We want to remove the extra data because it doesn't help the logs
let processedMessage: String = {
let logParts: [String] = msg.components(separatedBy: "] ")
guard logParts.count == 4 else { return msg.trimmingCharacters(in: .whitespacesAndNewlines) }
let message: String = String(logParts[3]).trimmingCharacters(in: .whitespacesAndNewlines)
return "\(logParts[1])] \(message)"
}()
Log.custom(
Log.Level(lvl),
[Log.Category(rawValue: cat, customPrefix: "libSession:")],
processedMessage
)
}
})
}
public static func clearLoggers() {
session_clear_loggers()
}
}
// MARK: - Convenience
fileprivate extension Log.Level {
var libSession: LOG_LEVEL? {
switch self {
case .verbose: return LOG_LEVEL_TRACE
case .debug: return LOG_LEVEL_DEBUG
case .info: return LOG_LEVEL_INFO
case .warn: return LOG_LEVEL_WARN
case .error: return LOG_LEVEL_ERROR
case .critical: return LOG_LEVEL_CRITICAL
case .off: return LOG_LEVEL_OFF
case .default: return nil // It'll use the default value by default so just return nil
}
}
init(_ level: LOG_LEVEL) {
switch level {
case LOG_LEVEL_TRACE: self = .verbose
case LOG_LEVEL_DEBUG: self = .debug
case LOG_LEVEL_INFO: self = .info
case LOG_LEVEL_WARN: self = .warn
case LOG_LEVEL_ERROR: self = .error
case LOG_LEVEL_CRITICAL: self = .critical
default: self = .off
}
}
}