Authored by 刘金林

performance report for sdwebimage

@@ -10,8 +10,6 @@ @@ -10,8 +10,6 @@
10 10
11 @interface SDWebImageManager (AutoTrack) 11 @interface SDWebImageManager (AutoTrack)
12 12
13 -@property(nonatomic,copy)NSString *yh_webImageId;//唯一ID  
14 -  
15 +(void)startTrack; 13 +(void)startTrack;
16 14
17 @end 15 @end
@@ -7,87 +7,112 @@ @@ -7,87 +7,112 @@
7 // 7 //
8 8
9 #import "SDWebImageManager+AutoTrack.h" 9 #import "SDWebImageManager+AutoTrack.h"
10 -#import "YHSwizzle.h"  
11 -#import <objc/runtime.h>  
12 -#import <objc/message.h>  
13 -#import "YH_EventCollector.h"  
14 -#import "YHLog.h"  
15 #import "YHEventReport.h" 10 #import "YHEventReport.h"
16 11
  12 +@interface NSNumber (YH_UnitConvert)
17 13
18 -@implementation SDWebImageManager (AutoTrack) 14 +@property (nonatomic, copy, readonly) NSNumber *SToIntMS;//s -> ms 并取整
  15 +
  16 +@end
  17 +
  18 +@implementation NSNumber (YH_UnitConvert)
  19 +
  20 +- (NSNumber *)SToIntMS {
  21 + const double ms = self.doubleValue;
  22 + const double s = ms * 1000;
  23 + return @((NSUInteger)s);
  24 +}
  25 +
  26 +@end
  27 +
  28 +@interface NSURLSessionTaskTransactionMetrics (YH_TrackEvent)
  29 +
  30 +@property (nonatomic, copy, readonly) NSNumber *totalTime;
  31 +@property (nonatomic, copy, readonly) NSNumber *dnsTime;
  32 +@property (nonatomic, copy, readonly) NSNumber *connectTime;
  33 +@property (nonatomic, copy, readonly) NSNumber *secureConnectTime;
  34 +@property (nonatomic, copy, readonly) NSNumber *requestTime;
  35 +@property (nonatomic, copy, readonly) NSNumber *responseTime;
  36 +
  37 +@end
  38 +
  39 +@implementation NSURLSessionTaskTransactionMetrics (YH_TrackEvent)
  40 +
  41 +- (NSNumber *)timeIntervalFromDate:(NSDate *)fromDate toDate:(NSDate *)toDate {
  42 + if (fromDate && toDate &&
  43 + [fromDate compare:toDate] == NSOrderedAscending) {
  44 + return @([toDate timeIntervalSinceDate:fromDate]);
  45 + }
  46 + return @(0.f);
  47 +}
  48 +
  49 +- (NSNumber *)totalTime {
  50 + return [self timeIntervalFromDate:self.fetchStartDate toDate:self.responseEndDate];
  51 +}
19 52
  53 +- (NSNumber *)dnsTime {
  54 + return [self timeIntervalFromDate:self.domainLookupStartDate toDate:self.domainLookupEndDate];
  55 +}
20 56
21 -- (void)setYh_webImageId:(NSString *)yh_webImageId{  
22 - objc_setAssociatedObject(self,@selector(yh_webImageId),yh_webImageId,OBJC_ASSOCIATION_RETAIN); 57 +- (NSNumber *)connectTime {
  58 + return [self timeIntervalFromDate:self.connectStartDate toDate:self.connectEndDate];
23 } 59 }
24 60
25 -- (NSString *)yh_webImageId{  
26 - return objc_getAssociatedObject(self, @selector(yh_webImageId)); 61 +- (NSNumber *)secureConnectTime {
  62 + return [self timeIntervalFromDate:self.secureConnectionStartDate toDate:self.secureConnectionEndDate];
27 } 63 }
28 64
  65 +- (NSNumber *)requestTime {
  66 + return [self timeIntervalFromDate:self.requestStartDate toDate:self.requestEndDate];
  67 +}
  68 +
  69 +- (NSNumber *)responseTime {
  70 + return [self timeIntervalFromDate:self.responseStartDate toDate:self.responseEndDate];
  71 +}
  72 +
  73 +@end
  74 +
  75 +@implementation SDWebImageManager (AutoTrack)
  76 +
29 +(void)startTrack 77 +(void)startTrack
30 { 78 {
31 static dispatch_once_t onceToken; 79 static dispatch_once_t onceToken;
32 dispatch_once(&onceToken, ^{ 80 dispatch_once(&onceToken, ^{
33 - @try {  
34 -  
35 - NSError *downloadImageError = NULL;  
36 - [[self class] yh_swizzleMethod:@selector(downloadImageWithURL:options:progress:completed:)  
37 - withMethod:@selector(yher_downloadImageWithURL:options:progress:completed:)  
38 - error:&downloadImageError];  
39 - if (downloadImageError) {  
40 - downloadImageError = NULL;  
41 - }  
42 -  
43 - } @catch (NSException *exception) {  
44 - YHLog(@"%@ error: %@", self, exception);  
45 - } 81 + [[NSNotificationCenter defaultCenter] addObserverForName:@"yoho_image_download_network_metrics" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
  82 + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  83 + [self reportImageViewPerformanceForNotification:note];
  84 + });
  85 + }];
46 }); 86 });
47 } 87 }
48 88
49 -- (id <SDWebImageOperation>)yher_downloadImageWithURL:(NSURL *)url  
50 - options:(SDWebImageOptions)options  
51 - progress:(SDWebImageDownloaderProgressBlock)progressBlock  
52 - completed:(SDInternalCompletionBlock)completedBlock  
53 -{  
54 - @try {  
55 - if ([url isKindOfClass:NSString.class]) {  
56 - url = [NSURL URLWithString:(NSString *)url];  
57 - }  
58 -  
59 - // Prevents app crashing on argument type error like sending NSNull instead of NSURL  
60 - if ([url isKindOfClass:NSURL.class]) {  
61 - if ([YHEventReport sharedInstance].isPerformanceTrackEnabled && [YHEventReport sharedInstance].isImagePerformanceTrackEnable){  
62 - [[YH_EventCollector sharedInstance] timeEventStartWithWebImageDownloadURL:url.absoluteString];  
63 - }  
64 - }  
65 - } @catch (NSException *exception) {  
66 - YHLog(@"%@ error: %@", self, exception); 89 ++ (void)reportImageViewPerformanceForNotification:(NSNotification *)note {
  90 + NSURLSessionTaskMetrics *metrics = note.userInfo[@"metrics"];
  91 + NSError *error = note.userInfo[@"error"];
  92 + NSParameterAssert([metrics isKindOfClass:[NSURLSessionTaskMetrics class]]);
  93 + if (error.code == NSURLErrorCancelled ) {
  94 + return;
67 } 95 }
68 -  
69 - return [self yher_downloadImageWithURL:url options:options progress:progressBlock completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {  
70 -  
71 - @try {  
72 - if ([url isKindOfClass:NSURL.class]) {  
73 - if ([YHEventReport sharedInstance].isPerformanceTrackEnabled && [YHEventReport sharedInstance].isImagePerformanceTrackEnable){  
74 - if (cacheType == SDImageCacheTypeNone) {//暂时只去下载的图片的时间,过滤掉读缓存的时间  
75 - if (error) {  
76 - [[YH_EventCollector sharedInstance] timeEventEndWithWebImageDownloadURL:url.absoluteString status:YHEventLoadStatusFailed];  
77 - }else{  
78 - [[YH_EventCollector sharedInstance] timeEventEndWithWebImageDownloadURL:url.absoluteString status:YHEventLoadStatusSuc];  
79 - }  
80 - }  
81 - }  
82 - }  
83 - } @catch (NSException *exception) {  
84 - YHLog(@"%@ error: %@", self, exception);  
85 - }  
86 -  
87 - if (completedBlock) {  
88 - completedBlock(image,data,error,cacheType,finished,imageURL); 96 + [metrics.transactionMetrics enumerateObjectsUsingBlock:^(NSURLSessionTaskTransactionMetrics * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  97 + if (obj.resourceFetchType == NSURLSessionTaskMetricsResourceFetchTypeNetworkLoad) {
  98 + [self reportImageDownloadTransactionMetrics:obj];
89 } 99 }
90 }]; 100 }];
91 } 101 }
92 102
  103 ++ (void)reportImageDownloadTransactionMetrics:(NSURLSessionTaskTransactionMetrics *)transMetrics {
  104 + NSDictionary *performanceDict = @{ @"url" : transMetrics.request.URL.absoluteString ?: @"",
  105 + @"protocol": transMetrics.networkProtocolName ?:@"",
  106 + @"proxyConnection": transMetrics.proxyConnection ? @"1" : @"0",
  107 + @"reusedConnection": transMetrics.reusedConnection ? @"1" : @"0",
  108 + @"fetch": transMetrics.totalTime.SToIntMS,
  109 + @"dns": transMetrics.dnsTime.SToIntMS,
  110 + @"connect": transMetrics.connectTime.SToIntMS,
  111 + @"secureConnection": transMetrics.secureConnectTime.SToIntMS,
  112 + @"request": transMetrics.requestTime.SToIntMS,
  113 + @"response": transMetrics.responseTime.SToIntMS
  114 + };
  115 + [[YHEventReport sharedInstance] reportWithPointType:YHPT_PERFORMANCE pointName:YHPN_IMAGEVIEW parameters:performanceDict];
  116 +}
  117 +
93 @end 118 @end