element-x-ios/ElementX/Sources/Other/Logging/MXLog.swift

178 lines
7.2 KiB
Swift

//
// Copyright 2021 The Matrix.org Foundation C.I.C
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Foundation
import SwiftyBeaver
/// Various MXLog configuration options. Used in conjunction with `MXLog.configure()`
public class MXLogConfiguration: NSObject {
/// the desired log level. `.verbose` by default.
public var logLevel = MXLogLevel.verbose
/// whether logs should be written directly to files. `false` by default.
public var redirectLogsToFiles = false
/// the maximum total space to use for log files in bytes. `100MB` by default.
public var logFilesSizeLimit: UInt = 100 * 1024 * 1024 // 100MB
/// the maximum number of log files to use before rolling. `50` by default.
public var maxLogFilesCount: UInt = 50
/// the subname for log files. Files will be named as 'console-[subLogName].log'. `nil` by default
public var subLogName: String?
}
/// MXLog logging levels. Use .none to disable logging entirely.
public enum MXLogLevel: UInt {
case none
case verbose
case debug
case info
case warning
case error
}
private var logger: SwiftyBeaver.Type = {
let logger = SwiftyBeaver.self
MXLog.configureLogger(logger, withConfiguration: MXLogConfiguration())
return logger
}()
/**
Logging utility that provies multiple logging levels as well as file output and rolling.
Its purpose is to provide a common entry for customizing logging and should be used throughout the code.
Please see `MXLog.h` for Objective-C options.
*/
public class MXLog: NSObject {
/// Method used to customize MXLog's behavior.
/// Called automatically when first accessing the logger with the default values.
/// Please see `MXLogConfiguration` for all available options.
/// - Parameters:
/// - configuration: the `MXLogConfiguration` instance to use
public static func configure(_ configuration: MXLogConfiguration) {
configureLogger(logger, withConfiguration: configuration)
}
public static func verbose(_ message: @autoclosure () -> Any,
file: String = #file,
function: String = #function,
line: Int = #line,
context: Any? = nil) {
logger.verbose(message(), file: file, function: function, line: line, context: context)
}
public static func debug(_ message: @autoclosure () -> Any,
file: String = #file,
function: String = #function,
line: Int = #line,
context: Any? = nil) {
logger.debug(message(), file: file, function: function, line: line, context: context)
}
public static func info(_ message: @autoclosure () -> Any,
file: String = #file,
function: String = #function,
line: Int = #line,
context: Any? = nil) {
logger.info(message(), file: file, function: function, line: line, context: context)
}
public static func warning(_ message: @autoclosure () -> Any,
file: String = #file,
function: String = #function,
line: Int = #line,
context: Any? = nil) {
logger.warning(message(), file: file, function: function, line: line, context: context)
}
/// Log error with additional details
///
/// - Parameters:
/// - message: Description of the error without any variables (this is to improve error aggregations by type)
/// - context: Additional context-dependent details about the issue
public static func error(_ message: @autoclosure () -> Any,
file: String = #file,
function: String = #function,
line: Int = #line,
context: Any? = nil) {
logger.error(message(), file: file, function: function, line: line, context: context)
}
/// Log failure with additional details
///
/// A failure is any type of programming error which should never occur in production. In `DEBUG` configuration
/// any failure will raise `assertionFailure`
///
/// - Parameters:
/// - message: Description of the error without any variables (this is to improve error aggregations by type)
/// - context: Additional context-dependent details about the issue
public static func failure(_ message: String,
file: String = #file,
function: String = #function,
line: Int = #line,
context: Any? = nil) {
logger.error(message, file: file, function: function, line: line, context: context)
#if DEBUG
assertionFailure("\(message)")
#endif
}
// MARK: - Private
fileprivate static func configureLogger(_ logger: SwiftyBeaver.Type, withConfiguration configuration: MXLogConfiguration) {
if let subLogName = configuration.subLogName {
MXLogger.setSubLogName(subLogName)
}
MXLogger.redirectNSLog(toFiles: configuration.redirectLogsToFiles,
numberOfFiles: configuration.maxLogFilesCount,
sizeLimit: configuration.logFilesSizeLimit)
guard configuration.logLevel != .none else {
logger.removeAllDestinations()
return
}
logger.removeAllDestinations()
let consoleDestination = ConsoleDestination()
consoleDestination.useNSLog = true
consoleDestination.asynchronously = false
consoleDestination.format = "$C$N.$F:$l $M $X$c" // See https://docs.swiftybeaver.com/article/20-custom-format
consoleDestination.levelColor.verbose = ""
consoleDestination.levelColor.debug = ""
consoleDestination.levelColor.info = ""
consoleDestination.levelColor.warning = "⚠️ "
consoleDestination.levelColor.error = "🚨 "
switch configuration.logLevel {
case .verbose:
consoleDestination.minLevel = .verbose
case .debug:
consoleDestination.minLevel = .debug
case .info:
consoleDestination.minLevel = .info
case .warning:
consoleDestination.minLevel = .warning
case .error:
consoleDestination.minLevel = .error
case .none:
break
}
logger.addDestination(consoleDestination)
}
}