iOS开发——自主设计日志系统

好像很久没有写有关iOS的文章了,其实iOS的开发一直都是在进行的,但是最近有需求拓宽知识的宽度,所以一直在接触别的知识,当然啦,移动端开发并不能丢下。

我平时开发的项目监测bug和崩溃的模块都是集成了鹅厂的Bugly系统,毕竟是谁用谁说好的第三方系统。而Bugly主要还是返回的还是崩溃之后的日志,所以如果想在平时的运行中,就能拿到客户手机中的日志怎么办呢。在这个需求的驱使下,便开始着手设计一个日志系统。

需求还是不难的,记录手机操作的内容,如

时间|日志级别|类名_函数名_行数|分类|Log内容

这样的一种日志形式。

因为不希望频繁的读写,所以希望每十条Log生成之后,读写一次。而未写入硬盘的Log保存在内存中。按照天数,每天都有一份日志,并且在客户的手机异常之后,可以将所有日志压缩上传到服务器。需求介绍完了,并不难对不对。

在Log的生成方面,我的设计是枚举出日志的级别,之后利用Swift的 #function#line等定义,方便的获取函数名和行数,类名我是利用一个对于NSObjectextension来完成的,类似这样:


extension NSObject {
    var className: String {
        return String(describing: type(of: self)).components(separatedBy: ".").last!
    }

    class var className: String {
        return String(describing: self).components(separatedBy: ".").last!
    }
}

开箱可用,准确获取类名。

生成log的核心函数例如如下这样:

public func createLog(level: DebugLevel, targetClass: AnyClass, type: OperateType, content: String,  _ line: Int = #line, _ function: String = #function)
-> String {
    let lineStr = String.init(format: "line:%d", line)
    let levelStr = levelToString(level: level)
    let separator = "|"
    let classSeparator = "_"
    let log: String = Date().toString() + separator + levelStr + separator + targetClass.className + classSeparator + function + classSeparator + lineStr + separator + content + "\n"
    print(log)
    return log
}

而基于这个函数做一些封装,就能封装出很简便的打印各级别日志的API了。

至此,介绍完Log的生成类: LogGenerator

之后是对日志的读写,需要有一个文件读写的类,暂定名为LogStorage

因为文件的读写都是常规的操作,所以代码就不贴出来了。我在这里只是贴出我在LogStorage类里暴露的接口方法


public protocol LogStorageProtocol {

    /// 获取日志缓存地址
    ///
    /// - Returns: String
    func getCachePath() -> String

    /// 删除文件
    ///
    /// - Parameter fileName: String
    /// - Returns: Bool
    func deleteFile(fileName: String) -> Bool

    /// 清除全部日志缓存
    ///
    /// - Returns: Bool
    func cleanCache() -> Bool

    /// 读取日志文件
    ///
    /// - Parameter fileName: String
    /// - Returns: Data
    func readFile(fileName: String) -> Data?

    /// 更新写入Log数据
    ///
    /// - Parameters:
    ///   - fileName: String
    ///   - data: Data
    /// - Returns: Data
    func updateFile(fileName: String, data: Data) -> Bool

    /// 自动根据天数创建文件名
    ///
    /// - Returns: String
    func createFileName() -> String
}

而这个十条一写,没有达到标准的就暂时保存在内存里,我的想法是创建一个循环队列,根据FIFO原则,当满足十条Log时,做一次写入操作,而循环队列在空间上是非常节省资源的,如果没有满足十条日志,那就都暂存在队列里,整个开销就是循环队列的一个数组,容量是11个元素,还有一个充当哨兵。

循环队列的数据结构是队列的数据结构里最基础的

protocol QueueProtocol {
    func createQueue()
    func traverseQueue()
    func isFullQueue() -> Bool
    func isEmptyQueue() -> Bool
    func Enqueue(log: String) -> Bool
    func Dequeue() -> Bool
}

在内部增加了一个遍历队列写入日志的函数

private func updateFileWhenTranverse() {
    var i = queue.front
    while (i != queue.rear) {
        let fileName = LogStorage.share.createFileName()
        let data = queue.logData[i].data(using: .utf8)
        if (LogStorage.share.updateFile(fileName: fileName, data: data!)) {
            let _ = Dequeue()
        }
        i += 1
        i = i % queue.maxsize
    }
}

而最后一个需求就是压缩上传了,在这里使用了SSZipArchive这个第三方库来压缩文件成zip格式。封装成LogArchive类。是不是三言两语间,整个日志系统就设计完成了,但是我是用Swift来写的,若是Objective-C调用怎么办呢。答案当然是用Objc强大的宏定义来搞定咯,几个宏定义,轻松的一行代码就调用了Log输出。

#define Cute_Debug(log) [[LogGenerator new] debugWithTargetClass:self.classForCoder content:[NSString stringWithFormat:@"%@", log] :(NSInteger)__LINE__ :[NSString stringWithFormat:@"%s", __FUNCTION__]];

#define Cute_Warning(log) [[LogGenerator new] warningWithTargetClass:self.classForCoder content:[NSString stringWithFormat:@"%@", log] :(NSInteger)__LINE__ :[NSString stringWithFormat:@"%s", __FUNCTION__]];

#define Cute_Info(log) [[LogGenerator new] infoWithTargetClass:self.classForCoder content:[NSString stringWithFormat:@"%@", log] :(NSInteger)__LINE__ :[NSString stringWithFormat:@"%s", __FUNCTION__]];

#define Cute_Error(log) [[LogGenerator new] errorWithTargetClass:self.classForCoder content:[NSString stringWithFormat:@"%@", log] :(NSInteger)__LINE__ :[NSString stringWithFormat:@"%s", __FUNCTION__]];

整个日志系统,我已经开源放在了我的github上,具体的代码可以去github上看。
欢迎提issue,如果有用,请点个star谢谢。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352

推荐阅读更多精彩内容