iOS 控制日誌的開關

級別: ★☆☆☆☆
標籤:「iOS」「Log」「CocoaLumberjack」
做者: dac_1033
審校: QiShare團隊php


在開發過程當中打印日誌功能是必不可少的,日誌的處理主要分爲如下幾種:git

  • Debug/Release模式下日誌的處理;
  • 將日誌記錄在本地文件,並上傳服務器;
  • 由業務App控制是否開啓日誌。
1. Debug/Release模式下日誌的處理

第一點在開發業務App時最常使用,一行語句就搞定:github

#ifdef DEBUG
    #define DLog(fmt, ...) {NSLog((@"%s [Line %d]\n " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);}
#else
    #define DLog(...)
#endif
複製代碼

若是圖方便,能夠將以上代碼寫到prefix.pch文件中,在須要輸出log的地方調用DLog(...),便可在Debug/Release模式切換時,自動開啓/關閉打印log。objective-c

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

將日誌記錄在本地文件經常使用三方庫CocoaLumberjack來處理,咱們經過這個庫能夠將日誌輸出至控制檯,也能夠寫在本地文件中,咱們還能夠設置輸出日誌等級。具體CocoaLumberjack的使用方式能夠參考iOS開發之日誌框架CocoaLumberjack的配置與使用詳解服務器

3. 兼容CocoaLumberjack的同時,控制日誌的開關

這個場景常常出如今framework開發過程當中,咱們開發一個framework,其中須要本身輸出日誌到本地文件,另外宿主App聯調時,也經常須要主動控制log的開和關。咱們定義了一個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,也能實現log的開關。若是想美觀一點實現CocoaLumberjack的「掛載」,請參考iOS App中實現可拆卸一個framework的兩種方式函數


小編微信:可加並拉入《QiShare技術交流羣》。工具

關注咱們的途徑有:
QiShare(簡書)
QiShare(掘金)
QiShare(知乎)
QiShare(GitHub)
QiShare(CocoaChina)
QiShare(StackOverflow)
QiShare(微信公衆號)優化

推薦文章:
iOS App中可拆卸一個framework的兩種方式
自定義WKWebView顯示內容(一)
Swift 5.1 (6) - 函數 Swift 5.1 (5) - 控制流
Xcode11 新建工程中的SceneDelegate
iOS App啓動優化(二)—— 使用「Time Profiler」工具監控App的啓動耗時
iOS App啓動優化(一)—— 瞭解App的啓動流程
iOS WKWebView的基本使用
Swift 5.1 (4) - 集合類型
奇舞週刊

相關文章
相關標籤/搜索