日志收集(通过cocoalumberjack实现)

一.自定义log语句

因为我做了Fatal,Error,Warn,Info,Debug五个等级,所以要自己定制一下,至于DDLogFatal(frmt, ...) 对应LOG_FLAG_ERROR,是因为在DDLog新的版本里都换成这种枚举了,不是原来的那种Define的,我就直接把默认的五个等级对应到了我自定义的等级,这个在formatLogMessage中也要记得对应。

//新版本的DDLog
typedef NS_OPTIONS(NSUInteger, DDLogFlag){

    DDLogFlagError      = (1 << 0),

    DDLogFlagWarning    = (1 << 1),    
  
    DDLogFlagInfo       = (1 << 2),
  
    DDLogFlagDebug      = (1 << 3),
    
    DDLogFlagVerbose    = (1 << 4)
};

#import <CocoaLumberjack/CocoaLumberjack.h>

static const DDLogLevel ddLogLevel = DDLogLevelVerbose;

#undef DDLogError
#undef DDLogWarn
#undef DDLogInfo
#undef DDLogDebug
#undef DDLogVerbose

#define LOG_FLAG_ERROR    DDLogFlagError
#define LOG_FLAG_WARN     DDLogFlagWarning
#define LOG_FLAG_INFO     DDLogFlagInfo
#define LOG_FLAG_DEBUG    DDLogFlagDebug
#define LOG_FLAG_VERBOSE  DDLogFlagVerbose

#define DDLogFatal(frmt, ...)   LOG_MAYBE(NO,  ddLogLevel, LOG_FLAG_ERROR,  logContext, nil, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)
#define DDLogError(frmt, ...)   LOG_MAYBE(NO,  ddLogLevel, LOG_FLAG_WARN, logContext, nil, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)
#define DDLogWarn(frmt, ...)    LOG_MAYBE(YES, ddLogLevel, LOG_FLAG_INFO,   logContext, nil, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)
#define DDLogInfo(frmt, ...)    LOG_MAYBE(YES, ddLogLevel, LOG_FLAG_DEBUG,   logContext, nil, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)
#define DDLogDebug(frmt, ...)   LOG_MAYBE(YES, ddLogLevel,  LOG_FLAG_VERBOSE, logContext, nil, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)

二.自定义fileLogger

//  MyFileLogger.m
#import "MyFileLogger.h"

@implementation MyFileLogger

- (instancetype)initWithFilePathPrefix:(NSString *)filePathPrefix
                        FileFolderName:(NSString *)folderName
                              fileName:(NSString *)logName
                              withFlag:(NSUInteger)flag {
    //新建一个文件夹去保存
    _filePathPrefix = filePathPrefix;//路径前缀
    _folderName = folderName;//文件夹名
    _logName = logName;//log文件名
    _logFlag = flag;//这个就是上下文,为了分文件输出
    NSString *logsDirectory = [filePathPrefix stringByAppendingPathComponent:folderName];
    MyFileManagerDefault *defaultLogFileManager = [[MyFileManagerDefault alloc] initWithLogsDirectory:logsDirectory fileName:logName];
    return [self initWithLogFileManager:defaultLogFileManager];
}

@end

@interface MyFileManagerDefault()
@property (nonatomic, strong) NSString *fileName;
@end

@implementation MyFileManagerDefault

- (instancetype)initWithLogsDirectory:(NSString *)logsDirectory
                             fileName:(NSString *)name{
    //logsDirectory日志自定义路径
    self = [super initWithLogsDirectory:logsDirectory];
    if (self) {
        self.fileName = name;
    }
    return self;
}

#pragma mark - Override methods

- (NSString *)newLogFileName {
    //重写文件名称
    NSDateFormatter *dateFormatter = [self logFileDateFormatter];
    NSString *formattedDate = [dateFormatter stringFromDate:[NSDate date]];
    return [NSString stringWithFormat:@"%@_%@.log", self.fileName, formattedDate];
}

- (NSDateFormatter *)logFileDateFormatter {
    
    //获取当前线程的字典
    NSMutableDictionary *dictionary = [[NSThread currentThread]
                                       threadDictionary];
    //设置日期格式
    NSString *dateFormat = @"yyyy'-'MM'-'dd'";
    NSString *key = [NSString stringWithFormat:@"logFileDateFormatter.%@", dateFormat];
    NSDateFormatter *dateFormatter = dictionary[key];
    
    if (dateFormatter == nil) {
        //设置日期格式
        dateFormatter = [[NSDateFormatter alloc] init];
        [dateFormatter setLocale:[NSLocale localeWithLocaleIdentifier:@"zh_CN"]];//en_US zh_CN
        [dateFormatter setDateFormat:dateFormat];
        [dateFormatter setTimeZone:[NSTimeZone localTimeZone]];
        dictionary[key] = dateFormatter;
    }
    
    return dateFormatter;
}

- (BOOL)isLogFile:(NSString *)fileName
{  //这个方法必须重写,很重要
    BOOL hasProperSuffix = [fileName hasSuffix:@".log"];
    BOOL isCurrentFile = NO;
    //isCurrentFile这个判断必须有,比如你想在一个文件夹里建第二个log文件,如果只判断是不是.log结尾,那么会复用你建的第一个文件
    if (hasProperSuffix)
    {
        NSString *currentFileName = [[fileName componentsSeparatedByString:@"_"] firstObject];
        if ([self.fileName isEqualToString:currentFileName]) {
            isCurrentFile = YES;
        }
    }
    return (hasProperSuffix && isCurrentFile);
}

三.利用加白名单实现分文件输出

//  MyContextWhitelistFilterLogFormatter.h
#import <Cocoa/Cocoa.h>
#import "MyLog.h"

@interface MyContextWhitelistFilterLogFormatter : DDContextWhitelistFilterLogFormatter {
    NSDateFormatter *threadUnsafeDateFormatter;
}
@end
//  MyContextWhitelistFilterLogFormatter.m

#import "MyContextWhitelistFilterLogFormatter.h"

@implementation MyContextWhitelistFilterLogFormatter

- (id)init {
    if((self = [super init])) {
        threadUnsafeDateFormatter = [[NSDateFormatter alloc] init];
        [threadUnsafeDateFormatter setDateFormat:@"yyyy/MM/dd HH:mm:ss:SSS"];
    }
    return self;
}

- (NSString *)formatLogMessage:(DDLogMessage *)logMessage {
    if ([self isOnWhitelist:logMessage->_context]) {
        //利用这个判断context是否在白名单里,实现分文件输出
        NSString *logLevel = @"";
        switch (logMessage.flag) {
            case DDLogFlagError:
                logLevel = @"FATAL";
                break;
                
            case DDLogFlagWarning:
                logLevel = @"ERROR";
                break;
                
            case DDLogFlagInfo:
                logLevel = @"WARN";
                break;
                
            case DDLogFlagDebug:
                logLevel = @"INFO";
                break;
                
            default:
                logLevel = @"DEBUG";
                break;
        }
        
        NSString *dateAndTime = [threadUnsafeDateFormatter stringFromDate:(logMessage.timestamp)];
        dateAndTime = [dateAndTime stringByReplacingOccurrencesOfString:@"/" withString:@"-"];
        dateAndTime = [dateAndTime substringToIndex:dateAndTime.length - 4];
        
        return [NSString stringWithFormat:@"Time:%@\tLogInfo:[%@] %@\r\n", dateAndTime,  logMsg];
    } else {
        return nil;
    }
}

四.抽出来一个方法

- (id<DDLogger>)createFilePathPrefix:(NSString *)filePathPrefix
                          FileLogger:(NSString *)folderName
                         logName:(NSString *)logName
                        withFlag:(NSInteger)flag {
    DDContextWhitelistFilterLogFormatter *fileLogFormatter = [[DDContextWhitelistFilterLogFormatter alloc] init];
    [fileLogFormatter addToWhitelist:flag];
    
    _fileLogger = [[DDFileLogger alloc] initWithFilePathPrefix:filePathPrefix FileFolderName:folderName fileName:logName withFlag:flag];
    [_fileLogger setLogFormatter:fileLogFormatter];
    _fileLogger.maximumFileSize = 10 * 1024 * 1024;//禁用 10MB 10 * 1024 * 1024 
    _fileLogger.rollingFrequency = 0; //0 禁用
    _fileLogger.logFileManager.maximumNumberOfLogFiles = 2;//禁用
    //我只做了10MB到大小限制,会新开一个log文件,每个fileLogger最多2个文件,再超过大小会顶掉旧的那个,新建
    return _fileLogger;
    
}

使用

typedef NS_ENUM(NSUInteger, DDLogContext){
    DDLogContextOne = 100,
    DDLogContextTwo,
};
DDFileLogger *OneFileLogger = [[DDLoggerAssembler shareInstance] createFilePathPrefix:@""FileLogger:@"文件夹名"logName:@"One" withFlag:DDLogContextOne];
[DDLog addLogger:OneFileLogger withLevel:ddLogLevel];
用的时候在m文件里写下面这句就可以
static const DDLogContext logContext = DDLogContextOne;

参考链接:
DDLog 使用小记
CocoaLumberjack使用*
基于第三方CocoaLumberjack(DDLog)做保存不同分类的日志:
CocoaLumberjack自定义日志级
关于CocoaLumberjack
CocoaLumberjack:简单好用的Log库
CocoaLumberjack的github地址
DDLog源码解析一:框架结构
DDLog源码解析二:设计初衷
DDLog源码解析三:FileLogger
浅谈iOS日志收集系统:(也有一些DDLog的使用)
一个关于日志系统的思路
iOS平台常见日志库简介
https://cocoalumberjack.github.io

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

推荐阅读更多精彩内容