在写代码的时候我们通常会埋很多的日志,以方便我们在debug的时候查看哪里出的问题。但在控制台打一堆的日志,看起日志的时候总是不方便。 所以我写的一个可以将我们需要的日志单独导出来的类。好用的话记得点赞哦!
import Cocoa
typealias MLog = MTLogHelper
public enum OutputMode: Int {
case none =0
case redirect
case file
case console
case fileAndConsole
}
public class MTLogHelper: NSObject {
/// Whether to output log files
public static var outModel: OutputMode = .file
private static var pipe = Pipe()
private static var once: Bool = true
private static var lock = NSLock.init()
private static var semaphore = DispatchSemaphore.init(value: 0)
private static var redirectQueue = DispatchQueue.init(label: "com.meitu.logRedirected")
private static var writeQueue = DispatchQueue.init(label: "com.meitu.logWrite")
}
//MARK: - OutPut Model
//MARK: -
extension MTLogHelper {
//封装的日志输出功能(T表示不指定日志信息参数类型)
public class func output
( _ message:T, file:String = #file, function:String = #function, line:Int = #line) {#if DEBUG
let splitLine = "============================================"
let fileName = (file as NSString).lastPathComponent.replacingOccurrences(of: ".swift", with: "")
let outPutContent = "\(fileName):\(String(format: "%04d", line)) | \(function) | \(message)"
/// redirect
if outModel == .redirect {
redirectQueue.sync {
if self.once {
print("===>LogPath: \(logURL.path)")
appendText(splitLine + splitLine )
openConsolePipe()
self.once = false
}
print(outPutContent)
semaphore.wait()
}
return
}
/// one new start
if self.once {
self.once = false
print("===>LogPath: \(logURL.path)")
//try? FileManager.default.removeItem(at: logURL)
appendText(splitLine + splitLine )
}
/// output console
if outModel == .console {
print("\(timeData) \(message)")
}
/// output file
if outModel == .file {
appendText(outPutContent)
}
/// output console and file
if outModel == .fileAndConsole {
print("\(timeData) \(message)")
appendText(outPutContent)
}
#endif
}
/// 重定向
class func openConsolePipe() {
dup2(pipe.fileHandleForWriting.fileDescriptor, STDOUT_FILENO)
// listening on the readabilityHandler
pipe.fileHandleForReading.readabilityHandler = { handle in
let data = handle.availableData
var str = String(data: data, encoding: .ascii) ?? "No finde console data"
str = str.replacingOccurrences(of:"\n", with: "")
appendText(str)
semaphore.signal()
}
}
}
//MARK: - File Path
//MARK: -
extension MTLogHelper {
/// 输出路径
private static var logURL: URL {
let cachePath = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
return cachePath.appendingPathComponent("console.log")
}
/// 获取时间
static var timeData: String {
let dformatter = DateFormatter()
dformatter.dateFormat ="yy-MM-dd HH:mm:ss:SS"
let datestr = dformatter.string(from: Date())
return datestr
}
// 输出到指定文件
class func appendText(_ string: String) {
try? writeQueue.sync {
lock.lock()
//如果文件不存在则新建一个
if !FileManager.default.fileExists(atPath: logURL.path) {
FileManager.default.createFile(atPath: logURL.path, contents: nil)
}
let fileHandle = try FileHandle(forWritingTo: logURL)
let stringToWrite = timeData + " " + string + "\n"
/// 读取数据再写入
//let oldData = try String(contentsOf: logURL, encoding: .utf8).data(using: .utf8)!
let data = stringToWrite.data(using: .utf8)!
//data.append(oldData)
if #available(macOS 10.15.4, *) {
try fileHandle.seekToEnd()
}else {
}
fileHandle.write(data)
lock.unlock()
}
}
}
使用方法:
MTLogHelper.MTLog("xxxxxx")
需要查看日志的时候可以设置
MTLogHelper.outModel = .file
可以选择日志是单独显示在console.log 内, 或直接打印在控制台。 需要打印一份完整日志时,可以设为.redirect 得到一份完整的日志
如果使用的模块比较多所以我们可以在MTLog基础上封装了一些枚举。在我需要的时候可以针对不同模块过滤导出日志。
当日志导入文件时会在控制台内打印保存路径!
(未允许不可转载)