級(jí)別: ★☆☆☆☆
標(biāo)簽:「iOS」「Log」「CocoaLumberjack」
作者: dac_1033
審校: QiShare團(tuán)隊(duì)
在開發(fā)過(guò)程中打印日志功能是必不可少的,日志的處理主要分為以下幾種:
- Debug/Release模式下日志的處理狰闪;
- 將日志記錄在本地文件跋选,并上傳服務(wù)器杈绸;
- 由業(yè)務(wù)App控制是否開啟日志站削。
1. Debug/Release模式下日志的處理
第一點(diǎn)在開發(fā)業(yè)務(wù)App時(shí)最常使用勋乾,一行語(yǔ)句就搞定:
#ifdef DEBUG
#define DLog(fmt, ...) {NSLog((@"%s [Line %d]\n " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);}
#else
#define DLog(...)
#endif
如果圖方便蛛淋,可以將以上代碼寫到prefix.pch文件中,在需要輸出log的地方調(diào)用DLog(...)造挽,即可在Debug/Release模式切換時(shí)碱璃,自動(dòng)開啟/關(guān)閉打印log。
2. 將日志記錄在本地文件
將日志記錄在本地文件常用三方庫(kù)CocoaLumberjack來(lái)處理饭入,我們通過(guò)這個(gè)庫(kù)可以將日志輸出至控制臺(tái)嵌器,也可以寫在本地文件中,我們還可以設(shè)置輸出日志等級(jí)谐丢。具體CocoaLumberjack的使用方式可以參考iOS開發(fā)之日志框架CocoaLumberjack的配置與使用詳解
3. 兼容CocoaLumberjack的同時(shí)爽航,控制日志的開關(guān)
這個(gè)場(chǎng)景經(jīng)常出現(xiàn)在framework開發(fā)過(guò)程中,我們開發(fā)一個(gè)framework乾忱,其中需要自己輸出日志到本地文件岳掐,另外宿主App聯(lián)調(diào)時(shí),也常常需要主動(dòng)控制log的開和關(guān)饭耳。我們定義了一個(gè)LogManager類,LogManager.h代碼如下:
@import Foundation;
//#define LUMBERJACK @"LUMBERJACK"
#ifdef LUMBERJACK
#define LOG_LEVEL_DEF ddLogLevelf
#import <CocoaLumberjack/CocoaLumberjack.h>
#else /* LUMBERJACK */
typedef NS_OPTIONS(NSUInteger, DDLogFlag){
// 0...00001 DDLogFlagError
DDLogFlagError = (1 << 0),
// 0...00010 DDLogFlagWarning
DDLogFlagWarning = (1 << 1),
// 0...00100 DDLogFlagInfo
DDLogFlagInfo = (1 << 2),
// 0...01000 DDLogFlagDebug
DDLogFlagDebug = (1 << 3),
// 0...10000 DDLogFlagVerbose
DDLogFlagVerbose = (1 << 4)
};
typedef NS_ENUM(NSUInteger, DDLogLevel){
DDLogLevelOff = 0,
// Error logs only
DDLogLevelError = (DDLogFlagError),
// Error and warning logs
DDLogLevelWarning = (DDLogLevelError | DDLogFlagWarning),
// Error, warning and info logs
DDLogLevelInfo = (DDLogLevelWarning | DDLogFlagInfo),
// Error, warning, info and debug logs
DDLogLevelDebug = (DDLogLevelInfo | DDLogFlagDebug),
// Error, warning, info, debug and verbose logs
DDLogLevelVerbose = (DDLogLevelDebug | DDLogFlagVerbose),
// All logs (1...11111)
DDLogLevelAll = NSUIntegerMax
};
#define CustomLog(format,...) [MQTTLog customLogWithFormatString:[NSString stringWithFormat:format, ##__VA_ARGS__]]
#define DDLogVerbose if (ddLogLevel & DDLogFlagVerbose) CustomLog
#define DDLogDebug if (ddLogLevel & DDLogFlagDebug) CustomLog
#define DDLogWarn if (ddLogLevel & DDLogFlagWarning) CustomLog
#define DDLogInfo if (ddLogLevel & DDLogFlagInfo) CustomLog
#define DDLogError if (ddLogLevel & DDLogFlagError) CustomLog
#endif /* LUMBERJACK */
extern DDLogLevel ddLogLevel;
extern BOOL logEnable;
/** MQTTLog lets you define the log level for MQTTClient
* independently of using CocoaLumberjack
*/
@interface MQTTLog: NSObject
// default one is DDLogLevelVerbose
+ (void)setLogLevel:(DDLogLevel)logLevel;
+ (void)setLogEnable:(BOOL)logEnable;
+ (void)customLogWithFormatString:(NSString *)formatString;
@end
LogManager.m代碼如下:
#import "MQTTLog.h"
#ifdef LUMBERJACK
// 自定義日志文件里 log的格式
@interface DDLogFileFormatter : NSObject <DDLogFormatter>
{
NSDateFormatter *dateFormatter;
}
- (id)init;
- (instancetype)initWithDateFormatter:(NSDateFormatter *)dateFormatter;
@end
@implementation DDLogFileFormatter
- (id)init {
return [self initWithDateFormatter:nil];
}
- (instancetype)initWithDateFormatter:(NSDateFormatter *)aDateFormatter {
if ((self = [super init])) {
if (aDateFormatter) {
dateFormatter = aDateFormatter;
} else {
dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; // 10.4+ style
[dateFormatter setDateFormat:@"yyyyMMdd-HHmmss.SSS"];
}
}
return self;
}
- (NSString *)formatLogMessage:(DDLogMessage *)logMessage {
NSString *dateAndTime = [dateFormatter stringFromDate:(logMessage.timestamp)];
NSString* level;
switch(logMessage.flag) {
case DDLogFlagError:
level=@"E";
break;
case DDLogFlagWarning:
level=@"W";
break;
case DDLogFlagInfo:
level=@"I";
break;
case DDLogFlagDebug:
level=@"D";
break;
case DDLogFlagVerbose:
level=@"V";
break;
default:
level=@"U";
break;
}
NSString *formatStr = [NSString stringWithFormat:@"%@ %@ %d.%@[%@:%ld:%@] %@", level, dateAndTime, getpid(),logMessage.threadID, logMessage.fileName, (unsigned long)logMessage.line, logMessage.function, logMessage.message];
return formatStr;
}
@end
#endif
BOOL mqttLogEnable = NO;
@implementation MQTTLog
DDLogLevel ddLogLevel = DDLogLevelVerbose;
+ (void)setLogLevel:(DDLogLevel)logLevel {
ddLogLevel = logLevel;
}
+ (void)setLogEnable:(BOOL)logEnable {
mqttLogEnable = logEnable;
if (logEnable) {
[MQTTLog startDDLogger];
}
}
+ (void)startDDLogger {
#ifdef LUMBERJACK
#ifdef DEBUG
//[DDLog addLogger:[DDTTYLogger sharedInstance]]; // TTY = Xcode console
[[DDTTYLogger sharedInstance] setColorsEnabled:YES];
[DDLog addLogger:[DDOSLogger sharedInstance]]; // ASL = Apple System Logs
#endif
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; // 10.4+ style
[dateFormatter setDateFormat:@"yyyyMMdd-HHmmss.SSS"];
NSArray *path = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *folderPath = [NSString stringWithFormat:@"%@/QiTestSDK/QiTestSDKLogs", path[0]];
if (![[NSFileManager defaultManager] fileExistsAtPath:folderPath]) {
[[NSFileManager defaultManager] createDirectoryAtPath:folderPath withIntermediateDirectories:YES attributes:nil error:nil];
}
DDLogFileManagerDefault *fileManager = [[DDLogFileManagerDefault alloc] initWithLogsDirectory:folderPath];
DDFileLogger *fileLogger = [[DDFileLogger alloc] initWithLogFileManager:fileManager];
fileLogger.rollingFrequency = 60 * 60 * 24 * 3; // 3 days rolling
fileLogger.logFileManager.maximumNumberOfLogFiles = 5;
fileLogger.logFileManager.logFilesDiskQuota = 50 * 1024 * 1024; // 50M
fileLogger.maximumFileSize = 10 * 1024 * 1024;
fileLogger.logFormatter = [[DDLogFileFormatter alloc] init];
[DDLog addLogger:fileLogger];
#endif
}
+ (void)customLogWithFormatString:(NSString *)formatString {
if (mqttLogEnable) {// 開啟了Log
NSLog(@"%@", formatString);
}
}
@end
這樣通過(guò)宏定義执解,既能兼容CocoaLumberjack寞肖,也能實(shí)現(xiàn)log的開關(guān)。如果想美觀一點(diǎn)實(shí)現(xiàn)CocoaLumberjack的“掛載”衰腌,請(qǐng)參考iOS App中實(shí)現(xiàn)可拆卸一個(gè)framework的兩種方式新蟆。
推薦文章:
iOS App中可拆卸一個(gè)framework的兩種方式
自定義WKWebView顯示內(nèi)容(一)
Swift 5.1 (6) - 函數(shù)
Swift 5.1 (5) - 控制流
Xcode11 新建工程中的SceneDelegate
iOS App啟動(dòng)優(yōu)化(二)—— 使用“Time Profiler”工具監(jiān)控App的啟動(dòng)耗時(shí)
iOS App啟動(dòng)優(yōu)化(一)—— 了解App的啟動(dòng)流程
iOS WKWebView的基本使用
Swift 5.1 (4) - 集合類型