QNUploadRequestMetrics.m 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. //
  2. // QNUploadRequestMetrics.m
  3. // QiniuSDK
  4. //
  5. // Created by yangsen on 2020/4/29.
  6. // Copyright © 2020 Qiniu. All rights reserved.
  7. //
  8. #import "QNUtils.h"
  9. #import "QNUploadRequestMetrics.h"
  10. #import "NSURLRequest+QNRequest.h"
  11. #import "QNZoneInfo.h"
  12. @interface QNUploadMetrics()
  13. @property (nullable, strong) NSDate *startDate;
  14. @property (nullable, strong) NSDate *endDate;
  15. @end
  16. @implementation QNUploadMetrics
  17. //MARK:-- 构造
  18. + (instancetype)emptyMetrics {
  19. return [[self alloc] init];
  20. }
  21. - (NSNumber *)totalElapsedTime{
  22. return [QNUtils dateDuration:self.startDate endDate:self.endDate];
  23. }
  24. - (void)start {
  25. self.startDate = [NSDate date];
  26. }
  27. - (void)end {
  28. self.endDate = [NSDate date];
  29. }
  30. @end
  31. @interface QNUploadSingleRequestMetrics()
  32. @property (nonatomic, assign) int64_t countOfRequestHeaderBytes;
  33. @property (nonatomic, assign) int64_t countOfRequestBodyBytes;
  34. @end
  35. @implementation QNUploadSingleRequestMetrics
  36. + (instancetype)emptyMetrics{
  37. QNUploadSingleRequestMetrics *metrics = [[QNUploadSingleRequestMetrics alloc] init];
  38. return metrics;
  39. }
  40. - (instancetype)init{
  41. if (self = [super init]) {
  42. [self initData];
  43. }
  44. return self;
  45. }
  46. - (void)initData{
  47. _countOfRequestHeaderBytesSent = 0;
  48. _countOfRequestBodyBytesSent = 0;
  49. _countOfResponseHeaderBytesReceived = 0;
  50. _countOfResponseBodyBytesReceived = 0;
  51. }
  52. - (void)setRequest:(NSURLRequest *)request{
  53. NSMutableURLRequest *newRequest = [NSMutableURLRequest requestWithURL:request.URL
  54. cachePolicy:request.cachePolicy
  55. timeoutInterval:request.timeoutInterval];
  56. newRequest.allHTTPHeaderFields = request.allHTTPHeaderFields;
  57. self.countOfRequestHeaderBytes = [NSString stringWithFormat:@"%@", request.allHTTPHeaderFields].length;
  58. self.countOfRequestBodyBytes = [request.qn_getHttpBody length];
  59. _totalBytes = @(self.countOfRequestHeaderBytes + self.countOfRequestBodyBytes);
  60. _request = [newRequest copy];
  61. }
  62. - (void)setResponse:(NSURLResponse *)response {
  63. if ([response isKindOfClass:[NSHTTPURLResponse class]] &&
  64. [(NSHTTPURLResponse *)response statusCode] >= 200 &&
  65. [(NSHTTPURLResponse *)response statusCode] < 300) {
  66. _countOfRequestHeaderBytesSent = _countOfRequestHeaderBytes;
  67. _countOfRequestBodyBytesSent = _countOfRequestBodyBytes;
  68. }
  69. if (_countOfResponseBodyBytesReceived <= 0) {
  70. _countOfResponseBodyBytesReceived = response.expectedContentLength;
  71. }
  72. if (_countOfResponseHeaderBytesReceived <= 0 && [response isKindOfClass:[NSHTTPURLResponse class]]) {
  73. _countOfResponseHeaderBytesReceived = [NSString stringWithFormat:@"%@", [(NSHTTPURLResponse *)response allHeaderFields]].length;
  74. }
  75. _response = [response copy];
  76. }
  77. - (BOOL)isForsureHijacked {
  78. return [self.hijacked isEqualToString:kQNMetricsRequestHijacked];
  79. }
  80. - (BOOL)isMaybeHijacked {
  81. return [self.hijacked isEqualToString:kQNMetricsRequestMaybeHijacked];
  82. }
  83. - (NSNumber *)totalElapsedTime{
  84. return [self timeFromStartDate:self.startDate
  85. toEndDate:self.endDate];
  86. }
  87. - (NSNumber *)totalDnsTime{
  88. return [self timeFromStartDate:self.domainLookupStartDate
  89. toEndDate:self.domainLookupEndDate];
  90. }
  91. - (NSNumber *)totalConnectTime{
  92. return [self timeFromStartDate:self.connectStartDate
  93. toEndDate:self.connectEndDate];
  94. }
  95. - (NSNumber *)totalSecureConnectTime{
  96. return [self timeFromStartDate:self.secureConnectionStartDate
  97. toEndDate:self.secureConnectionEndDate];
  98. }
  99. - (NSNumber *)totalRequestTime{
  100. return [self timeFromStartDate:self.requestStartDate
  101. toEndDate:self.requestEndDate];
  102. }
  103. - (NSNumber *)totalWaitTime{
  104. return [self timeFromStartDate:self.requestEndDate
  105. toEndDate:self.responseStartDate];
  106. }
  107. - (NSNumber *)totalResponseTime{
  108. return [self timeFromStartDate:self.responseStartDate
  109. toEndDate:self.responseEndDate];
  110. }
  111. - (NSNumber *)bytesSend{
  112. int64_t totalBytes = [self totalBytes].integerValue;
  113. int64_t senderBytes = self.countOfRequestBodyBytesSent + self.countOfRequestHeaderBytesSent;
  114. int64_t bytes = MIN(totalBytes, senderBytes);
  115. return @(bytes);
  116. }
  117. - (NSNumber *)timeFromStartDate:(NSDate *)startDate toEndDate:(NSDate *)endDate{
  118. return [QNUtils dateDuration:startDate endDate:endDate];
  119. }
  120. - (NSNumber *)perceptiveSpeed {
  121. int64_t size = self.bytesSend.longLongValue + _countOfResponseHeaderBytesReceived + _countOfResponseBodyBytesReceived;
  122. if (size == 0 || self.totalElapsedTime == nil) {
  123. return nil;
  124. }
  125. return [QNUtils calculateSpeed:size totalTime:self.totalElapsedTime.longLongValue];
  126. }
  127. @end
  128. @interface QNUploadRegionRequestMetrics()
  129. @property (nonatomic, strong) id <QNUploadRegion> region;
  130. @property (nonatomic, copy) NSMutableArray<QNUploadSingleRequestMetrics *> *metricsListInter;
  131. @end
  132. @implementation QNUploadRegionRequestMetrics
  133. + (instancetype)emptyMetrics{
  134. QNUploadRegionRequestMetrics *metrics = [[QNUploadRegionRequestMetrics alloc] init];
  135. return metrics;
  136. }
  137. - (instancetype)initWithRegion:(id<QNUploadRegion>)region{
  138. if (self = [super init]) {
  139. _region = region;
  140. _metricsListInter = [NSMutableArray array];
  141. }
  142. return self;
  143. }
  144. - (QNUploadSingleRequestMetrics *)lastMetrics {
  145. @synchronized (self) {
  146. return self.metricsListInter.lastObject;
  147. }
  148. }
  149. - (NSNumber *)requestCount{
  150. if (self.metricsList) {
  151. return @(self.metricsList.count);
  152. } else {
  153. return @(0);
  154. }
  155. }
  156. - (NSNumber *)bytesSend{
  157. if (self.metricsList) {
  158. long long bytes = 0;
  159. for (QNUploadSingleRequestMetrics *metrics in self.metricsList) {
  160. bytes += metrics.bytesSend.longLongValue;
  161. }
  162. return @(bytes);
  163. } else {
  164. return @(0);
  165. }
  166. }
  167. - (void)addMetricsList:(NSArray<QNUploadSingleRequestMetrics *> *)metricsList{
  168. @synchronized (self) {
  169. [_metricsListInter addObjectsFromArray:metricsList];
  170. }
  171. }
  172. - (void)addMetrics:(QNUploadRegionRequestMetrics*)metrics{
  173. if ([metrics.region.zoneInfo.regionId isEqualToString:self.region.zoneInfo.regionId]) {
  174. @synchronized (self) {
  175. [_metricsListInter addObjectsFromArray:metrics.metricsListInter];
  176. }
  177. }
  178. }
  179. - (NSArray<QNUploadSingleRequestMetrics *> *)metricsList{
  180. @synchronized (self) {
  181. return [_metricsListInter copy];
  182. }
  183. }
  184. @end
  185. @interface QNUploadTaskMetrics()
  186. @property (nonatomic, copy) NSString *upType;
  187. @property (nonatomic, copy) NSMutableArray<NSString *> *metricsKeys;
  188. @property (nonatomic, strong) NSMutableDictionary<NSString *, QNUploadRegionRequestMetrics *> *metricsInfo;
  189. @end
  190. @implementation QNUploadTaskMetrics
  191. + (instancetype)emptyMetrics{
  192. QNUploadTaskMetrics *metrics = [[QNUploadTaskMetrics alloc] init];
  193. return metrics;
  194. }
  195. + (instancetype)taskMetrics:(NSString *)upType {
  196. QNUploadTaskMetrics *metrics = [self emptyMetrics];
  197. metrics.upType = upType;
  198. return metrics;
  199. }
  200. - (instancetype)init{
  201. if (self = [super init]) {
  202. _metricsKeys = [NSMutableArray array];
  203. _metricsInfo = [NSMutableDictionary dictionary];
  204. }
  205. return self;
  206. }
  207. - (QNUploadRegionRequestMetrics *)lastMetrics {
  208. if (self.metricsKeys.count < 1) {
  209. return nil;
  210. }
  211. @synchronized (self) {
  212. NSString *key = self.metricsKeys.lastObject;
  213. if (key == nil) {
  214. return nil;
  215. }
  216. return self.metricsInfo[key];
  217. }
  218. }
  219. - (NSNumber *)totalElapsedTime{
  220. NSDictionary *metricsInfo = [self syncCopyMetricsInfo];
  221. if (metricsInfo) {
  222. double time = 0;
  223. for (QNUploadRegionRequestMetrics *metrics in metricsInfo.allValues) {
  224. time += metrics.totalElapsedTime.doubleValue;
  225. }
  226. return time > 0 ? @(time) : nil;
  227. } else {
  228. return nil;
  229. }
  230. }
  231. - (NSNumber *)requestCount{
  232. NSDictionary *metricsInfo = [self syncCopyMetricsInfo];
  233. if (metricsInfo) {
  234. NSInteger count = 0;
  235. for (QNUploadRegionRequestMetrics *metrics in metricsInfo.allValues) {
  236. count += metrics.requestCount.integerValue;
  237. }
  238. return @(count);
  239. } else {
  240. return @(0);
  241. }
  242. }
  243. - (NSNumber *)bytesSend{
  244. NSDictionary *metricsInfo = [self syncCopyMetricsInfo];
  245. if (metricsInfo) {
  246. long long bytes = 0;
  247. for (QNUploadRegionRequestMetrics *metrics in metricsInfo.allValues) {
  248. bytes += metrics.bytesSend.longLongValue;
  249. }
  250. return @(bytes);
  251. } else {
  252. return @(0);
  253. }
  254. }
  255. - (NSNumber *)regionCount{
  256. NSDictionary *metricsInfo = [self syncCopyMetricsInfo];
  257. if (metricsInfo) {
  258. int count = 0;
  259. for (QNUploadRegionRequestMetrics *metrics in metricsInfo.allValues) {
  260. if (![metrics.region.zoneInfo.regionId isEqualToString:QNZoneInfoEmptyRegionId]) {
  261. count += 1;
  262. }
  263. }
  264. return @(count);
  265. } else {
  266. return @(0);
  267. }
  268. }
  269. - (void)setUcQueryMetrics:(QNUploadRegionRequestMetrics *)ucQueryMetrics {
  270. _ucQueryMetrics = ucQueryMetrics;
  271. [self addMetrics:ucQueryMetrics];
  272. }
  273. - (void)addMetrics:(QNUploadRegionRequestMetrics *)metrics{
  274. NSString *regionId = metrics.region.zoneInfo.regionId;
  275. if (!regionId) {
  276. return;
  277. }
  278. @synchronized (self) {
  279. QNUploadRegionRequestMetrics *metricsOld = self.metricsInfo[regionId];
  280. if (metricsOld) {
  281. [metricsOld addMetrics:metrics];
  282. } else {
  283. [self.metricsKeys addObject:regionId];
  284. self.metricsInfo[regionId] = metrics;
  285. }
  286. }
  287. }
  288. - (NSDictionary<NSString *, QNUploadRegionRequestMetrics *> *)syncCopyMetricsInfo {
  289. @synchronized (self) {
  290. return [_metricsInfo copy];
  291. }
  292. }
  293. @end