日志收集(通过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 

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 
#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)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

你可能感兴趣的:(日志收集(通过cocoalumberjack实现))