日志收集(通過cocoalumberjack實(shí)現(xiàn))

一.自定義log語句

因?yàn)槲易隽薋atal,Error,Warn,Info,Debug五個(gè)等級(jí),所以要自己定制一下,至于DDLogFatal(frmt, ...) 對(duì)應(yīng)LOG_FLAG_ERROR,是因?yàn)樵贒DLog新的版本里都換成這種枚舉了,不是原來的那種Define的,我就直接把默認(rèn)的五個(gè)等級(jí)對(duì)應(yīng)到了我自定義的等級(jí),這個(gè)在formatLogMessage中也要記得對(duì)應(yīng)。

//新版本的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 {
    //新建一個(gè)文件夾去保存
    _filePathPrefix = filePathPrefix;//路徑前綴
    _folderName = folderName;//文件夾名
    _logName = logName;//log文件名
    _logFlag = flag;//這個(gè)就是上下文,為了分文件輸出
    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 {
    
    //獲取當(dāng)前線程的字典
    NSMutableDictionary *dictionary = [[NSThread currentThread]
                                       threadDictionary];
    //設(shè)置日期格式
    NSString *dateFormat = @"yyyy'-'MM'-'dd'";
    NSString *key = [NSString stringWithFormat:@"logFileDateFormatter.%@", dateFormat];
    NSDateFormatter *dateFormatter = dictionary[key];
    
    if (dateFormatter == nil) {
        //設(shè)置日期格式
        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
{  //這個(gè)方法必須重寫,很重要
    BOOL hasProperSuffix = [fileName hasSuffix:@".log"];
    BOOL isCurrentFile = NO;
    //isCurrentFile這個(gè)判斷必須有,比如你想在一個(gè)文件夾里建第二個(gè)log文件,如果只判斷是不是.log結(jié)尾,那么會(huì)復(fù)用你建的第一個(gè)文件
    if (hasProperSuffix)
    {
        NSString *currentFileName = [[fileName componentsSeparatedByString:@"_"] firstObject];
        if ([self.fileName isEqualToString:currentFileName]) {
            isCurrentFile = YES;
        }
    }
    return (hasProperSuffix && isCurrentFile);
}

三.利用加白名單實(shí)現(xiàn)分文件輸出

//  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]) {
        //利用這個(gè)判斷context是否在白名單里,實(shí)現(xiàn)分文件輸出
        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;
    }
}

四.抽出來一個(gè)方法

- (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到大小限制,會(huì)新開一個(gè)log文件,每個(gè)fileLogger最多2個(gè)文件,再超過大小會(huì)頂?shù)襞f的那個(gè),新建
    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];
用的時(shí)候在m文件里寫下面這句就可以
static const DDLogContext logContext = DDLogContextOne;

參考鏈接:
DDLog 使用小記
CocoaLumberjack使用*
基于第三方CocoaLumberjack(DDLog)做保存不同分類的日志:
CocoaLumberjack自定義日志級(jí)
關(guān)于CocoaLumberjack
CocoaLumberjack:簡單好用的Log庫
CocoaLumberjack的github地址
DDLog源碼解析一:框架結(jié)構(gòu)
DDLog源碼解析二:設(shè)計(jì)初衷
DDLog源碼解析三:FileLogger
淺談iOS日志收集系統(tǒng):(也有一些DDLog的使用)
一個(gè)關(guān)于日志系統(tǒng)的思路
iOS平臺(tái)常見日志庫簡介
https://cocoalumberjack.github.io

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容