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”来唯一限定日志输出目标.