Bugly iOS 日志
Bugly 日志提供业务日志的主动上报和主动捞取的服务。需要接入日志 SDK (TDOS_Diagnose)后使用。
SDK 结构及接入
日志 SDK (TDOS_Diagnose),主要分为两部分:
- 日志捞取模块:日志捞取模块是 Bugly 提供日志能力的核心,实现了日志的上传和日志捞取命令字的拉取等能力;
- 本地打日志模块:为了方便未引入日志模块的业务使用,Bugly 提供了一个高效的日志打印模块;该模块为可选模块,业务可以保持使用自己的日志模块,将日志存储位置交给 Bugly SDK 即可实现正常的捞取上报。
SDK 接入
1. 引入 TDOS_Diagnose.framework
TDOS_Diagnose
SDK 支持通过 CocoaPods 接入。直接在 Podfile 中引入即可:
环境要求 (Requirements):iOS 9.0+
# 添加Pod依赖
pod 'TDOS_Diagnose', '0.8.2.1'
直接引入 TDOS_Diagnose 会默认包含 TDOS_Diagnose 的所有模块,主要有以下几部分组成:
TDOS_Diagnose/Core
: 核心模块,提供日志的上传和下发命令的捞取等能力支持;TDOS_Diagnose/DefaultLogger
: SDK 提供的默认的打日志模块实现,底层依赖 mars.framework;TDOS_Diagnose/DefaultStorageImpl
: 默认的KV存储实现,依赖MMKV;TDOS_Diagnose/DefaultFilePacker
: 默认的文件压缩实现,依赖SSZipArchive;
除去核心模块外,其中后三者可以替换为业务的其他实现,具体的使用方法参考后续介绍。
2. 配置和启动 SDK
由于 SDK 中的打日志、KV存储及文件压缩均是可替换模块,故在 SDK 初始化前,需要先配置好对应的依赖情况。
SDK 通过 TDIAGDepends
来管理模块的依赖情况。TDIAGDepends 实例需要提供实现 id<TDLoggingIMPProtocol>
, id<RAFTKVStorageFactoryProtocol>)
和 id<TDLogFilePackerProtocol>
的实际例。例如:
#import <TDOS_Diagnose/TDOS_Diagnose.h> // 日志 SDK 模块
#import <TDOS_Diagnose/TDMMKVFactoryImpl.h> // MMKV模块
#import <TDOS_Diagnose/TDOSLoggerProxy.h> // 打日志模块
#import <TDOS_Diagnose/TDLogFilePackerImp.h> // 文件压缩模块
// 使用 SDK 提供的默认模块
TDOSLoggerProxy *loggerProxy = [TDOSLoggerProxy defaultProxy];
TDMMKVFactory *kvFactory = [TDMMKVFactoryImpl sharedInstance];
TDLogFilePackerImp *filePacker = [[TDLogFilePackerImp alloc] init];
// 创建一个 TDIAGDepends 实例子
TDIAGDepends *depends = [TDIAGDepends dependsWithLogImp:loggerProxy
kvFactoryImp:kvFactory
andFilePackerImp:filePacker];
上述例子中的 TDOSLoggerProxy
, TDMMKVFactoryImpl
及 TDLogFilePackerImp
均是 SDK 提供的默认且实现了对应接口的实例子。
创建完 TDIAGDepends 后,便可以正常初始化 SDK 了。
// appid & appKey, 平台生成
NSString *appID = BUGLY_APPID;
NSString *appKey = BUGLY_APPKEY;
提供对应的 AppID 和 AppKey, 此处直接使用 Bugly 产品注册时提供的 AppID 和 AppKey 即可。
// 生成捞日志模块配置实例,并初始化
TDLogSDKConfig *config = [TDLogSDKConfig configWithAppId:appID
appKey:appKey
dataSource:self
depends:depends];
这里需要提供一个 dataSource, 该对象需要实现 TDLogSDKDataSource
协议,为 SDK 提供必要的数据。详情可以参考 TDLogSDKDataSource 中的定义。
其中需要必要实现 - (NSString *)guidForTDLog;
方法,该方法返回用户唯一ID,平台下发命令时填写此ID。
默认情况下,日志模块使用的内部域名,对于 BuglyPro 用户而言,需要在 TDLogSDKConfig
提供对应的域名类型:
// !!!: 设置 server host type 为 TDLogServerHostTypeBuglyPro
config.serverHostType = TDLogServerHostTypeBuglyPro;
// 开启频率控制(默认不限制),传空表示使用SDK默认频控策略:2次/5min,也可传入自定义策略;被限制后自动上报接口会回调失败。
// 举例:10min内最多只允许3次上报(采用令牌桶算法)
// TDLogFrequencyControlStrategy *strategy = [TDLogFrequencyControlStrategy new];
// strategy.times = 3;
// strategy.timeInterval = 10 * 60;
// 注意,该接口要求TDLogSDKDataSource必须实现whitelistForAutoUploadTags协议,提供自动上报tag白名单,避免影响必要上报。
[config setFrequencyLimitStatusForAutoUpload:YES
withCustomControlStrategy:nil]; // 推荐设置,确保不频繁自动上报
// 开启流量控制(默认不限制),传0表示禁止上报,传入负值代表不限制,被限制后自动上报接口会回调失败。
// 注意,该接口要求TDLogSDKDataSource必须实现whitelistForAutoUploadTags协议,提供自动上报tag白名单,避免影响必要上报。
[config setTrafficQuota24hLimitForAutoUpload:(200 * 1024 * 1024)
xgQuota:(50 * 1024 * 1024)]; // 可选,设置自动上报流量限额
根据业务需求,可以配置对应的频率和流量控制策略,确保不会因为频繁上报日志占用过多的网络资源等。
[[TDLogSDK sharedInstance] startWithConfig:config];
最后调用对应的方法启动 SDK,即可完成初始化工作。
3. 配置本地打日志模块
上述中的 TDOSLoggerProxy
实际上是对 TDOS_Diagnose 中的日志打印模块 TDOSLogger
的 TDLoggingIMPProtocol
接口实现封装。
若要使用 TDOSLogger
模块,需要对该模块做一些初始化工作:
// 初始化打日志模块
TDOSLoggerConfig *loggerConfig = [TDOSLoggerConfig defaultConfig];
TDOSLogger *logger = [[TDOSLogger alloc] initWithConfig:loggerConfig];
并将实力化后的 logger 对象设置到上述过程中的 TDOSLoggerProxy
对象中,以正常使用 TDOSLogger
模块。
TDOSLoggerProxy *loggerProxy = [TDOSLoggerProxy defaultProxy];
[loggerProxy setLogger:logger];
Extension项目接入特别说明: 本SDK支持iOS Extension,如使用默认的依赖模块MMKV,需在项目Podfile中添加如下脚本:
post_install do |installer|
installer.pods_project.targets.each do |target|
if target.name == "MMKV"
target.build_configurations.each do |config|
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)', 'MMKV_IOS_EXTENSION']
end
end
end
end
TDOSLogger
还提供一些其他特性, 详情参考后续的SDK日志打印模块说明。
可选模块配置
上述 SDK 接入中,都是按照业务以来所有 TDOS_Diagnose
模块进行的接入。如上所述,对于已经有日志打印等模块额业务而言,不需要引入新的日志打印模块,此时可以选择直接入基础模块,通过实现 TDLoggingIMPProtocol
接口来使用。此时在 Pod 引入模块时,可以使用子模块引入的方式,仅引入 TDOS_Diagnose/Core
模块即可。
之后将实现了 TDLoggingIMPProtocol
(LogReport/TDLoggingIMPProtocol.h) 接口的模块直接实例化后,用其初始化 TDIAGDepends
。
同理,此处的 DefaultStorageImpl
和 DefaultFilePacker
模块亦是如此,提供实现对应接口的实例给 TDIAGDepends
即可。
日志捞取
Bugly 平台提供了日志捞取指令的下发功能,用户可以在 Bugly 管理端的 "日志查询" 页面进行指令的下发和上报结果查询。
通过 "新建查询" 入口,新建一个日志捞取命令:
此处需要填入一个有效的“设备ID”值,该值便是 SDK 初始化时,由 TDLogSDKDataSource
中的 - (NSString *)guidForTDLog;
提供的值。
TDOS_Diagnose
SDK会默认在启动
/ 进前台
等时机以一定时间间隔主动检查有无日志捞取命令。对于有对于日志命令的设备,会进行对应日志的上报任务。
主动触发拉取捞日志命令(Push,可选)
业务可以接合自身 App 的 Push 通道,触发主动拉取捞日志命令。通过业务自身的 Push 能力,可更及时收到日志捞取命令,减少等待时间。
PS: 业务自身 Push 下发能力需要与 Bugly 平台进行对接,或在新建查询后,主动去触发一次对应指令。
客户端在收到Push命令后,需主动调用TDOS_Diagnose
SDK的如下接口,实现及时请求捞日志配置:
/// 主动拉取捞日志命令
///
/// 调用场景:如收到Push消息时
- (void)requestLogConfigFromServer;
// 调用示例:
#import <TDOS_Diagnose/TDOS_Diagnose.h>
[TDLogSDK.sharedInstance requestLogConfigFromServer];
主动上报日志
TDOS_Diagnose
SDK支持APP主动调用上报接口,上传自定义日志、文件等信息。主动上报的日志可以在 “日志查询”-“主动上报” Tab 下查询到。
该功能可用于用户反馈、异常发生等场景及时上报本地日志信息,帮助保留问题现场。
接口说明:
/// 主动上报日志
/// @param files 日志文件列表
/// @param tag 标签,必填,最大长度64bytes
/// @param summary 摘要信息(支持搜索),最大长度256bytes
/// @param extendInfoDict 扩展信息,最大长度1K
/// @param completionBlock 上传结果回调
- (void)uploadFiles:(nonnull NSArray <NSString *> *)files
withTag:(NSString *)tag
summary:(nullable NSString *)summary
andExtendInfo:(nullable NSDictionary *)extendInfoDict
completion:(void (^)(BOOL result, NSString *_Nullable errMsg))completionBlock;
成功上报后,在平台端“自动上报”页面即可查看上报记录和内容。
请合理指定上报内容或时间范围,避免主动上报日志过大或调用过频繁。
✅更新说明(v0.5.5):
由于主动上报是程序自动触发,其频率与时机存在不可控性。为了保障上报安全,避免App异常情况下高频上报,导致浪费流量等问题,TDOS_Diagnose
SDK对主动上报提供了如下4种安全机制:
- 大小限制机制:限制压缩前的总文件大小(默认500M),超过上限则只保留修改时间较新的部分文件。
- 频率限制机制:支持设置主动上传的频率,如10分钟内3次(SDK默认不开启)。设置接口参见
TDLogSDKConfig
。 - 流量限制机制:支持设置每24小时的总上报流量与xg流量(SDK默认不开启),超过额度将禁止上报。设置接口参见
TDLogSDKConfig
。 - 错误熔断机制:连续上传失败10次后,将停用自动上报6h。(此机制为SDK内部安全兜底机制,暂不支持调整)。
SDK日志打印模块说明
SDK内置的打日志能力基于微信Mars-xlog方案,对外提供能力在TDLoggingIMPProtocol
(TDOS_Diagnose/Classes/LogReport/TDLoggingIMPProtocol.h)中定义,主要包含如下本地日志打印、日志染色、日志文件获取等功能,使用方法:
// 头文件
#import <TDOS_Diagnose/TDOSLoggerProxy.h>
// 初始化方式:
@interface TDOSLogger : NSObject <TDLoggingIMPProtocol>
/// 根据配置初始化日志SDK
/// @param config 配置
- (instancetype)initWithConfig:(TDOSLoggerConfig *)config;
@end
// 其中,TDOSLoggerConfig配置包含如下可选设置项:
/// 日志目录
@property (nonatomic, readonly) NSString *logPath;
/// 默认日志级别,默认RAFTLogLevel_Error
@property (nonatomic, readonly) RAFTLogLevel defaultLogLevel;
/// 加密Key
@property (nonatomic, readonly) NSString *publicKey;
/// 控制台是否输出,默认关闭
@property (nonatomic, assign) BOOL enableConsoleLog;
/// 日志文件名前缀(可选设置)
@property (nonatomic, copy) NSString *logFilePrefix;
✅更新说明v0.5.7:打日志模块支持多实例,即不同业务日志输出至不同文件。使用方式详见TDLoggingIMPProtocol
或参考Example工程。
下面具体说明一些能力:
基础能力
包含打日志、设置日志级别、强制日志落地等。其中日志级别遵循RAFT日志定义——RAFTLogDef
(Log/RAFTLogDef.h),提供7个级别。
RAFTLogLevelVerbose = 0,
RAFTLogLevelDebug = 1,
RAFTLogLevelInfo = 2,
RAFTLogLevelWarn = 3,
RAFTLogLevelError = 4,
RAFTLogLevelFatal = 5,
RAFTLogLevelNone = 6,
在此基础上,TDOS_Diagnose
SDK提供了5个宏定义,以便业务快速接入。这些宏定义在TDOSLoggerProxy
中,如下所示:
#define TDLogDebug(tag, format, ...)
#define TDLogInfo(tag, format, ...)
#define TDLogWarn(tag, format, ...)
#define TDLogError(tag, format, ...)
#define TDLogFatal(tag, format, ...)
原始具体接口如下所示:
/// 打日志接口(不带格式化字符串)
- (void)log:(RAFTLogLevel)level
tag:(NSString *)tag
file:(const char *)file
func:(const char *)func
line:(int)line
msg:(NSString *)msg;
/// 打日志接口(带格式化字符串)
- (void)log:(RAFTLogLevel)level
tag:(NSString *)tag
file:(const char *)file
func:(const char *)func
line:(int)line
format:(NSString *)format, ... __attribute__((format(__NSString__, 6, 7))) NS_REQUIRES_NIL_TERMINATION;
/// 获取当前是否处于染色状态
- (BOOL)isColorState;
/// 重置染色级别
- (void)resetColorLevel;
/// 设置Log打印级别
/// @param level 日志级别
- (void)setLogLevel:(RAFTLogLevel)level;
/// 设置打印log的特殊级别, 以及特殊级别的过期时间
/// @param level 日志级别
/// @param endtime 结束时间
- (void)setLogLevel:(RAFTLogLevel)level endTimestamp:(time_t)endtime;
/// 强制写入日志到文件
/// @param isSync 是否同步写入
- (void)flushLog:(BOOL)isSync;
更多日志设置能力
包含设置本地日志最大保留时间(默认10天)、设置本地保留的最大日志总量、设置控制台日志输出、设置日志落地时机等。
/// 设置日志最大存留时间
/// @param time 单位s,默认10(10*24*60*60)天
- (void)setMaxLogAliveTime:(long)time;
/// 设置总的日志文件大小,超出即清理(底层限制最小50M)
/// @param maxSize 总文件大小,默认为0不限制
- (void)setMaxTotalLogFileSize:(int64_t)maxSize;
/// 设置控制台log输出
/// @param enabled 是否开启
- (void)setConsoleLogEnabled:(BOOL)enabled;
日志信息获取
/// 获取日志列表(按小时打印)
/// @param startTime 开始时间戳
/// @param endTime 结束时间戳
- (nullable NSArray<NSString *> *)getPeroidLogFilesWithStartTime:(NSTimeInterval)startTime
endTime:(NSTimeInterval)endTime;
/// 获取日志列表,支持限定最大日志量
/// (超过大小优先丢弃旧文件)
///
/// @param startTime 开始时间戳
/// @param endTime 结束时间戳
/// @param sizeLimit 最大日志包
- (nullable NSArray<NSString *> *)getPeroidLogFilesWithStartTime:(NSTimeInterval)startTime
endTime:(NSTimeInterval)endTime
sizeLimit:(unsigned long long)sizeLimit;
/// 获取日志文件夹路径。
- (NSString *)getLogFolderPath;
/// 获取日志加密公钥
- (nullable NSString *)getLogEncryptPublicKey;