TNLExample/TNLXNetworkHeuristicObserver.m (95 lines of code) (raw):

// // TNLXNetworkHeuristicObserver.m // TwitterNetworkLayer // // Created on 1/26/15. // Copyright © 2020 Twitter. All rights reserved. // #import "TNLXNetworkHeuristicObserver.h" #define LOG_STATS_HEARTBEAT 0 @implementation TNLXNetworkHeuristicObserver { dispatch_queue_t _queue; dispatch_source_t _timer; NSTimeInterval _totalAttemptTime; NSTimeInterval _totalOperationTime; UInt64 _totalLayer8BytesUp; UInt64 _totalLayer8BytesDown; UInt64 _retryCount; UInt64 _redirectCount; UInt64 _attemptCount; UInt64 _cancelCount; } + (instancetype)sharedInstance { static TNLXNetworkHeuristicObserver *sInstance; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sInstance = [[TNLXNetworkHeuristicObserver alloc] init]; [[TNLGlobalConfiguration sharedInstance] addNetworkObserver:sInstance]; }); return sInstance; } - (instancetype)init { if (self = [super init]) { _queue = dispatch_queue_create("TNLXNetworkHeuristicObserver.queue", DISPATCH_QUEUE_SERIAL); #if LOG_STATS_HEARTBEAT _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, _queue); int64_t repeatInterval = (int64_t)(4.0 * (double)NSEC_PER_SEC); dispatch_source_set_timer(_timer, dispatch_time(DISPATCH_TIME_NOW, repeatInterval), (uint64_t)repeatInterval, (uint64_t)(1.0 * (double)NSEC_PER_SEC)); dispatch_source_set_event_handler(_timer, ^{ NSLog(@"%@", [self dictionaryValue]); }); dispatch_resume(_timer); #endif } return self; } - (void)tnl_requestOperation:(TNLRequestOperation *)op didCompleteAttemptWithIntermediateResponse:(TNLResponse *)response disposition:(TNLAttemptCompleteDisposition)disposition { TNLAttemptMetrics *metrics = response.metrics.attemptMetrics.lastObject; dispatch_async(_queue, ^{ NSTimeInterval duration = metrics.duration; TNLAttemptMetaData *metaData = metrics.metaData; if (duration >= 0.0) { self->_totalAttemptTime += duration; } if (metaData.layer8BodyBytesReceived > 0) { self->_totalLayer8BytesDown += (UInt64)metaData.layer8BodyBytesReceived; } if (metaData.layer8BodyBytesTransmitted > 0) { self->_totalLayer8BytesUp += (UInt64)metaData.layer8BodyBytesTransmitted; } switch (metrics.attemptType) { case TNLAttemptTypeInitial: break; case TNLAttemptTypeRedirect: self->_redirectCount++; break; case TNLAttemptTypeRetry: self->_retryCount++; break; } self->_attemptCount++; }); } - (void)tnl_requestOperation:(TNLRequestOperation *)op didCompleteWithResponse:(TNLResponse *)response { dispatch_async(_queue, ^{ NSTimeInterval duration = response.metrics.totalDuration; if (duration >= 0.0) { self->_totalOperationTime += duration; } if ([response.operationError.domain isEqualToString:TNLErrorDomain] && response.operationError.code == TNLErrorCodeRequestOperationCancelled) { self->_cancelCount++; } }); } - (NSDictionary *)dictionaryValue { return @{ @"attemptTime" : @(_totalAttemptTime), @"operationTime" : @(_totalOperationTime), @"l8_rx" : @(_totalLayer8BytesDown), @"l8_tx" : @(_totalLayer8BytesUp), @"attemptCount" : @(_attemptCount), @"redirectCount" : @(_redirectCount), @"retryCount" : @(_retryCount), @"cancelCount" : @(_cancelCount), }; } @end