跳转至

URLSession 自定义 Network 采集

通过转发 URLSession Delegate 自定义采集 Network

SDK 提供了一个类 FTURLSessionDelegate,可以通过该类对某一 URLSession 发起的网络请求进行自定义 RUM Resource 采集链路追踪

  • FTURLSessionDelegate 支持通过设置 traceInterceptor block 拦截 URLResquest,进行自定义链路追踪(SDK 1.5.9 及以上版本支持该方法),优先级 > FTTraceConfig.traceInterceptor
  • FTURLSessionDelegate 支持通过设置 provider block 自定义 RUM Resource 需要额外采集的属性,优先级 > FTRumConfig.resourcePropertyProvider
  • FTURLSessionDelegate 支持通过设置 errorFilter block 自定义是否拦截 SessionTask Error(SDK 1.5.17 及以上版本支持)
    • return YES:拦截,RUM-Error 中不再添加本条 network_error
    • return NO:不拦截,RUM-Error 中添加本条 network_error
  • FTRumConfig.enableTraceUserResourceFTTraceConfig.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)
    }
}

文档评价

文档内容是否对您有帮助? ×