URLSession 커스텀 네트워크 수집¶
URLSession Delegate를 통한 커스텀 네트워크 수집¶
SDK는 FTURLSessionDelegate 클래스를 제공합니다. 이 클래스를 사용하여 특정 URLSession이 시작한 네트워크 요청에 대해 커스텀 RUM Resource 수집 및 분산 추적을 수행할 수 있습니다.
FTURLSessionDelegate는traceInterceptor블록을 설정하여URLResquest를 가로채고 커스텀 분산 추적을 지원합니다 (SDK 1.5.9 이상 버전에서 지원). 우선순위는FTTraceConfig.traceInterceptor보다 높습니다.FTURLSessionDelegate는provider블록을 설정하여 RUM Resource에 추가로 수집할 속성을 커스텀할 수 있습니다. 우선순위는FTRumConfig.resourcePropertyProvider보다 높습니다.FTURLSessionDelegate는errorFilter블록을 설정하여 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와 함께 사용할 경우 우선순위는 커스텀 > 자동 수집입니다.
다양한 시나리오를 충족하기 위해 세 가지 방법을 제공합니다.
방법 1¶
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)
방법 2¶
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)
// 사용자 정의 로직
// ......
}
}
방법 3¶
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)
}
}