URLSession 自定义 Network 采集¶
通过转发 URLSession Delegate 自定义采集 Network¶
SDK 提供了一个类 FTURLSessionDelegate,可以通过该类对某一 URLSession 发起的网络请求进行自定义 RUM Resource 采集和链路追踪。
FTURLSessionDelegate支持通过设置traceInterceptorblock 拦截URLResquest,进行自定义链路追踪(SDK 1.5.9 及以上版本支持该方法),优先级 >FTTraceConfig.traceInterceptorFTURLSessionDelegate支持通过设置providerblock 自定义 RUM Resource 需要额外采集的属性,优先级 >FTRumConfig.resourcePropertyProviderFTURLSessionDelegate支持通过设置errorFilterblock 自定义是否拦截 SessionTask Error(SDK 1.5.17 及以上版本支持)- return YES:拦截,RUM-Error 中不再添加本条
network_error - return NO:不拦截,RUM-Error 中添加本条
network_error
- return YES:拦截,RUM-Error 中不再添加本条
- 与
FTRumConfig.enableTraceUserResource、FTTraceConfig.enableAutoTrace一起使用时,优先级:自定义 > 自动采集
下面提供三种方法,来满足不同场景。
方法一¶
直接设置 URLSession 的 delegate 对象为 FTURLSessionDelegate 的实例。
id<NSURLSessionDelegate> delegate = [[FTURLSessionDelegate alloc]init];
// 添加自定义 RUM 资源属性,建议标签命名添加项目缩写的前缀,例如 `df_tag_name`。
delegate.provider = ^NSDictionary * _Nullable(NSURLRequest *request, NSURLResponse *response, NSData *data, NSError *error) {
NSString *body = [[NSString alloc] initWithData:request.HTTPBody encoding:NSUTF8StringEncoding];
return @{@"df_requestbody":body};
};
// 支持自定义 trace, 确认拦截后,返回 TraceContext,不拦截返回 nil
delegate.traceInterceptor = ^FTTraceContext * _Nullable(NSURLRequest *request) {
FTTraceContext *context = [FTTraceContext new];
context.traceHeader = @{@"trace_key":@"trace_value"};
context.traceId = @"trace_id";
context.spanId = @"span_id";
return context;
};
// 自定义是否拦截 SessionTask Error. return YES:拦截,RUM-Error 中不再添加本条 `network_error`
delegate.errorFilter = ^BOOL(NSError * _Nonnull error) {
return error.code == NSURLErrorCancelled;
};
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:delegate delegateQueue:nil];
let delegate = FTURLSessionDelegate.init()
// 添加自定义 RUM 资源属性,建议标签命名添加项目缩写的前缀,例如 `df_tag_name`。
delegate.provider = { request,response,data,error in
var extraData:Dictionary<String, Any> = Dictionary()
if let data = data,let requestBody = String(data: data, encoding: .utf8) {
extraData["df_requestBody"] = requestBody
}
if let error = error {
extraData["df_error"] = error.localizedDescription
}
return extraData
}
// 支持自定义 trace, 确认拦截后,返回 TraceContext,不拦截返回 nil
delegate.traceInterceptor = { request in
let traceContext = FTTraceContext()
traceContext.traceHeader = ["trace_key":"trace_value"]
traceContext.spanId = "spanId"
traceContext.traceId = "traceId"
return traceContext
}
delegate.errorFilter = { error in
return (error as? URLError)?.code == .cancelled
}
let session = URLSession.init(configuration: URLSessionConfiguration.default, delegate:delegate
, delegateQueue: nil)
方法二¶
使 URLSession 的 delegate 对象继承自 FTURLSessionDelegate 类。
如果 delegate 对象实现了下列方法,请确保在方法内调用父类相应的方法。
-URLSession:dataTask:didReceiveData:-URLSession:task:didCompleteWithError:-URLSession:task:didFinishCollectingMetrics:
@interface InstrumentationInheritClass:FTURLSessionDelegate
@property (nonatomic, strong) NSURLSession *session;
@end
@implementation InstrumentationInheritClass
-(instancetype)init{
self = [super init];
if(self){
_session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];
// 添加自定义 RUM 资源属性,建议标签命名添加项目缩写的前缀,例如 `df_tag_name`。
self.provider = ^NSDictionary * _Nullable(NSURLRequest *request, NSURLResponse *response, NSData *data, NSError *error) {
NSString *body = [[NSString alloc] initWithData:request.HTTPBody encoding:NSUTF8StringEncoding];
return @{@"df_requestbody":body};
};
// 支持自定义 trace, 确认拦截后,返回 TraceContext,不拦截返回 nil
self.traceInterceptor = ^FTTraceContext * _Nullable(NSURLRequest *request) {
FTTraceContext *context = [FTTraceContext new];
context.traceHeader = @{@"trace_key":@"trace_value"};
context.traceId = @"trace_id";
context.spanId = @"span_id";
return context;
};
// 自定义是否拦截 SessionTask Error. return YES:拦截,RUM-Error 中不再添加本条 `network_error`
self.errorFilter = ^BOOL(NSError * _Nonnull error) {
return error.code == NSURLErrorCancelled;
};
}
return self;
}
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics{
// 一定要调用 父类 方法
[super URLSession:session task:task didFinishCollectingMetrics:metrics];
// 您自己的逻辑
// ......
}
@end
class InheritHttpEngine:FTURLSessionDelegate {
var session:URLSession?
override init(){
session = nil
super.init()
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = 30
session = URLSession.init(configuration: configuration, delegate:self, delegateQueue: nil)
override init() {
super.init()
// 添加自定义 RUM 资源属性,建议标签命名添加项目缩写的前缀,例如 `df_tag_name`。
provider = { request,response,data,error in
var extraData:Dictionary<String, Any> = Dictionary()
if let data = data,let requestBody = String(data: data, encoding: .utf8) {
extraData["df_requestBody"] = requestBody
}
if let error = error {
extraData["df_error"] = error.localizedDescription
}
return extraData
}
// 支持自定义 trace, 确认拦截后,返回 TraceContext,不拦截返回 nil
traceInterceptor = { request in
let traceContext = FTTraceContext()
traceContext.traceHeader = ["trace_key":"trace_value"]
traceContext.spanId = "spanId"
traceContext.traceId = "traceId"
return traceContext
}
errorFilter = { error in
return (error as? URLError)?.code == .cancelled
}
}
}
override func urlSession(_ session: URLSession, task: URLSessionTask, didFinishCollecting metrics: URLSessionTaskMetrics) {
// 一定要调用 父类 方法
super.urlSession(session, task: task, didFinishCollecting: metrics)
// 用户自己的逻辑
// ......
}
}
方法三¶
使 URLSession 的 delegate 对象遵循 FTURLSessionDelegateProviding 协议。
- 实现协议中
ftURLSessionDelegate属性的 get 方法 - 转发下列 URLSession 的 delegate 方法到
ftURLSessionDelegate,以便于 SDK 进行数据采集-URLSession:dataTask:didReceiveData:-URLSession:task:didCompleteWithError:-URLSession:task:didFinishCollectingMetrics:
@interface UserURLSessionDelegateClass:NSObject<NSURLSessionDataDelegate,FTURLSessionDelegateProviding>
@end
@implementation UserURLSessionDelegateClass
@synthesize ftURLSessionDelegate = _ftURLSessionDelegate;
- (nonnull FTURLSessionDelegate *)ftURLSessionDelegate {
if(!_ftURLSessionDelegate){
_ftURLSessionDelegate = [[FTURLSessionDelegate alloc]init];
// 添加自定义 RUM 资源属性,建议标签命名添加项目缩写的前缀,例如 `df_tag_name`。
_ftURLSessionDelegate.provider = ^NSDictionary * _Nullable(NSURLRequest *request, NSURLResponse *response, NSData *data, NSError *error) {
NSString *body = [[NSString alloc] initWithData:request.HTTPBody encoding:NSUTF8StringEncoding];
return @{@"df_requestbody":body};
};
// 支持自定义 trace, 确认拦截后,返回 TraceContext,不拦截返回 nil
_ftURLSessionDelegate.requestInterceptor = ^NSURLRequest * _Nonnull(NSURLRequest * _Nonnull request) {
NSDictionary *traceHeader = [[FTExternalDataManager sharedManager] getTraceHeaderWithUrl:request.URL];
NSMutableURLRequest *newRequest = [request mutableCopy];
if(traceHeader){
for (NSString *key in traceHeader.allKeys) {
[newRequest setValue:traceHeader[key] forHTTPHeaderField:key];
}
}
return newRequest;
};
// 自定义是否拦截 SessionTask Error. return YES:拦截,RUM-Error 中不再添加本条 `network_error`
_ftURLSessionDelegate.errorFilter = ^BOOL(NSError * _Nonnull error) {
return error.code == NSURLErrorCancelled;
};
}
return _ftURLSessionDelegate;
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{
[self.ftURLSessionDelegate URLSession:session dataTask:dataTask didReceiveData:data];
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
[self.ftURLSessionDelegate URLSession:session task:task didCompleteWithError:error];
}
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics{
[self.ftURLSessionDelegate URLSession:session task:task didFinishCollectingMetrics:metrics];
}
@end
class HttpEngine:NSObject,URLSessionDataDelegate,FTURLSessionDelegateProviding {
var ftURLSessionDelegate: FTURLSessionDelegate = FTURLSessionDelegate()
var session:URLSession?
override init(){
session = nil
super.init()
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = 30
session = URLSession.init(configuration: configuration, delegate:self, delegateQueue: nil)
// 添加自定义 RUM 资源属性,建议标签命名添加项目缩写的前缀,例如 `df_tag_name`。
ftURLSessionDelegate.provider = { request,response,data,error in
var extraData:Dictionary<String, Any> = Dictionary()
if let data = data,let requestBody = String(data: data, encoding: .utf8) {
extraData["df_requestBody"] = requestBody
}
if let error = error {
extraData["df_error"] = error.localizedDescription
}
return extraData
}
// 支持自定义 trace, 确认拦截后,返回 TraceContext,不拦截返回 nil
ftURLSessionDelegate.traceInterceptor = { request in
let traceContext = FTTraceContext()
traceContext.traceHeader = ["trace_key":"trace_value"]
traceContext.spanId = "spanId"
traceContext.traceId = "traceId"
return traceContext
}
ftURLSessionDelegate.errorFilter = { error in
return (error as? URLError)?.code == .cancelled
}
}
// 下面方法一定要实现
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
ftURLSessionDelegate.urlSession(session, dataTask: dataTask, didReceive: data)
}
func urlSession(_ session: URLSession, task: URLSessionTask, didFinishCollecting metrics: URLSessionTaskMetrics) {
ftURLSessionDelegate.urlSession(session, task: task, didFinishCollecting: metrics)
}
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
ftURLSessionDelegate.urlSession(session, task: task, didCompleteWithError: error)
}
}