Why NSLogger ?
NSLogger是一個便捷好用的第三方日志庫,Github官方鏈接:https://github.com/fpillet/NSLogger
來自官方的介紹:
NSLogger is a high performance logging utility which displays traces emitted by client applications running on macOS, iOS and Android. It replaces traditional console logging traces (NSLog(), Java Log).
The NSLogger Viewer runs on macOS and replaces Xcode, Android Studio or Eclipse consoles. It provides powerful additions like display filtering, defining log domain and level, image and binary logging, message coloring, traces buffering, timing information, link with source code, etc.
個人認為其比起iOS自帶的NSLog直接好處為:
- 不需要有線連接,基于Bonjour service服務發現協議在局域網內自動捕捉客戶端發送的log信息(也能配置在廣域網接受遠程internet客戶端的日志輸出)
- 有自己獨立的桌面軟件查看日志,故而支持給log加tag,過濾等高階日志查看操作,甚至支持輸出圖片作為日志;
- 解決了NSLog終端日志輸出不完整問題(NSLog輸出超長文本等經常會有長度限制)
- 安裝使用方便,提供現成的宏替換(重定向)NSLog的日志輸出到NSLogger
//提供的NSLogger.h頭文件已經預定義了很多現有的宏
//可根據實際需求更改定義自己的宏來使用
#ifdef DEBUG
#define NSLog(...) LogMessageF(__FILE__, __LINE__, __FUNCTION__, @"NSLog", 0, __VA_ARGS__)
#define LoggerError(level, ...) LogMessageF(__FILE__, __LINE__, __FUNCTION__, @"Error", level, __VA_ARGS__)
#define LoggerApp(level, ...) LogMessageF(__FILE__, __LINE__, __FUNCTION__, @"App", level, __VA_ARGS__)
#define LoggerView(level, ...) LogMessageF(__FILE__, __LINE__, __FUNCTION__, @"View", level, __VA_ARGS__)
#define LoggerService(level, ...) LogMessageF(__FILE__, __LINE__, __FUNCTION__, @"Service", level, __VA_ARGS__)
#define LoggerModel(level, ...) LogMessageF(__FILE__, __LINE__, __FUNCTION__, @"Model", level, __VA_ARGS__)
#define LoggerData(level, ...) LogMessageF(__FILE__, __LINE__, __FUNCTION__, @"Data", level, __VA_ARGS__)
#define LoggerNetwork(level, ...) LogMessageF(__FILE__, __LINE__, __FUNCTION__, @"Network", level, __VA_ARGS__)
#define LoggerLocation(level, ...) LogMessageF(__FILE__, __LINE__, __FUNCTION__, @"Location", level, __VA_ARGS__)
#define LoggerPush(level, ...) LogMessageF(__FILE__, __LINE__, __FUNCTION__, @"Push", level, __VA_ARGS__)
#define LoggerFile(level, ...) LogMessageF(__FILE__, __LINE__, __FUNCTION__, @"File", level, __VA_ARGS__)
#define LoggerSharing(level, ...) LogMessageF(__FILE__, __LINE__, __FUNCTION__, @"Sharing", level, __VA_ARGS__)
#define LoggerAd(level, ...) LogMessageF(__FILE__, __LINE__, __FUNCTION__, @"Ad and Stat", level, __VA_ARGS__)
#else
#define NSLog(...) LogMessageCompat(__VA_ARGS__)
#define LoggerError(...) while(0) {}
#define LoggerApp(level, ...) while(0) {}
#define LoggerView(...) while(0) {}
#define LoggerService(...) while(0) {}
#define LoggerModel(...) while(0) {}
#define LoggerData(...) while(0) {}
#define LoggerNetwork(...) while(0) {}
#define LoggerLocation(...) while(0) {}
#define LoggerPush(...) while(0) {}
#define LoggerFile(...) while(0) {}
#define LoggerSharing(...) while(0) {}
#define LoggerAd(...) while(0) {}
#endif
安裝使用基于Github官方的文檔走就行,CocoaPods安裝依賴庫,然后Mac安裝一個日志查看桌面軟件即可。
存在的問題
由于該日志輸出是基于Bonjour service這個服務發現協議來尋找日志的接收端(即發出日志的應用為client,接收查看日志的桌面Viewer軟件為Server),默認情況下App輸出日志時,會作為client會在局域網內自動搜索日志接收server,找到的第一個server則建立日志輸出連接,日志查看軟件Viewer會自動打開一個新窗口顯示日志。
但是當公司的局域網內有多個日志輸出客戶端(多個App使用該日志庫)和日志接收查看Viewer Server(多個測試人員開著日志查看Viewer看log),日志輸出連接會錯亂,A輸出的日志可能會連接顯示到B的日志查看Viewer軟件上。
問題解決
官方目前新版本也已經給使用CocoaPods安裝庫的童鞋們內置了一個方案:Using NSLogger on a Shared Network
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
//在應用啟動時調用其定義的宏
LoggerSetupBonjourForBuildUser();
return YES;
}
LoggerSetupBonjourForBuildUser();
為展示該宏具體實現,下面手動做一個配置,明白其配置原理便于做出更高階更適合自身使用場景的配置:
Step 1: 添加Run Pre-action Scheme
配置Xcode運行Run命令的前置腳本,使得每次運行Run命令自動打開NSlogger Viewer日志查看軟件。
Step 2 : 修改Build Setting添加PREPROCESSOR MACROS
類似經常使用的DEBUG宏,這里加一個自定義的LOGGER_TARGET宏
LOGGER_TARGET=@\"$(USER)\"
即定義LOGGER_TARGET為當前系統登錄用戶的用戶名。
Step 3 : Config LoggerSetupBonjour
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
//在應用啟動時調用其定義的宏
#ifdef LOGGER_TARGET
LoggerSetupBonjour(NULL, NULL, (CFStringRef)LOGGER_TARGET);
//LoggerSetupBonjour(LoggerGetDefaultLogger(), NULL, (CFStringRef)LOGGER_TARGET);
#endif
return YES;
}
配置日志輸出的目標Bonjour Service為指定的名稱,即配置該日志只會輸出到名為LOGGER_TARGET(編譯該App的電腦的系統賬戶名稱)
Step 4 : NSLogger Viewer日志查看軟件配置
配置NSLogger Viewer日志查看軟件的Bonjour Service名字為當前系統賬戶名。
上述配置即完成了指定日志輸出到編譯該App電腦的賬戶名稱的日志查看客戶端,測試可以修改日志查看軟件的Bonjour Service Name可以指定接收查看對應App的日志輸出。
高階拓展
追蹤官方提供的內置宏,發現其實也是通過CocoaPods內置一個NSLOGGER_BUILD_USERNAME,然后通過LoggerSetupBonjour配置輸出到指定的日志接收服務。
void LoggerSetupBonjourForBuildUser() {
LoggerSetupBonjour(LoggerGetDefaultLogger(), NULL, CFSTR(nslogger_xstr(NSLOGGER_BUILD_USERNAME)));
}
上述方案也只是簡單解決了單個項目可以通過不同研發電腦的賬戶名區分日志輸出,若是都是通過Jekins在同一臺機器上編譯打包,那也是難以區分接收不同的日志;所以更多的需要結合Jekins參數化打包,在打包時手動配置一個日志targetName參數(例如打包任務創建者的名字),然后在App啟動時,didFinishLaunchingWithOptions函數內讀取該targetName參數,配置LoggerSetupBonjour。
例如:每個測試輸入自己的名字配置jekins打包targetName參數,然后該測試打包出來的App就可以通過配置Viewer軟件的Bonjour Service Name來指定接收查看自己正在測試的App的日志輸出;若有多個需要測試的項目也可以使用“姓名_appName”來唯一限定日志輸出目標.