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