一.自定義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