Skip to main content

Bugly iOS 日志

Bugly 日志提供业务日志的主动上报和主动捞取的服务。需要接入日志 SDK (TDOS_Diagnose)后使用。

SDK 结构及接入

日志 SDK (TDOS_Diagnose),主要分为两部分:

  1. 日志捞取模块:日志捞取模块是 Bugly 提供日志能力的核心,实现了日志的上传和日志捞取命令字的拉取等能力;
  2. 本地打日志模块:为了方便未引入日志模块的业务使用,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, TDMMKVFactoryImplTDLogFilePackerImp 均是 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 中的日志打印模块 TDOSLoggerTDLoggingIMPProtocol 接口实现封装。

若要使用 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

同理,此处的 DefaultStorageImplDefaultFilePacker 模块亦是如此,提供实现对应接口的实例给 TDIAGDepends 即可。

日志捞取

Bugly 平台提供了日志捞取指令的下发功能,用户可以在 Bugly 管理端的 "日志查询" 页面进行指令的下发和上报结果查询。

通过 "新建查询" 入口,新建一个日志捞取命令:

新建日志查询

此处需要填入一个有效的“设备ID”值,该值便是 SDK 初始化时,由 TDLogSDKDataSource 中的 - (NSString *)guidForTDLog; 提供的值。

TDOS_DiagnoseSDK会默认在启动 / 进前台等时机以一定时间间隔主动检查有无日志捞取命令。对于有对于日志命令的设备,会进行对应日志的上报任务。

主动触发拉取捞日志命令(Push,可选)

业务可以接合自身 App 的 Push 通道,触发主动拉取捞日志命令。通过业务自身的 Push 能力,可更及时收到日志捞取命令,减少等待时间。

PS: 业务自身 Push 下发能力需要与 Bugly 平台进行对接,或在新建查询后,主动去触发一次对应指令。

客户端在收到Push命令后,需主动调用TDOS_DiagnoseSDK的如下接口,实现及时请求捞日志配置:

/// 主动拉取捞日志命令
///
/// 调用场景:如收到Push消息时
- (void)requestLogConfigFromServer;

// 调用示例:
#import <TDOS_Diagnose/TDOS_Diagnose.h>
[TDLogSDK.sharedInstance requestLogConfigFromServer];

主动上报日志

TDOS_DiagnoseSDK支持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_DiagnoseSDK对主动上报提供了如下4种安全机制:

  1. 大小限制机制:限制压缩前的总文件大小(默认500M),超过上限则只保留修改时间较新的部分文件。
  2. 频率限制机制:支持设置主动上传的频率,如10分钟内3次(SDK默认不开启)。设置接口参见TDLogSDKConfig
  3. 流量限制机制:支持设置每24小时的总上报流量与xg流量(SDK默认不开启),超过额度将禁止上报。设置接口参见TDLogSDKConfig
  4. 错误熔断机制:连续上传失败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_DiagnoseSDK提供了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;