iOS 控制日志的開關(guān)

級別: ★☆☆☆☆
標(biāo)簽:「iOS」「Log」「CocoaLumberjack」
作者: dac_1033
審校: QiShare團(tuán)隊


在開發(fā)過程中打印日志功能是必不可少的,日志的處理主要分為以下幾種:

  • Debug/Release模式下日志的處理;
  • 將日志記錄在本地文件,并上傳服務(wù)器;
  • 由業(yè)務(wù)App控制是否開啟日志。
1. Debug/Release模式下日志的處理

第一點(diǎn)在開發(fā)業(yè)務(wù)App時最常使用,一行語句就搞定:

#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模式切換時,自動開啟/關(guān)閉打印log。

2. 將日志記錄在本地文件

將日志記錄在本地文件常用三方庫CocoaLumberjack來處理,我們通過這個庫可以將日志輸出至控制臺,也可以寫在本地文件中,我們還可以設(shè)置輸出日志等級。具體CocoaLumberjack的使用方式可以參考iOS開發(fā)之日志框架CocoaLumberjack的配置與使用詳解

3. 兼容CocoaLumberjack的同時,控制日志的開關(guān)

這個場景經(jīng)常出現(xiàn)在framework開發(fā)過程中,我們開發(fā)一個framework,其中需要自己輸出日志到本地文件,另外宿主App聯(lián)調(diào)時,也常常需要主動控制log的開和關(guān)。我們定義了一個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

這樣通過宏定義,既能兼容CocoaLumberjack,也能實現(xiàn)log的開關(guān)。如果想美觀一點(diǎn)實現(xiàn)CocoaLumberjack的“掛載”,請參考iOS App中實現(xiàn)可拆卸一個framework的兩種方式。


推薦文章:
iOS App中可拆卸一個framework的兩種方式
自定義WKWebView顯示內(nèi)容(一)
Swift 5.1 (6) - 函數(shù)
Swift 5.1 (5) - 控制流
Xcode11 新建工程中的SceneDelegate
iOS App啟動優(yōu)化(二)—— 使用“Time Profiler”工具監(jiān)控App的啟動耗時
iOS App啟動優(yōu)化(一)—— 了解App的啟動流程
iOS WKWebView的基本使用
Swift 5.1 (4) - 集合類型

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

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

  • 第二次的7天高效學(xué)習(xí)又來了,因為這期是情緒課題,最近工作壓力大,馬上報了名,后來emma和芽芽都問我要不要繼續(xù)當(dāng)教...
    梁突突閱讀 91評論 0 0
  • 唉,其實作為散戶,基本的判斷力還是該有的,總是聽風(fēng)就是雨,容易成為意見領(lǐng)袖們的手中玩物,是**、韭菜、散戶、羊毛黨...
    小事_f0ab閱讀 153評論 0 0
  • 夏天的椰樹啊 在地面的水溝里 裝修工人纏繞住利益的捆綁 ?彩燈和白熾燈四方地 只是少了一片海灘,驕陽的廣闊 她只看...
    喵咪薄荷糖喵閱讀 129評論 0 1
  • 現(xiàn)在獲取知識的渠道比以前多了很多,當(dāng)然學(xué)習(xí)對于大多數(shù)人是非常渴望的,我有時也在感嘆我的學(xué)習(xí)效率不高,今天的晨讀文章...
    莉萍LP閱讀 223評論 2 1

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