数据采集自定义规则¶
View¶
需要开启配置 FTRUMConfig.enableTraceUserView = YES 。
rumConfig.viewTrackingHandler = [CustomViewTracker new];
#import "FTDefaultUIKitViewTrackingHandler.h"
// 协议实现方式示例
@interface CustomViewTracker : NSObject <FTUIKitViewTrackingHandler>
// 仅在需要 SDK 默认的 view 采集规则时添加
@property (nonatomic, strong) FTDefaultUIKitViewTrackingHandler defaultHandler;
@end
@implementation CustomViewTracker
// 仅在需要 SDK 默认的 view 采集规则时添加
-(FTDefaultUIKitViewTrackingHandler *)defaultHandler{
if (!_defaultHandler) {
_defaultHandler = [FTDefaultUIKitViewTrackingHandler new];
}
return _defaultHandler;
}
- (FTRUMView *)rumViewForViewController:(UIViewController *)viewController {
// 通过类名精确匹配
if ([viewController isKindOfClass:[HomeViewController class]]) {
return [[FTRUMView alloc] initWithViewName:@"main_home" property:@{@"page_type": @"home"}];
}
// 通过前缀过滤
else if ([NSStringFromClass([viewController class]) hasPrefix:@"FT"]) {
return [[FTRUMView alloc] initWithViewName:[NSString stringWithFormat:@"ft_%@", NSStringFromClass([viewController class])] property:nil];
}
// 通过 accessibilityLabel 设置
else if (viewController.view.accessibilityLabel) {
return [[FTRUMView alloc] initWithViewName:viewController.view.accessibilityLabel property:nil];
}
// 自定义部分页面后,剩余页面使用 SDK 默认采集规则(返回默认处理器的处理结果)
return [self.defaultHandler rumViewForViewController:viewController];
// 若需要跳过追踪,直接返回 nil 即可
return nil;
}
@end
rumConfig.viewTrackingHandler = CustomViewTracker()
class CustomViewTracker: NSObject, FTUIKitViewTrackingHandler {
// 仅在需要 SDK 默认 view 采集规则时保留该属性
lazy var defaultHandler: FTDefaultUIKitViewTrackingHandler = {
FTDefaultUIKitViewTrackingHandler()
}()
func rumView(for viewController: UIViewController) -> FTRUMView? {
// 通过类名精确匹配
if viewController is HomeViewController {
let properties: [String: Any] = ["page_type": "home"]
return FTRUMView(viewName: "main_home", property: properties)
}
// 通过类名前缀过滤
let vcClassName = String(describing: type(of: viewController))
if vcClassName.hasPrefix("FT") {
let viewName = "ft_\(vcClassName)"
return FTRUMView(viewName: viewName, property: nil)
}
// 通过 accessibilityLabel 设置
if let accessibilityLabel = viewController.view.accessibilityLabel, !accessibilityLabel.isEmpty {
return FTRUMView(viewName: accessibilityLabel, property: nil)
}
// 自定义部分页面后,剩余页面使用 SDK 默认采集规则(返回默认处理器的处理结果)
return defaultHandler.rumView(for: viewController)
// 若需要跳过追踪,直接返回 nil 即可
return nil
}
}
Action¶
需要开启配置 FTRUMConfig.enableTraceUserAction = YES。
rumConfig.actionTrackingHandler = [CustomActionTracker new];
#import "FTDefaultActionTrackingHandler.h"
// 协议实现方式示例
// 在 iOS 环境需遵循 `FTUIPressRUMActionsHandler` 协议
// 在 tvOS 环境 ,需遵循 `FTUITouchRUMActionsHandler` 协议。
@interface CustomActionTracker : NSObject <FTUIPressRUMActionsHandler,FTUITouchRUMActionsHandler>
// 仅在需要 SDK 默认的 Action 采集规则时添加
@property (nonatomic, strong) FTDefaultActionTrackingHandler defaultHandler;
@end
@implementation CustomActionTracker
// 仅在需要 SDK 默认的 Action 采集规则时添加
-(FTDefaultActionTrackingHandler *)defaultHandler{
if (!_defaultHandler) {
_defaultHandler = [FTDefaultActionTrackingHandler new];
}
return _defaultHandler;
}
// iOS 与 tvOS 都需要实现的协议方法
- (nullable FTRUMAction *)rumLaunchActionWithLaunchType:(FTLaunchType)type {
if(type == FTLaunchCold){
return [[FTRUMAction alloc]initWithActionName:@"cold"];
}
// 返回 nil 跳过跟踪
return nil;
}
// iOS 环境需实现的协议方法
-(nullable FTRUMAction *)rumActionWithTargetView:(UIView *)targetView{
if (view.accessibilityIdentifier){
return [[FTRUMAction alloc] initWithActionName:view.accessibilityIdentifier];
}
// 自定义部分 Action 后,剩余使用 SDK 默认采集规则(返回默认处理器的处理结果)
return [self.defaultHandler rumActionWithTargetView:targetView];
// 返回 nil 跳过跟踪
return nil;
}
// tvOS 环境需实现的协议方法
- (nullable FTRUMAction *)rumActionWithPressType:(UIPressType)type targetView:(UIView *)targetView{
if (type == UIPressTypeSelect && view.accessibilityIdentifier){
return [[FTRUMAction alloc] initWithActionName:view.accessibilityIdentifier];
}
// 自定义部分 Action 后,剩余使用 SDK 默认采集规则(返回默认处理器的处理结果)
return [self.defaultHandler rumActionWithPressType:type targetView:targetView];
// 返回 nil 跳过跟踪
return nil;
}
@end
rumConfig.actionTrackingHandler = CustomActionTracker()
// 协议实现方式示例
// 在 iOS 环境需遵循 `FTUIPressRUMActionsHandler` 协议
// 在 tvOS 环境 ,需遵循 `FTUITouchRUMActionsHandler` 协议。
class CustomActionTracker: NSObject, FTUIPressRUMActionsHandler, FTUITouchRUMActionsHandler {
// 仅在需要 SDK 默认的 Action 采集规则时添加
lazy var defaultHandler: FTDefaultActionTrackingHandler = {
FTDefaultActionTrackingHandler()
}()
// iOS 与 tvOS 都需要实现的协议方法
func rumLaunchAction(with type: FTLaunchType) -> FTRUMAction? {
if type == .cold {
return FTRUMAction(actionName: "cold")
}
// 返回 nil 跳过跟踪
return nil
}
// iOS 环境需实现的协议方法
func rumAction(withTargetView targetView: UIView) -> FTRUMAction? {
if let identifier = targetView.accessibilityIdentifier {
return FTRUMAction(actionName: identifier)
}
// 自定义部分 Action 后,剩余使用 SDK 默认采集规则(返回默认处理器的处理结果)
return defaultHandler.rumAction(withTargetView: targetView)
// 返回 nil 跳过跟踪
return nil
}
// tvOS 环境需实现的协议方法
func rumAction(with pressType: UIPress.PressType, targetView: UIView) -> FTRUMAction? {
if pressType == .select, let identifier = targetView.accessibilityIdentifier {
return FTRUMAction(actionName: identifier)
}
// 自定义部分 Action 后,剩余使用 SDK 默认采集规则(返回默认处理器的处理结果)
return defaultHandler.rumAction(with: pressType, targetView: targetView)
// 返回 nil 跳过跟踪
return nil
}
}
Resource¶
需要开启配置 FTRUMConfig.enableTraceUserResource = YES 或 通过转发 URLSession Delegate 自定义采集 Network
根据 Url 采集过滤¶
添加自定义属性¶
通过设置属性提供程序闭包,您可以返回要附加到 RUM Resoucre 的其他属性。
例如,您可能希望向 RUM Resource 添加 HTTP 请求 body:
rumConfig.resourcePropertyProvider = ^NSDictionary *_Nullable(NSURLRequest *request, NSURLResponse *response,NSData *data, NSError *error) {
NSString *body = @"";
if (request.HTTPBody) {
body = [[NSString alloc] initWithData:httpBody encoding:NSUTF8StringEncoding] ?: @"";
}
return @{@"request_body": body};
}
过滤网络错误¶
网络请求发生错误时,RUM 中会生成一条类型为 network_error 的 Error 数据,一些 URLSeesion 的本地错误比如 task.cancel 是用户程序中的正常逻辑,并非是错误数据,此时可以通过 sessionTaskErrorFilter 回调进行拦截过滤。确认拦截返回 YES,不拦截返回 NO,拦截后 RUM-Error 不采集该条错误。
自定义 TraceHeader¶
可以通过 FTTraceConfig.traceInterceptor 进行全局设置,或 URLSession 级自定义 Trace,以下为 w3c-traceContext 为例
FTTraceConfig *traceConfig = [[FTTraceConfig alloc]init];
traceConfig.traceInterceptor = ^FTTraceContext * _Nullable(NSURLRequest *request) {
// 1. 获取业务自定义的 traceId
NSString *replaceTrace = [request.allHTTPHeaderFields valueForKey:CUSTOM_TRACE_HEADER];
// 2. 获取 SDK 标准 W3C traceparent 请求头
NSDictionary *traceHeaders = [[FTExternalDataManager sharedManager] getTraceHeaderWithUrl:request.URL];
NSString *traceParentStr = traceHeaders[FT_NETWORK_TRACEPARENT_KEY];
// 3. 解析 W3C traceparent 格式并替换索引 1 的 traceId
NSArray *traceComponents = [traceParentStr componentsSeparatedByString:@"-"];
if (traceComponents.count != 4) {
return nil;
}
NSMutableArray *newComponents = [traceComponents mutableCopy];
newComponents[1] = replaceTrace;
NSString *newTraceParent = [newComponents componentsJoinedByString:@"-"];
// 4. 组装并返回自定义追踪上下文
FTTraceContext *context = [FTTraceContext new];
context.traceHeader = @{FT_NETWORK_TRACEPARENT_KEY:newTraceParent};
context.traceId = replaceTrace;
// 保留 SDK 生成的 spanId(索引 2 固定位置)
context.spanId = newComponents[2];
return context;
};
let traceConfig = FTTraceConfig()
traceConfig.traceInterceptor = { (request: URLRequest) -> FTTraceContext? in
// 1. 获取业务自定义的 traceId
guard let replaceTrace = request.allHTTPHeaderFields?[CUSTOM_TRACE_HEADER] else {
return nil
}
// 2. 获取 SDK 标准 W3C traceparent 请求头
guard let traceHeaders = FTExternalDataManager.shared().getTraceHeader(with: request.url!), let traceParentStr = traceHeaders[FT_NETWORK_TRACEPARENT_KEY] as? String else {
return nil
}
// 3. 解析 W3C traceparent 格式并替换索引 1 的 traceId
let traceComponents = traceParentStr.components(separatedBy: "-")
guard traceComponents.count == 4 else {
return nil
}
var newComponents = traceComponents
newComponents[1] = replaceTrace
let newTraceParent = newComponents.joined(separator: "-")
// 4. 组装并返回自定义追踪上下文
let context = FTTraceContext()
context.traceHeader = [FT_NETWORK_TRACEPARENT_KEY: newTraceParent]
context.traceId = replaceTrace
// 保留 SDK 生成的 spanId(索引 2 固定位置)
context.spanId = newComponents[2]
return context
}