From cb20a7a08b5b292dc23f17094b1bdac3dedf11f0 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Thu, 20 Oct 2022 16:41:16 +0200 Subject: [PATCH 01/18] HTTP Client errors --- .../ProfileDataGeneratorUITest.xcscheme | 2 +- .../xcschemes/TrendingMovies.xcscheme | 2 +- .../xcschemes/iOS-ObjectiveC.xcscheme | 2 +- .../xcschemes/iOS-Swift-Benchmarking.xcscheme | 2 +- .../xcshareddata/xcschemes/iOS-Swift.xcscheme | 2 +- .../xcschemes/iOS-SwiftClip.xcscheme | 2 +- .../xcschemes/iOS-SwiftUITests.xcscheme | 2 +- Samples/iOS-Swift/iOS-Swift/AppDelegate.swift | 1 + .../xcschemes/iOS-SwiftUI.xcscheme | 2 +- .../xcschemes/macOS-Swift.xcscheme | 2 +- .../xcschemes/tvOS-Swift.xcscheme | 2 +- Sentry.xcodeproj/project.pbxproj | 10 +- .../xcshareddata/xcschemes/Sentry.xcscheme | 2 +- Sources/Sentry/Public/SentryEvent.h | 7 +- Sources/Sentry/Public/SentryOptions.h | 6 ++ Sources/Sentry/Public/SentryStacktrace.h | 5 + Sources/Sentry/SentryEvent.m | 5 + Sources/Sentry/SentryNetworkTracker.m | 94 ++++++++++++++++++- .../Sentry/SentryNetworkTrackingIntegration.m | 6 +- Sources/Sentry/SentryOptions.m | 4 + Sources/Sentry/SentryRequest.h | 55 +++++++++++ Sources/Sentry/SentryRequest.m | 51 ++++++++++ Sources/Sentry/SentryStacktrace.m | 2 + Sources/Sentry/include/SentryNetworkTracker.h | 2 + 24 files changed, 255 insertions(+), 15 deletions(-) create mode 100644 Sources/Sentry/SentryRequest.h create mode 100644 Sources/Sentry/SentryRequest.m diff --git a/Samples/TrendingMovies/TrendingMovies.xcodeproj/xcshareddata/xcschemes/ProfileDataGeneratorUITest.xcscheme b/Samples/TrendingMovies/TrendingMovies.xcodeproj/xcshareddata/xcschemes/ProfileDataGeneratorUITest.xcscheme index fc186453333..37c5bba9acc 100644 --- a/Samples/TrendingMovies/TrendingMovies.xcodeproj/xcshareddata/xcschemes/ProfileDataGeneratorUITest.xcscheme +++ b/Samples/TrendingMovies/TrendingMovies.xcodeproj/xcshareddata/xcschemes/ProfileDataGeneratorUITest.xcscheme @@ -1,6 +1,6 @@ @@ -159,6 +159,11 @@ NS_SWIFT_NAME(Event) */ @property (nonatomic, strong) NSArray *_Nullable breadcrumbs; +/** + * Set the Http request information. + */ +@property (nonatomic, strong) SentryRequest *_Nullable request; + /** * Init an SentryEvent will set all needed fields by default * @return SentryEvent diff --git a/Sources/Sentry/Public/SentryOptions.h b/Sources/Sentry/Public/SentryOptions.h index 37229734120..2e2cdc29a2b 100644 --- a/Sources/Sentry/Public/SentryOptions.h +++ b/Sources/Sentry/Public/SentryOptions.h @@ -414,6 +414,12 @@ NS_SWIFT_NAME(Options) */ @property (nonatomic, retain) NSArray *tracePropagationTargets; + +/** + * When enabled, the SDK captures HTTP Client errors. Default value is NO. + */ +@property (nonatomic, assign) BOOL enableCaptureFailedRequests; + @end NS_ASSUME_NONNULL_END diff --git a/Sources/Sentry/Public/SentryStacktrace.h b/Sources/Sentry/Public/SentryStacktrace.h index e8c67d83f41..43e0e762d1a 100644 --- a/Sources/Sentry/Public/SentryStacktrace.h +++ b/Sources/Sentry/Public/SentryStacktrace.h @@ -21,6 +21,11 @@ SENTRY_NO_INIT */ @property (nonatomic, strong) NSDictionary *registers; +/** + * Indicates that this stack trace is a snapshot triggered by an external signal. + */ +@property (nonatomic, copy) NSNumber *_Nullable snapshot; + /** * Initialize a SentryStacktrace with frames and registers * @param frames NSArray diff --git a/Sources/Sentry/SentryEvent.m b/Sources/Sentry/SentryEvent.m index 243f9405c51..ffb89e6f05c 100644 --- a/Sources/Sentry/SentryEvent.m +++ b/Sources/Sentry/SentryEvent.m @@ -2,6 +2,7 @@ #import "NSDate+SentryExtras.h" #import "NSDictionary+SentrySanitize.h" #import "SentryBreadcrumb.h" +#import "SentryRequest.h" #import "SentryClient.h" #import "SentryCurrentDate.h" #import "SentryDebugMeta.h" @@ -157,6 +158,10 @@ - (void)addSimpleProperties:(NSMutableDictionary *)serializedData forKey:@"start_timestamp"]; } } + + if (nil != self.request) { + [serializedData setValue:[self.request serialize] forKey:@"request"]; + } } - (NSArray *_Nullable)serializeBreadcrumbs diff --git a/Sources/Sentry/SentryNetworkTracker.m b/Sources/Sentry/SentryNetworkTracker.m index b3ef917b83c..43cafd6cc88 100644 --- a/Sources/Sentry/SentryNetworkTracker.m +++ b/Sources/Sentry/SentryNetworkTracker.m @@ -1,7 +1,15 @@ #import "SentryNetworkTracker.h" #import "SentryBaggage.h" #import "SentryBreadcrumb.h" +#import "SentryEvent.h" +#import "SentryException.h" +#import "SentryMechanism.h" +#import "SentryRequest.h" +#import "SentryStacktrace.h" +#import "SentryThread.h" #import "SentryHub+Private.h" +#import "SentryClient+Private.h" +#import "SentryThreadInspector.h" #import "SentryLog.h" #import "SentrySDK+Private.h" #import "SentryScope+Private.h" @@ -16,6 +24,7 @@ @property (nonatomic, assign) BOOL isNetworkTrackingEnabled; @property (nonatomic, assign) BOOL isNetworkBreadcrumbEnabled; +@property (nonatomic, assign) BOOL isCaptureFailedRequests; @end @@ -34,6 +43,7 @@ - (instancetype)init if (self = [super init]) { _isNetworkTrackingEnabled = NO; _isNetworkBreadcrumbEnabled = NO; + _isCaptureFailedRequests = NO; } return self; } @@ -52,11 +62,19 @@ - (void)enableNetworkBreadcrumbs } } +- (void)enableCaptureFailedRequests +{ + @synchronized(self) { + _isCaptureFailedRequests = YES; + } +} + - (void)disable { @synchronized(self) { _isNetworkBreadcrumbEnabled = NO; _isNetworkTrackingEnabled = NO; + _isCaptureFailedRequests = NO; } } @@ -206,7 +224,7 @@ - (void)urlSessionTaskResume:(NSURLSessionTask *)sessionTask - (void)urlSessionTask:(NSURLSessionTask *)sessionTask setState:(NSURLSessionTaskState)newState { - if (!self.isNetworkTrackingEnabled && !self.isNetworkBreadcrumbEnabled) { + if (!self.isNetworkTrackingEnabled && !self.isNetworkBreadcrumbEnabled && !self.isCaptureFailedRequests) { return; } @@ -239,6 +257,8 @@ - (void)urlSessionTask:(NSURLSessionTask *)sessionTask setState:(NSURLSessionTas } if (sessionTask.state == NSURLSessionTaskStateRunning) { + [self captureEvent:sessionTask]; + [self addBreadcrumbForSessionTask:sessionTask]; NSInteger responseStatusCode = [self urlResponseStatusCode:sessionTask.response]; @@ -265,6 +285,78 @@ - (void)urlSessionTask:(NSURLSessionTask *)sessionTask setState:(NSURLSessionTas SENTRY_LOG_DEBUG(@"SentryNetworkTracker finished HTTP span for sessionTask"); } +- (void)captureEvent:(NSURLSessionTask *)sessionTask +{ + NSInteger responseStatusCode = [self urlResponseStatusCode:sessionTask.response]; + + // TODO: check the string contains and regex + if (!self.isCaptureFailedRequests) { + return; + } + + // TODO: check the range + if (responseStatusCode == 201) { + return; + } + + NSString *message = [NSString stringWithFormat:@"HTTP Client Error with status code: %li", + (long)(responseStatusCode)]; + + SentryEvent *event = [[SentryEvent alloc] initWithLevel:kSentryLevelError]; + + SentryThreadInspector *threadInspector = SentrySDK.currentHub.getClient.threadInspector; + NSArray *threads = [threadInspector getCurrentThreadsWithStackTrace]; + + SentryException *sentryException = [[SentryException alloc] initWithValue:message + type:@"HTTP-ClientError"]; + sentryException.mechanism = [[SentryMechanism alloc] initWithType:@"SentryNetworkTrackingIntegration"]; + + + SentryStacktrace *sentryStacktrace = [threads[0] stacktrace]; + sentryStacktrace.snapshot = @(YES); + + sentryException.stacktrace = sentryStacktrace; + // TODO: do I need this? +// [threads enumerateObjectsUsingBlock:^(SentryThread *_Nonnull obj, NSUInteger idx, +// BOOL *_Nonnull stop) { obj.current = [NSNumber numberWithBool:idx == 0]; }]; + + SentryRequest *request = [[SentryRequest alloc] init]; + + NSURLRequest *myRequest = (NSURLRequest *)sessionTask.currentRequest; + + NSURL *url = [[sessionTask currentRequest] URL]; + request.url = url.absoluteString; + + request.fragment = url.fragment; + request.queryString = url.query; + request.method = myRequest.HTTPMethod; + request.bodySize = [NSNumber numberWithLongLong:sessionTask.countOfBytesSent]; + request.headers = myRequest.allHTTPHeaderFields.copy; + request.cookies = myRequest.allHTTPHeaderFields[@"Cookie"]; + + event.exceptions = @[ sentryException ]; + event.request = request; + + NSHTTPURLResponse *myResponse = (NSHTTPURLResponse *)sessionTask.response; + + NSMutableDictionary *newContext; + if (nil == event.context) { + newContext = [[NSMutableDictionary alloc] init]; + } else { + newContext = event.context.mutableCopy; + } + NSMutableDictionary *response = [[NSMutableDictionary alloc] init]; + [response setValue:[NSNumber numberWithLongLong:responseStatusCode] forKey:@"status_code"]; + [response setValue:myResponse.allHeaderFields.copy forKey:@"headers"]; + [response setValue:myResponse.allHeaderFields[@"Cookie"] forKey:@"cookies"]; + [response setValue:[NSNumber numberWithLongLong:sessionTask.countOfBytesReceived] forKey:@"body_size"]; + + newContext[@"response"] = response; + event.context = newContext; + + [SentrySDK captureEvent:event]; +} + - (void)addBreadcrumbForSessionTask:(NSURLSessionTask *)sessionTask { if (!self.isNetworkBreadcrumbEnabled) { diff --git a/Sources/Sentry/SentryNetworkTrackingIntegration.m b/Sources/Sentry/SentryNetworkTrackingIntegration.m index ee006406e05..36488fe33e3 100644 --- a/Sources/Sentry/SentryNetworkTrackingIntegration.m +++ b/Sources/Sentry/SentryNetworkTrackingIntegration.m @@ -24,8 +24,12 @@ - (BOOL)installWithOptions:(SentryOptions *)options if (options.enableNetworkBreadcrumbs) { [SentryNetworkTracker.sharedInstance enableNetworkBreadcrumbs]; } + + if (options.enableCaptureFailedRequests) { + [SentryNetworkTracker.sharedInstance enableCaptureFailedRequests]; + } - if (shouldEnableNetworkTracking || options.enableNetworkBreadcrumbs) { + if (shouldEnableNetworkTracking || options.enableNetworkBreadcrumbs || options.enableCaptureFailedRequests) { [SentryNetworkTrackingIntegration swizzleURLSessionTask]; return YES; } else { diff --git a/Sources/Sentry/SentryOptions.m b/Sources/Sentry/SentryOptions.m index 8f9bc0b5036..fe814094de3 100644 --- a/Sources/Sentry/SentryOptions.m +++ b/Sources/Sentry/SentryOptions.m @@ -60,6 +60,7 @@ - (instancetype)init self.maxAttachmentSize = 20 * 1024 * 1024; self.sendDefaultPii = NO; self.enableAutoPerformanceTracking = YES; + self.enableCaptureFailedRequests = NO; #if SENTRY_HAS_UIKIT self.enableUIViewControllerTracking = YES; self.attachScreenshot = NO; @@ -269,6 +270,9 @@ - (BOOL)validateOptions:(NSDictionary *)options [self setBool:options[@"enableAutoPerformanceTracking"] block:^(BOOL value) { self->_enableAutoPerformanceTracking = value; }]; + + [self setBool:options[@"enableCaptureFailedRequests"] + block:^(BOOL value) { self->_enableCaptureFailedRequests = value; }]; #if SENTRY_HAS_UIKIT [self setBool:options[@"enableUIViewControllerTracking"] diff --git a/Sources/Sentry/SentryRequest.h b/Sources/Sentry/SentryRequest.h new file mode 100644 index 00000000000..23e55e1a242 --- /dev/null +++ b/Sources/Sentry/SentryRequest.h @@ -0,0 +1,55 @@ +#import "SentryDefines.h" +#import "SentrySerializable.h" + +NS_ASSUME_NONNULL_BEGIN + +NS_SWIFT_NAME(Request) +@interface SentryRequest : NSObject + +// TODO: data, env + +/** + * Optional: HTTP response body size. + */ +@property (atomic, copy) NSNumber *_Nullable bodySize; + +/** + * Optional: The cookie values. + */ +@property (atomic, copy) NSString *_Nullable cookies; + +/** +* Optional: A dictionary of submitted headers. +*/ +@property (nonatomic, strong) NSDictionary *_Nullable headers; + +/** + * Optional: The fragment of the request URL. + */ +@property (atomic, copy) NSString *_Nullable fragment; + +/** + * Optional: HTTP request method. + */ +@property (atomic, copy) NSString *_Nullable method; + +/** + * Optional: The query string component of the URL. + */ +@property (atomic, copy) NSString *_Nullable queryString; + +/** + * Optional: The URL of the request if available. + */ +@property (atomic, copy) NSString *_Nullable url; + +///** +// * Optional: HTTP status code. +// */ +//@property (atomic, copy) NSNumber *_Nullable statusCode; + +- (instancetype)init; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Sources/Sentry/SentryRequest.m b/Sources/Sentry/SentryRequest.m new file mode 100644 index 00000000000..42edb8ce533 --- /dev/null +++ b/Sources/Sentry/SentryRequest.m @@ -0,0 +1,51 @@ +#import "SentryRequest.h" +#import "NSDictionary+SentrySanitize.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation SentryRequest + +- (instancetype)init +{ + return [super init]; +} + +- (NSDictionary *)serialize +{ + NSMutableDictionary *serializedData = [[NSMutableDictionary alloc] init]; + + @synchronized(self) { + [serializedData setValue:self.bodySize forKey:@"body_size"]; + [serializedData setValue:self.cookies forKey:@"cookies"]; + [serializedData setValue:self.fragment forKey:@"fragment"]; + [serializedData setValue:[self.headers sentry_sanitize] forKey:@"headers"]; + [serializedData setValue:self.method forKey:@"method"]; + [serializedData setValue:self.queryString forKey:@"query_string"]; + [serializedData setValue:self.url forKey:@"url"]; + } + + return serializedData; +} + +- (id)copyWithZone:(nullable NSZone *)zone +{ + SentryRequest *copy = [[SentryRequest allocWithZone:zone] init]; + + @synchronized(self) { + if (copy != nil) { + copy.bodySize = self.bodySize; + copy.cookies = self.cookies; + copy.fragment = self.fragment; + copy.method = self.method; + copy.queryString = self.queryString; + copy.url = self.url; + copy.headers = self.headers.copy; + } + } + + return copy; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Sources/Sentry/SentryStacktrace.m b/Sources/Sentry/SentryStacktrace.m index 49e6211da91..59d73d4e02d 100644 --- a/Sources/Sentry/SentryStacktrace.m +++ b/Sources/Sentry/SentryStacktrace.m @@ -55,6 +55,8 @@ - (void)fixDuplicateFrames if (self.registers.count > 0) { [serializedData setValue:self.registers forKey:@"registers"]; } + [serializedData setValue:self.snapshot forKey:@"snapshot"]; + return serializedData; } diff --git a/Sources/Sentry/include/SentryNetworkTracker.h b/Sources/Sentry/include/SentryNetworkTracker.h index c1758d5bcd5..204a80015d7 100644 --- a/Sources/Sentry/include/SentryNetworkTracker.h +++ b/Sources/Sentry/include/SentryNetworkTracker.h @@ -15,11 +15,13 @@ static NSString *const SENTRY_NETWORK_REQUEST_TRACKER_SPAN = @"SENTRY_NETWORK_RE - (void)urlSessionTask:(NSURLSessionTask *)sessionTask setState:(NSURLSessionTaskState)newState; - (void)enableNetworkTracking; - (void)enableNetworkBreadcrumbs; +- (void)enableCaptureFailedRequests; - (BOOL)addHeadersForRequestWithURL:(NSURL *)URL; - (void)disable; @property (nonatomic, readonly) BOOL isNetworkTrackingEnabled; @property (nonatomic, readonly) BOOL isNetworkBreadcrumbEnabled; +@property (nonatomic, readonly) BOOL isCaptureFailedRequests; @end From 068b12d2745651bc6d0abb8221f041311dc1f19d Mon Sep 17 00:00:00 2001 From: Sentry Github Bot Date: Thu, 20 Oct 2022 14:42:39 +0000 Subject: [PATCH 02/18] Format code --- Sources/Sentry/Public/SentryOptions.h | 1 - Sources/Sentry/SentryEvent.m | 4 +- Sources/Sentry/SentryNetworkTracker.m | 54 ++++++++++--------- .../Sentry/SentryNetworkTrackingIntegration.m | 5 +- Sources/Sentry/SentryOptions.m | 2 +- Sources/Sentry/SentryRequest.h | 4 +- Sources/Sentry/SentryStacktrace.m | 2 +- 7 files changed, 37 insertions(+), 35 deletions(-) diff --git a/Sources/Sentry/Public/SentryOptions.h b/Sources/Sentry/Public/SentryOptions.h index 2e2cdc29a2b..a99ef040610 100644 --- a/Sources/Sentry/Public/SentryOptions.h +++ b/Sources/Sentry/Public/SentryOptions.h @@ -414,7 +414,6 @@ NS_SWIFT_NAME(Options) */ @property (nonatomic, retain) NSArray *tracePropagationTargets; - /** * When enabled, the SDK captures HTTP Client errors. Default value is NO. */ diff --git a/Sources/Sentry/SentryEvent.m b/Sources/Sentry/SentryEvent.m index ffb89e6f05c..9c9416f0ff1 100644 --- a/Sources/Sentry/SentryEvent.m +++ b/Sources/Sentry/SentryEvent.m @@ -2,7 +2,6 @@ #import "NSDate+SentryExtras.h" #import "NSDictionary+SentrySanitize.h" #import "SentryBreadcrumb.h" -#import "SentryRequest.h" #import "SentryClient.h" #import "SentryCurrentDate.h" #import "SentryDebugMeta.h" @@ -11,6 +10,7 @@ #import "SentryLevelMapper.h" #import "SentryMessage.h" #import "SentryMeta.h" +#import "SentryRequest.h" #import "SentryStacktrace.h" #import "SentryThread.h" #import "SentryUser.h" @@ -158,7 +158,7 @@ - (void)addSimpleProperties:(NSMutableDictionary *)serializedData forKey:@"start_timestamp"]; } } - + if (nil != self.request) { [serializedData setValue:[self.request serialize] forKey:@"request"]; } diff --git a/Sources/Sentry/SentryNetworkTracker.m b/Sources/Sentry/SentryNetworkTracker.m index 43cafd6cc88..45bfb3890ba 100644 --- a/Sources/Sentry/SentryNetworkTracker.m +++ b/Sources/Sentry/SentryNetworkTracker.m @@ -1,19 +1,19 @@ #import "SentryNetworkTracker.h" #import "SentryBaggage.h" #import "SentryBreadcrumb.h" +#import "SentryClient+Private.h" #import "SentryEvent.h" #import "SentryException.h" -#import "SentryMechanism.h" -#import "SentryRequest.h" -#import "SentryStacktrace.h" -#import "SentryThread.h" #import "SentryHub+Private.h" -#import "SentryClient+Private.h" -#import "SentryThreadInspector.h" #import "SentryLog.h" +#import "SentryMechanism.h" +#import "SentryRequest.h" #import "SentrySDK+Private.h" #import "SentryScope+Private.h" #import "SentrySerialization.h" +#import "SentryStacktrace.h" +#import "SentryThread.h" +#import "SentryThreadInspector.h" #import "SentryTraceContext.h" #import "SentryTraceHeader.h" #import "SentryTracer.h" @@ -224,7 +224,8 @@ - (void)urlSessionTaskResume:(NSURLSessionTask *)sessionTask - (void)urlSessionTask:(NSURLSessionTask *)sessionTask setState:(NSURLSessionTaskState)newState { - if (!self.isNetworkTrackingEnabled && !self.isNetworkBreadcrumbEnabled && !self.isCaptureFailedRequests) { + if (!self.isNetworkTrackingEnabled && !self.isNetworkBreadcrumbEnabled + && !self.isCaptureFailedRequests) { return; } @@ -258,7 +259,7 @@ - (void)urlSessionTask:(NSURLSessionTask *)sessionTask setState:(NSURLSessionTas if (sessionTask.state == NSURLSessionTaskStateRunning) { [self captureEvent:sessionTask]; - + [self addBreadcrumbForSessionTask:sessionTask]; NSInteger responseStatusCode = [self urlResponseStatusCode:sessionTask.response]; @@ -288,45 +289,45 @@ - (void)urlSessionTask:(NSURLSessionTask *)sessionTask setState:(NSURLSessionTas - (void)captureEvent:(NSURLSessionTask *)sessionTask { NSInteger responseStatusCode = [self urlResponseStatusCode:sessionTask.response]; - + // TODO: check the string contains and regex if (!self.isCaptureFailedRequests) { return; } - + // TODO: check the range if (responseStatusCode == 201) { return; } - - NSString *message = [NSString stringWithFormat:@"HTTP Client Error with status code: %li", - (long)(responseStatusCode)]; + + NSString *message = [NSString + stringWithFormat:@"HTTP Client Error with status code: %li", (long)(responseStatusCode)]; SentryEvent *event = [[SentryEvent alloc] initWithLevel:kSentryLevelError]; - + SentryThreadInspector *threadInspector = SentrySDK.currentHub.getClient.threadInspector; NSArray *threads = [threadInspector getCurrentThreadsWithStackTrace]; - + SentryException *sentryException = [[SentryException alloc] initWithValue:message type:@"HTTP-ClientError"]; - sentryException.mechanism = [[SentryMechanism alloc] initWithType:@"SentryNetworkTrackingIntegration"]; - - + sentryException.mechanism = + [[SentryMechanism alloc] initWithType:@"SentryNetworkTrackingIntegration"]; + SentryStacktrace *sentryStacktrace = [threads[0] stacktrace]; sentryStacktrace.snapshot = @(YES); - + sentryException.stacktrace = sentryStacktrace; // TODO: do I need this? -// [threads enumerateObjectsUsingBlock:^(SentryThread *_Nonnull obj, NSUInteger idx, -// BOOL *_Nonnull stop) { obj.current = [NSNumber numberWithBool:idx == 0]; }]; - + // [threads enumerateObjectsUsingBlock:^(SentryThread *_Nonnull obj, NSUInteger idx, + // BOOL *_Nonnull stop) { obj.current = [NSNumber numberWithBool:idx == 0]; }]; + SentryRequest *request = [[SentryRequest alloc] init]; NSURLRequest *myRequest = (NSURLRequest *)sessionTask.currentRequest; NSURL *url = [[sessionTask currentRequest] URL]; request.url = url.absoluteString; - + request.fragment = url.fragment; request.queryString = url.query; request.method = myRequest.HTTPMethod; @@ -336,7 +337,7 @@ - (void)captureEvent:(NSURLSessionTask *)sessionTask event.exceptions = @[ sentryException ]; event.request = request; - + NSHTTPURLResponse *myResponse = (NSHTTPURLResponse *)sessionTask.response; NSMutableDictionary *newContext; @@ -349,8 +350,9 @@ - (void)captureEvent:(NSURLSessionTask *)sessionTask [response setValue:[NSNumber numberWithLongLong:responseStatusCode] forKey:@"status_code"]; [response setValue:myResponse.allHeaderFields.copy forKey:@"headers"]; [response setValue:myResponse.allHeaderFields[@"Cookie"] forKey:@"cookies"]; - [response setValue:[NSNumber numberWithLongLong:sessionTask.countOfBytesReceived] forKey:@"body_size"]; - + [response setValue:[NSNumber numberWithLongLong:sessionTask.countOfBytesReceived] + forKey:@"body_size"]; + newContext[@"response"] = response; event.context = newContext; diff --git a/Sources/Sentry/SentryNetworkTrackingIntegration.m b/Sources/Sentry/SentryNetworkTrackingIntegration.m index 36488fe33e3..3f0a5ba5a70 100644 --- a/Sources/Sentry/SentryNetworkTrackingIntegration.m +++ b/Sources/Sentry/SentryNetworkTrackingIntegration.m @@ -24,12 +24,13 @@ - (BOOL)installWithOptions:(SentryOptions *)options if (options.enableNetworkBreadcrumbs) { [SentryNetworkTracker.sharedInstance enableNetworkBreadcrumbs]; } - + if (options.enableCaptureFailedRequests) { [SentryNetworkTracker.sharedInstance enableCaptureFailedRequests]; } - if (shouldEnableNetworkTracking || options.enableNetworkBreadcrumbs || options.enableCaptureFailedRequests) { + if (shouldEnableNetworkTracking || options.enableNetworkBreadcrumbs + || options.enableCaptureFailedRequests) { [SentryNetworkTrackingIntegration swizzleURLSessionTask]; return YES; } else { diff --git a/Sources/Sentry/SentryOptions.m b/Sources/Sentry/SentryOptions.m index fe814094de3..8ee387b9ca1 100644 --- a/Sources/Sentry/SentryOptions.m +++ b/Sources/Sentry/SentryOptions.m @@ -270,7 +270,7 @@ - (BOOL)validateOptions:(NSDictionary *)options [self setBool:options[@"enableAutoPerformanceTracking"] block:^(BOOL value) { self->_enableAutoPerformanceTracking = value; }]; - + [self setBool:options[@"enableCaptureFailedRequests"] block:^(BOOL value) { self->_enableCaptureFailedRequests = value; }]; diff --git a/Sources/Sentry/SentryRequest.h b/Sources/Sentry/SentryRequest.h index 23e55e1a242..3e85ebaa110 100644 --- a/Sources/Sentry/SentryRequest.h +++ b/Sources/Sentry/SentryRequest.h @@ -19,8 +19,8 @@ NS_SWIFT_NAME(Request) @property (atomic, copy) NSString *_Nullable cookies; /** -* Optional: A dictionary of submitted headers. -*/ + * Optional: A dictionary of submitted headers. + */ @property (nonatomic, strong) NSDictionary *_Nullable headers; /** diff --git a/Sources/Sentry/SentryStacktrace.m b/Sources/Sentry/SentryStacktrace.m index 59d73d4e02d..ccf6a7d1232 100644 --- a/Sources/Sentry/SentryStacktrace.m +++ b/Sources/Sentry/SentryStacktrace.m @@ -56,7 +56,7 @@ - (void)fixDuplicateFrames [serializedData setValue:self.registers forKey:@"registers"]; } [serializedData setValue:self.snapshot forKey:@"snapshot"]; - + return serializedData; } From a04d660d5412ce33860cec17063e2c4df77297aa Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Thu, 20 Oct 2022 16:44:11 +0200 Subject: [PATCH 03/18] fix --- Sources/Sentry/SentryRequest.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Sources/Sentry/SentryRequest.h b/Sources/Sentry/SentryRequest.h index 23e55e1a242..b788f9adfe5 100644 --- a/Sources/Sentry/SentryRequest.h +++ b/Sources/Sentry/SentryRequest.h @@ -43,11 +43,6 @@ NS_SWIFT_NAME(Request) */ @property (atomic, copy) NSString *_Nullable url; -///** -// * Optional: HTTP status code. -// */ -//@property (atomic, copy) NSNumber *_Nullable statusCode; - - (instancetype)init; @end From db88adc07f718d3e9332e52bcc9f58c278761047 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Fri, 21 Oct 2022 08:56:32 +0200 Subject: [PATCH 04/18] fixes --- Sources/Sentry/SentryNetworkTracker.m | 52 +++++++++++++++------------ 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/Sources/Sentry/SentryNetworkTracker.m b/Sources/Sentry/SentryNetworkTracker.m index 43cafd6cc88..011def8975b 100644 --- a/Sources/Sentry/SentryNetworkTracker.m +++ b/Sources/Sentry/SentryNetworkTracker.m @@ -312,13 +312,15 @@ - (void)captureEvent:(NSURLSessionTask *)sessionTask sentryException.mechanism = [[SentryMechanism alloc] initWithType:@"SentryNetworkTrackingIntegration"]; - SentryStacktrace *sentryStacktrace = [threads[0] stacktrace]; - sentryStacktrace.snapshot = @(YES); - - sentryException.stacktrace = sentryStacktrace; - // TODO: do I need this? -// [threads enumerateObjectsUsingBlock:^(SentryThread *_Nonnull obj, NSUInteger idx, -// BOOL *_Nonnull stop) { obj.current = [NSNumber numberWithBool:idx == 0]; }]; + if (threads.count > 0) { + SentryStacktrace *sentryStacktrace = [threads[0] stacktrace]; + sentryStacktrace.snapshot = @(YES); + + sentryException.stacktrace = sentryStacktrace; + // TODO: do I need this? + // [threads enumerateObjectsUsingBlock:^(SentryThread *_Nonnull obj, NSUInteger idx, + // BOOL *_Nonnull stop) { obj.current = [NSNumber numberWithBool:idx == 0]; }]; + } SentryRequest *request = [[SentryRequest alloc] init]; @@ -330,29 +332,35 @@ - (void)captureEvent:(NSURLSessionTask *)sessionTask request.fragment = url.fragment; request.queryString = url.query; request.method = myRequest.HTTPMethod; - request.bodySize = [NSNumber numberWithLongLong:sessionTask.countOfBytesSent]; - request.headers = myRequest.allHTTPHeaderFields.copy; - request.cookies = myRequest.allHTTPHeaderFields[@"Cookie"]; + if (sessionTask.countOfBytesSent != 0) { + request.bodySize = [NSNumber numberWithLongLong:sessionTask.countOfBytesSent]; + } + if (nil != myRequest.allHTTPHeaderFields) { + NSDictionary *headers = myRequest.allHTTPHeaderFields.copy; + request.headers = headers; + request.cookies = headers[@"Cookie"]; + } event.exceptions = @[ sentryException ]; event.request = request; NSHTTPURLResponse *myResponse = (NSHTTPURLResponse *)sessionTask.response; - NSMutableDictionary *newContext; - if (nil == event.context) { - newContext = [[NSMutableDictionary alloc] init]; - } else { - newContext = event.context.mutableCopy; - } - NSMutableDictionary *response = [[NSMutableDictionary alloc] init]; + NSMutableDictionary *context = [[NSMutableDictionary alloc] init];; + NSMutableDictionary *response = [[NSMutableDictionary alloc] init]; + [response setValue:[NSNumber numberWithLongLong:responseStatusCode] forKey:@"status_code"]; - [response setValue:myResponse.allHeaderFields.copy forKey:@"headers"]; - [response setValue:myResponse.allHeaderFields[@"Cookie"] forKey:@"cookies"]; - [response setValue:[NSNumber numberWithLongLong:sessionTask.countOfBytesReceived] forKey:@"body_size"]; + if (nil != myResponse.allHeaderFields) { + NSDictionary *headers = myResponse.allHeaderFields.copy; + [response setValue:headers forKey:@"headers"]; + [response setValue:headers[@"Cookie"] forKey:@"cookies"]; + } + if (sessionTask.countOfBytesReceived != 0) { + [response setValue:[NSNumber numberWithLongLong:sessionTask.countOfBytesReceived] forKey:@"body_size"]; + } - newContext[@"response"] = response; - event.context = newContext; + context[@"response"] = response; + event.context = context; [SentrySDK captureEvent:event]; } From 4bf027c201eeb9d01035ea52bece0bb78e136ee5 Mon Sep 17 00:00:00 2001 From: Sentry Github Bot Date: Fri, 21 Oct 2022 07:12:05 +0000 Subject: [PATCH 05/18] Format code --- Sources/Sentry/SentryNetworkTracker.m | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Sources/Sentry/SentryNetworkTracker.m b/Sources/Sentry/SentryNetworkTracker.m index 9a8a9d4fde9..331c0ca2ba0 100644 --- a/Sources/Sentry/SentryNetworkTracker.m +++ b/Sources/Sentry/SentryNetworkTracker.m @@ -310,12 +310,13 @@ - (void)captureEvent:(NSURLSessionTask *)sessionTask SentryException *sentryException = [[SentryException alloc] initWithValue:message type:@"HTTP-ClientError"]; - sentryException.mechanism = [[SentryMechanism alloc] initWithType:@"SentryNetworkTrackingIntegration"]; - + sentryException.mechanism = + [[SentryMechanism alloc] initWithType:@"SentryNetworkTrackingIntegration"]; + if (threads.count > 0) { SentryStacktrace *sentryStacktrace = [threads[0] stacktrace]; sentryStacktrace.snapshot = @(YES); - + sentryException.stacktrace = sentryStacktrace; // TODO: do I need this? // [threads enumerateObjectsUsingBlock:^(SentryThread *_Nonnull obj, NSUInteger idx, @@ -346,7 +347,8 @@ - (void)captureEvent:(NSURLSessionTask *)sessionTask NSHTTPURLResponse *myResponse = (NSHTTPURLResponse *)sessionTask.response; - NSMutableDictionary *context = [[NSMutableDictionary alloc] init];; + NSMutableDictionary *context = [[NSMutableDictionary alloc] init]; + ; NSMutableDictionary *response = [[NSMutableDictionary alloc] init]; [response setValue:[NSNumber numberWithLongLong:responseStatusCode] forKey:@"status_code"]; @@ -356,9 +358,10 @@ - (void)captureEvent:(NSURLSessionTask *)sessionTask [response setValue:headers[@"Cookie"] forKey:@"cookies"]; } if (sessionTask.countOfBytesReceived != 0) { - [response setValue:[NSNumber numberWithLongLong:sessionTask.countOfBytesReceived] forKey:@"body_size"]; + [response setValue:[NSNumber numberWithLongLong:sessionTask.countOfBytesReceived] + forKey:@"body_size"]; } - + context[@"response"] = response; event.context = context; From 0587c63e28360c47812ce83a7a0027d0b95abaf5 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Fri, 21 Oct 2022 11:43:07 +0200 Subject: [PATCH 06/18] refactoring --- Sentry.xcodeproj/project.pbxproj | 8 ++++ Sources/Sentry/HttpStatusCodeRange.h | 13 +++++++ Sources/Sentry/Public/SentryOptions.h | 19 +++++++++- Sources/Sentry/SentryHttpStatusCodeRange.h | 20 ++++++++++ Sources/Sentry/SentryHttpStatusCodeRange.m | 29 +++++++++++++++ Sources/Sentry/SentryNetworkTracker.m | 37 ++++++++++++------- Sources/Sentry/SentryOptions.m | 36 ++++++++++++++++++ Sources/Sentry/include/SentryNetworkTracker.h | 3 +- 8 files changed, 150 insertions(+), 15 deletions(-) create mode 100644 Sources/Sentry/HttpStatusCodeRange.h create mode 100644 Sources/Sentry/SentryHttpStatusCodeRange.h create mode 100644 Sources/Sentry/SentryHttpStatusCodeRange.m diff --git a/Sentry.xcodeproj/project.pbxproj b/Sentry.xcodeproj/project.pbxproj index ab62106f42c..ff48ed9af1b 100644 --- a/Sentry.xcodeproj/project.pbxproj +++ b/Sentry.xcodeproj/project.pbxproj @@ -663,6 +663,8 @@ A839D89A24864BA8003B7AFD /* SentrySystemEventBreadcrumbs.m in Sources */ = {isa = PBXBuildFile; fileRef = A839D89924864BA8003B7AFD /* SentrySystemEventBreadcrumbs.m */; }; A8F17B2C29016BD100990B25 /* SentryRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = A8F17B2B29016BD100990B25 /* SentryRequest.h */; }; A8F17B2E2901765900990B25 /* SentryRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = A8F17B2D2901765900990B25 /* SentryRequest.m */; }; + A8F17B32290283C100990B25 /* SentryHttpStatusCodeRange.h in Headers */ = {isa = PBXBuildFile; fileRef = A8F17B31290283C100990B25 /* SentryHttpStatusCodeRange.h */; }; + A8F17B342902870300990B25 /* SentryHttpStatusCodeRange.m in Sources */ = {isa = PBXBuildFile; fileRef = A8F17B332902870300990B25 /* SentryHttpStatusCodeRange.m */; }; D8019910286B089000C277F0 /* SentryCrashReportSinkTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = D801990F286B089000C277F0 /* SentryCrashReportSinkTest.swift */; }; D808FB88281AB33C009A2A33 /* SentryUIEventTrackerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D808FB86281AB31D009A2A33 /* SentryUIEventTrackerTests.swift */; }; D808FB8B281BCE96009A2A33 /* TestSentrySwizzleWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = D808FB89281BCE46009A2A33 /* TestSentrySwizzleWrapper.swift */; }; @@ -1448,6 +1450,8 @@ A839D89924864BA8003B7AFD /* SentrySystemEventBreadcrumbs.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentrySystemEventBreadcrumbs.m; sourceTree = ""; }; A8F17B2B29016BD100990B25 /* SentryRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SentryRequest.h; sourceTree = ""; }; A8F17B2D2901765900990B25 /* SentryRequest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryRequest.m; sourceTree = ""; }; + A8F17B31290283C100990B25 /* SentryHttpStatusCodeRange.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SentryHttpStatusCodeRange.h; sourceTree = ""; }; + A8F17B332902870300990B25 /* SentryHttpStatusCodeRange.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryHttpStatusCodeRange.m; sourceTree = ""; }; D801990F286B089000C277F0 /* SentryCrashReportSinkTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryCrashReportSinkTest.swift; sourceTree = ""; }; D808FB86281AB31D009A2A33 /* SentryUIEventTrackerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryUIEventTrackerTests.swift; sourceTree = ""; }; D808FB89281BCE46009A2A33 /* TestSentrySwizzleWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestSentrySwizzleWrapper.swift; sourceTree = ""; }; @@ -2575,6 +2579,8 @@ 8E564AE7267AF22600FE117D /* SentryNetworkTracker.m */, D8370B6B273DF20F00F66E2D /* SentryNSURLSessionTaskSearch.h */, D8370B68273DF1E900F66E2D /* SentryNSURLSessionTaskSearch.m */, + A8F17B31290283C100990B25 /* SentryHttpStatusCodeRange.h */, + A8F17B332902870300990B25 /* SentryHttpStatusCodeRange.m */, ); name = Network; sourceTree = ""; @@ -2998,6 +3004,7 @@ 8EA1ED0D2669028C00E62B98 /* SentryUIViewControllerSwizzling.h in Headers */, 7B98D7E425FB7A7200C5A389 /* SentryAppState.h in Headers */, 7BDEAA022632A4580001EA25 /* SentryOptions+Private.h in Headers */, + A8F17B32290283C100990B25 /* SentryHttpStatusCodeRange.h in Headers */, 15E0A8EA240F2C9000F044E3 /* SentrySerialization.h in Headers */, 63FE70EF20DA4C1000CDBAE8 /* SentryCrashMonitor_AppState.h in Headers */, 635B3F381EBC6E2500A6176D /* SentryAsynchronousOperation.h in Headers */, @@ -3306,6 +3313,7 @@ 7BE3C77D2446112C00A38442 /* SentryRateLimitParser.m in Sources */, 8ECC674A25C23A20000E2BF6 /* SentryTransactionContext.m in Sources */, 03BCC38C27E1C01A003232C7 /* SentryTime.mm in Sources */, + A8F17B342902870300990B25 /* SentryHttpStatusCodeRange.m in Sources */, 03F84D3727DD4191008FE43F /* SentrySamplingProfiler.cpp in Sources */, 8453421628BE8A9500C22EEC /* SentrySpanStatus.m in Sources */, 7B9657262683104C00C66E25 /* NSData+Sentry.m in Sources */, diff --git a/Sources/Sentry/HttpStatusCodeRange.h b/Sources/Sentry/HttpStatusCodeRange.h new file mode 100644 index 00000000000..517c6b8965d --- /dev/null +++ b/Sources/Sentry/HttpStatusCodeRange.h @@ -0,0 +1,13 @@ +// +// HttpStatusCodeRange.h +// Sentry +// +// Created by Manoel Aranda Neto on 21.10.22. +// Copyright © 2022 Sentry. All rights reserved. +// + +#ifndef HttpStatusCodeRange_h +#define HttpStatusCodeRange_h + + +#endif /* HttpStatusCodeRange_h */ diff --git a/Sources/Sentry/Public/SentryOptions.h b/Sources/Sentry/Public/SentryOptions.h index a99ef040610..8413b967710 100644 --- a/Sources/Sentry/Public/SentryOptions.h +++ b/Sources/Sentry/Public/SentryOptions.h @@ -3,7 +3,7 @@ NS_ASSUME_NONNULL_BEGIN -@class SentryDsn, SentrySdkInfo, SentryMeasurementValue; +@class SentryDsn, SentrySdkInfo, SentryMeasurementValue, SentryHttpStatusCodeRange; NS_SWIFT_NAME(Options) @interface SentryOptions : NSObject @@ -419,6 +419,23 @@ NS_SWIFT_NAME(Options) */ @property (nonatomic, assign) BOOL enableCaptureFailedRequests; +/** + * The SDK will only capture HTTP Client errors if the HTTP Response status code is within the defined range. + * + * Defaults to 500 - 599. + */ +@property (nonatomic, assign) NSArray *failedRequestStatusCodes; + +/** + * An array of hosts or regexes that determines if HTTP Client errors will be automatically captured. + * + * This array can contain instances of NSString which should match the URL (using `contains`), + * and instances of NSRegularExpression, which will be used to check the whole URL. + * + * The default value automatically captures HTTP Client errors of all outgoing requests. + */ +@property (nonatomic, retain) NSArray *failedRequestTargets; + @end NS_ASSUME_NONNULL_END diff --git a/Sources/Sentry/SentryHttpStatusCodeRange.h b/Sources/Sentry/SentryHttpStatusCodeRange.h new file mode 100644 index 00000000000..f62bf3b13b0 --- /dev/null +++ b/Sources/Sentry/SentryHttpStatusCodeRange.h @@ -0,0 +1,20 @@ +#import "SentryDefines.h" + +NS_ASSUME_NONNULL_BEGIN + +NS_SWIFT_NAME(HttpStatusCodeRange) +@interface SentryHttpStatusCodeRange : NSObject + +@property (nonatomic, copy) NSNumber *min; + +@property (nonatomic, copy) NSNumber *max; + +- (instancetype)initWithMin:(NSNumber *)min andMax:(NSNumber *)max; + +- (instancetype)initWithStatusCode:(NSNumber *)statusCode; + +- (BOOL)isInRange:(NSNumber *)statusCode; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Sources/Sentry/SentryHttpStatusCodeRange.m b/Sources/Sentry/SentryHttpStatusCodeRange.m new file mode 100644 index 00000000000..8f9ea968554 --- /dev/null +++ b/Sources/Sentry/SentryHttpStatusCodeRange.m @@ -0,0 +1,29 @@ +#import + +NS_ASSUME_NONNULL_BEGIN + +@implementation SentryHttpStatusCodeRange + +- (instancetype)initWithMin:(NSNumber *)min andMax:(NSNumber *)max { + if (self = [super init]) { + _min = min; + _max = max; + } + return self; +} + +- (instancetype)initWithStatusCode:(NSNumber *)statusCode { + if (self = [super init]) { + _min = statusCode; + _max = statusCode; + } + return self; +} + +- (BOOL)isInRange:(NSNumber *)statusCode { + return statusCode >= _min && statusCode <= _max; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Sources/Sentry/SentryNetworkTracker.m b/Sources/Sentry/SentryNetworkTracker.m index 331c0ca2ba0..b0a52253541 100644 --- a/Sources/Sentry/SentryNetworkTracker.m +++ b/Sources/Sentry/SentryNetworkTracker.m @@ -12,6 +12,7 @@ #import "SentryScope+Private.h" #import "SentrySerialization.h" #import "SentryStacktrace.h" +#import "SentryHttpStatusCodeRange.h" #import "SentryThread.h" #import "SentryThreadInspector.h" #import "SentryTraceContext.h" @@ -78,9 +79,9 @@ - (void)disable } } -- (BOOL)addHeadersForRequestWithURL:(NSURL *)URL +- (BOOL)isTargetMatch:(NSURL *)URL withTargets:(NSArray *)targets { - for (id targetCheck in SentrySDK.options.tracePropagationTargets) { + for (id targetCheck in targets) { if ([targetCheck isKindOfClass:[NSRegularExpression class]]) { NSString *string = URL.absoluteString; NSUInteger numberOfMatches = @@ -161,7 +162,7 @@ - (void)urlSessionTaskResume:(NSURLSessionTask *)sessionTask } if ([sessionTask currentRequest] && - [self addHeadersForRequestWithURL:sessionTask.currentRequest.URL]) { + [self isTargetMatch:sessionTask.currentRequest.URL withTargets:SentrySDK.options.tracePropagationTargets]) { NSString *baggageHeader = @""; SentryTracer *tracer = [SentryTracer getTracer:span]; @@ -224,6 +225,8 @@ - (void)urlSessionTaskResume:(NSURLSessionTask *)sessionTask - (void)urlSessionTask:(NSURLSessionTask *)sessionTask setState:(NSURLSessionTaskState)newState { + // TODO: Can I actually read isCaptureFailedRequests directly from the options? + // Why do we have them here and in the options? if (!self.isNetworkTrackingEnabled && !self.isNetworkBreadcrumbEnabled && !self.isCaptureFailedRequests) { return; @@ -288,15 +291,14 @@ - (void)urlSessionTask:(NSURLSessionTask *)sessionTask setState:(NSURLSessionTas - (void)captureEvent:(NSURLSessionTask *)sessionTask { - NSInteger responseStatusCode = [self urlResponseStatusCode:sessionTask.response]; + NSHTTPURLResponse *myResponse = (NSHTTPURLResponse *)sessionTask.response; + NSNumber *responseStatusCode = [NSNumber numberWithLongLong:myResponse.statusCode]; - // TODO: check the string contains and regex - if (!self.isCaptureFailedRequests) { + if (!self.isCaptureFailedRequests || ![self containsStatusCode:responseStatusCode]) { return; } - - // TODO: check the range - if (responseStatusCode == 201) { + + if (![self isTargetMatch:sessionTask.currentRequest.URL withTargets:SentrySDK.options.failedRequestTargets]) { return; } @@ -306,7 +308,7 @@ - (void)captureEvent:(NSURLSessionTask *)sessionTask SentryEvent *event = [[SentryEvent alloc] initWithLevel:kSentryLevelError]; SentryThreadInspector *threadInspector = SentrySDK.currentHub.getClient.threadInspector; - NSArray *threads = [threadInspector getCurrentThreadsWithStackTrace]; + NSArray *threads = [threadInspector getCurrentThreads]; SentryException *sentryException = [[SentryException alloc] initWithValue:message type:@"HTTP-ClientError"]; @@ -327,6 +329,7 @@ - (void)captureEvent:(NSURLSessionTask *)sessionTask NSURLRequest *myRequest = (NSURLRequest *)sessionTask.currentRequest; + // TODO: strip query string and fragment from url NSURL *url = [[sessionTask currentRequest] URL]; request.url = url.absoluteString; @@ -345,13 +348,11 @@ - (void)captureEvent:(NSURLSessionTask *)sessionTask event.exceptions = @[ sentryException ]; event.request = request; - NSHTTPURLResponse *myResponse = (NSHTTPURLResponse *)sessionTask.response; - NSMutableDictionary *context = [[NSMutableDictionary alloc] init]; ; NSMutableDictionary *response = [[NSMutableDictionary alloc] init]; - [response setValue:[NSNumber numberWithLongLong:responseStatusCode] forKey:@"status_code"]; + [response setValue:responseStatusCode forKey:@"status_code"]; if (nil != myResponse.allHeaderFields) { NSDictionary *headers = myResponse.allHeaderFields.copy; [response setValue:headers forKey:@"headers"]; @@ -368,6 +369,16 @@ - (void)captureEvent:(NSURLSessionTask *)sessionTask [SentrySDK captureEvent:event]; } +- (BOOL)containsStatusCode:(NSNumber *)statusCode { + for (SentryHttpStatusCodeRange *targetCheck in SentrySDK.options.failedRequestStatusCodes) { + if ([targetCheck isInRange:statusCode]) { + return YES; + } + } + + return NO; +} + - (void)addBreadcrumbForSessionTask:(NSURLSessionTask *)sessionTask { if (!self.isNetworkBreadcrumbEnabled) { diff --git a/Sources/Sentry/SentryOptions.m b/Sources/Sentry/SentryOptions.m index 8ee387b9ca1..a2bbecb693c 100644 --- a/Sources/Sentry/SentryOptions.m +++ b/Sources/Sentry/SentryOptions.m @@ -6,12 +6,14 @@ #import "SentryMeta.h" #import "SentrySDK.h" #import "SentrySdkInfo.h" +#import "SentryHttpStatusCodeRange.h" @interface SentryOptions () @property (nullable, nonatomic, copy, readonly) NSNumber *defaultSampleRate; @property (nullable, nonatomic, copy, readonly) NSNumber *defaultTracesSampleRate; +@property (nullable, nonatomic, copy, readonly) SentryHttpStatusCodeRange *defaultHttpStatusCodeRange; #if SENTRY_TARGET_PROFILING_SUPPORTED @property (nullable, nonatomic, copy, readonly) NSNumber *defaultProfilesSampleRate; @property (nonatomic, assign) BOOL enableProfiling_DEPRECATED_TEST_ONLY; @@ -118,6 +120,12 @@ - (instancetype)init options:NSRegularExpressionCaseInsensitive error:NULL]; self.tracePropagationTargets = @[ everythingAllowedRegex ]; + + // defaults to 500 to 599 + _defaultHttpStatusCodeRange = [[SentryHttpStatusCodeRange alloc] initWithMin:[NSNumber numberWithInt:500] andMax:[NSNumber numberWithInt:599]]; + self.failedRequestStatusCodes = @[ _defaultHttpStatusCodeRange ]; + + self.failedRequestTargets = @[ everythingAllowedRegex ]; } return self; } @@ -149,6 +157,24 @@ - (void)setTracePropagationTargets:(NSArray *)tracePropagationTargets _tracePropagationTargets = tracePropagationTargets; } +- (void)setFailedRequestStatusCodes:(NSArray *)failedRequestStatusCodes +{ + _failedRequestStatusCodes = failedRequestStatusCodes; +} + +- (void)setFailedRequestTargets:(NSArray *)failedRequestTargets +{ + for (id targetCheck in failedRequestTargets) { + if (![targetCheck isKindOfClass:[NSRegularExpression class]] + && ![targetCheck isKindOfClass:[NSString class]]) { + SENTRY_LOG_WARN(@"Only instances of NSString and NSRegularExpression are supported " + @"inside failedRequestTargets."); + } + } + + _failedRequestTargets = failedRequestTargets; +} + - (void)setIntegrations:(NSArray *)integrations { SENTRY_LOG_WARN( @@ -355,6 +381,16 @@ - (BOOL)validateOptions:(NSDictionary *)options if ([options[@"tracePropagationTargets"] isKindOfClass:[NSArray class]]) { self.tracePropagationTargets = options[@"tracePropagationTargets"]; } + + // TODO: do I have to check the instance type of the items? + // or can I do in the signature? + if ([options[@"failedRequestStatusCodes"] isKindOfClass:[NSArray class]]) { + self.failedRequestStatusCodes = options[@"failedRequestStatusCodes"]; + } + + if ([options[@"failedRequestTargets"] isKindOfClass:[NSArray class]]) { + self.failedRequestTargets = options[@"failedRequestTargets"]; + } // SentrySdkInfo already expects a dictionary with {"sdk": {"name": ..., "value": ...}} // so we're passing the whole options object. diff --git a/Sources/Sentry/include/SentryNetworkTracker.h b/Sources/Sentry/include/SentryNetworkTracker.h index 204a80015d7..906dfed4f5d 100644 --- a/Sources/Sentry/include/SentryNetworkTracker.h +++ b/Sources/Sentry/include/SentryNetworkTracker.h @@ -16,7 +16,8 @@ static NSString *const SENTRY_NETWORK_REQUEST_TRACKER_SPAN = @"SENTRY_NETWORK_RE - (void)enableNetworkTracking; - (void)enableNetworkBreadcrumbs; - (void)enableCaptureFailedRequests; -- (BOOL)addHeadersForRequestWithURL:(NSURL *)URL; +- (BOOL)isTargetMatch:(NSURL *)URL withTargets:(NSArray *)targets; +- (BOOL)containsStatusCode:(NSNumber *)statusCode; - (void)disable; @property (nonatomic, readonly) BOOL isNetworkTrackingEnabled; From e25e33713b687959d37f89e964fba3e266aa7cfa Mon Sep 17 00:00:00 2001 From: Sentry Github Bot Date: Fri, 21 Oct 2022 09:44:11 +0000 Subject: [PATCH 07/18] Format code --- Sources/Sentry/HttpStatusCodeRange.h | 1 - Sources/Sentry/Public/SentryOptions.h | 6 ++++-- Sources/Sentry/SentryHttpStatusCodeRange.m | 9 ++++++--- Sources/Sentry/SentryNetworkTracker.m | 15 +++++++++------ Sources/Sentry/SentryOptions.m | 17 ++++++++++------- 5 files changed, 29 insertions(+), 19 deletions(-) diff --git a/Sources/Sentry/HttpStatusCodeRange.h b/Sources/Sentry/HttpStatusCodeRange.h index 517c6b8965d..37ad5800ee5 100644 --- a/Sources/Sentry/HttpStatusCodeRange.h +++ b/Sources/Sentry/HttpStatusCodeRange.h @@ -9,5 +9,4 @@ #ifndef HttpStatusCodeRange_h #define HttpStatusCodeRange_h - #endif /* HttpStatusCodeRange_h */ diff --git a/Sources/Sentry/Public/SentryOptions.h b/Sources/Sentry/Public/SentryOptions.h index 8413b967710..5443d6c7f0e 100644 --- a/Sources/Sentry/Public/SentryOptions.h +++ b/Sources/Sentry/Public/SentryOptions.h @@ -420,14 +420,16 @@ NS_SWIFT_NAME(Options) @property (nonatomic, assign) BOOL enableCaptureFailedRequests; /** - * The SDK will only capture HTTP Client errors if the HTTP Response status code is within the defined range. + * The SDK will only capture HTTP Client errors if the HTTP Response status code is within the + * defined range. * * Defaults to 500 - 599. */ @property (nonatomic, assign) NSArray *failedRequestStatusCodes; /** - * An array of hosts or regexes that determines if HTTP Client errors will be automatically captured. + * An array of hosts or regexes that determines if HTTP Client errors will be automatically + * captured. * * This array can contain instances of NSString which should match the URL (using `contains`), * and instances of NSRegularExpression, which will be used to check the whole URL. diff --git a/Sources/Sentry/SentryHttpStatusCodeRange.m b/Sources/Sentry/SentryHttpStatusCodeRange.m index 8f9ea968554..04a88a315c1 100644 --- a/Sources/Sentry/SentryHttpStatusCodeRange.m +++ b/Sources/Sentry/SentryHttpStatusCodeRange.m @@ -4,7 +4,8 @@ @implementation SentryHttpStatusCodeRange -- (instancetype)initWithMin:(NSNumber *)min andMax:(NSNumber *)max { +- (instancetype)initWithMin:(NSNumber *)min andMax:(NSNumber *)max +{ if (self = [super init]) { _min = min; _max = max; @@ -12,7 +13,8 @@ - (instancetype)initWithMin:(NSNumber *)min andMax:(NSNumber *)max { return self; } -- (instancetype)initWithStatusCode:(NSNumber *)statusCode { +- (instancetype)initWithStatusCode:(NSNumber *)statusCode +{ if (self = [super init]) { _min = statusCode; _max = statusCode; @@ -20,7 +22,8 @@ - (instancetype)initWithStatusCode:(NSNumber *)statusCode { return self; } -- (BOOL)isInRange:(NSNumber *)statusCode { +- (BOOL)isInRange:(NSNumber *)statusCode +{ return statusCode >= _min && statusCode <= _max; } diff --git a/Sources/Sentry/SentryNetworkTracker.m b/Sources/Sentry/SentryNetworkTracker.m index b0a52253541..1127bc8d583 100644 --- a/Sources/Sentry/SentryNetworkTracker.m +++ b/Sources/Sentry/SentryNetworkTracker.m @@ -4,6 +4,7 @@ #import "SentryClient+Private.h" #import "SentryEvent.h" #import "SentryException.h" +#import "SentryHttpStatusCodeRange.h" #import "SentryHub+Private.h" #import "SentryLog.h" #import "SentryMechanism.h" @@ -12,7 +13,6 @@ #import "SentryScope+Private.h" #import "SentrySerialization.h" #import "SentryStacktrace.h" -#import "SentryHttpStatusCodeRange.h" #import "SentryThread.h" #import "SentryThreadInspector.h" #import "SentryTraceContext.h" @@ -162,7 +162,8 @@ - (void)urlSessionTaskResume:(NSURLSessionTask *)sessionTask } if ([sessionTask currentRequest] && - [self isTargetMatch:sessionTask.currentRequest.URL withTargets:SentrySDK.options.tracePropagationTargets]) { + [self isTargetMatch:sessionTask.currentRequest.URL + withTargets:SentrySDK.options.tracePropagationTargets]) { NSString *baggageHeader = @""; SentryTracer *tracer = [SentryTracer getTracer:span]; @@ -297,8 +298,9 @@ - (void)captureEvent:(NSURLSessionTask *)sessionTask if (!self.isCaptureFailedRequests || ![self containsStatusCode:responseStatusCode]) { return; } - - if (![self isTargetMatch:sessionTask.currentRequest.URL withTargets:SentrySDK.options.failedRequestTargets]) { + + if (![self isTargetMatch:sessionTask.currentRequest.URL + withTargets:SentrySDK.options.failedRequestTargets]) { return; } @@ -369,13 +371,14 @@ - (void)captureEvent:(NSURLSessionTask *)sessionTask [SentrySDK captureEvent:event]; } -- (BOOL)containsStatusCode:(NSNumber *)statusCode { +- (BOOL)containsStatusCode:(NSNumber *)statusCode +{ for (SentryHttpStatusCodeRange *targetCheck in SentrySDK.options.failedRequestStatusCodes) { if ([targetCheck isInRange:statusCode]) { return YES; } } - + return NO; } diff --git a/Sources/Sentry/SentryOptions.m b/Sources/Sentry/SentryOptions.m index a2bbecb693c..6d7e0c9f02c 100644 --- a/Sources/Sentry/SentryOptions.m +++ b/Sources/Sentry/SentryOptions.m @@ -1,19 +1,20 @@ #import "SentryOptions.h" #import "SentryANRTracker.h" #import "SentryDsn.h" +#import "SentryHttpStatusCodeRange.h" #import "SentryLevelMapper.h" #import "SentryLog.h" #import "SentryMeta.h" #import "SentrySDK.h" #import "SentrySdkInfo.h" -#import "SentryHttpStatusCodeRange.h" @interface SentryOptions () @property (nullable, nonatomic, copy, readonly) NSNumber *defaultSampleRate; @property (nullable, nonatomic, copy, readonly) NSNumber *defaultTracesSampleRate; -@property (nullable, nonatomic, copy, readonly) SentryHttpStatusCodeRange *defaultHttpStatusCodeRange; +@property (nullable, nonatomic, copy, readonly) + SentryHttpStatusCodeRange *defaultHttpStatusCodeRange; #if SENTRY_TARGET_PROFILING_SUPPORTED @property (nullable, nonatomic, copy, readonly) NSNumber *defaultProfilesSampleRate; @property (nonatomic, assign) BOOL enableProfiling_DEPRECATED_TEST_ONLY; @@ -120,11 +121,13 @@ - (instancetype)init options:NSRegularExpressionCaseInsensitive error:NULL]; self.tracePropagationTargets = @[ everythingAllowedRegex ]; - + // defaults to 500 to 599 - _defaultHttpStatusCodeRange = [[SentryHttpStatusCodeRange alloc] initWithMin:[NSNumber numberWithInt:500] andMax:[NSNumber numberWithInt:599]]; + _defaultHttpStatusCodeRange = + [[SentryHttpStatusCodeRange alloc] initWithMin:[NSNumber numberWithInt:500] + andMax:[NSNumber numberWithInt:599]]; self.failedRequestStatusCodes = @[ _defaultHttpStatusCodeRange ]; - + self.failedRequestTargets = @[ everythingAllowedRegex ]; } return self; @@ -381,13 +384,13 @@ - (BOOL)validateOptions:(NSDictionary *)options if ([options[@"tracePropagationTargets"] isKindOfClass:[NSArray class]]) { self.tracePropagationTargets = options[@"tracePropagationTargets"]; } - + // TODO: do I have to check the instance type of the items? // or can I do in the signature? if ([options[@"failedRequestStatusCodes"] isKindOfClass:[NSArray class]]) { self.failedRequestStatusCodes = options[@"failedRequestStatusCodes"]; } - + if ([options[@"failedRequestTargets"] isKindOfClass:[NSArray class]]) { self.failedRequestTargets = options[@"failedRequestTargets"]; } From faf267212d0cfea2dfd410c564ffe47f23eb0c2d Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Fri, 21 Oct 2022 13:40:26 +0200 Subject: [PATCH 08/18] fixes --- Sources/Sentry/Public/SentryOptions.h | 4 ++-- Sources/Sentry/SentryHttpStatusCodeRange.h | 10 +++++----- Sources/Sentry/SentryHttpStatusCodeRange.m | 6 +++--- Sources/Sentry/SentryNetworkTracker.m | 15 ++++++++------- Sources/Sentry/SentryOptions.m | 11 ++++++----- Sources/Sentry/include/SentryNetworkTracker.h | 2 +- 6 files changed, 25 insertions(+), 23 deletions(-) diff --git a/Sources/Sentry/Public/SentryOptions.h b/Sources/Sentry/Public/SentryOptions.h index 8413b967710..c681fa6f241 100644 --- a/Sources/Sentry/Public/SentryOptions.h +++ b/Sources/Sentry/Public/SentryOptions.h @@ -424,7 +424,7 @@ NS_SWIFT_NAME(Options) * * Defaults to 500 - 599. */ -@property (nonatomic, assign) NSArray *failedRequestStatusCodes; +@property (nonatomic, strong) NSArray *failedRequestStatusCodes; /** * An array of hosts or regexes that determines if HTTP Client errors will be automatically captured. @@ -434,7 +434,7 @@ NS_SWIFT_NAME(Options) * * The default value automatically captures HTTP Client errors of all outgoing requests. */ -@property (nonatomic, retain) NSArray *failedRequestTargets; +@property (nonatomic, strong) NSArray *failedRequestTargets; @end diff --git a/Sources/Sentry/SentryHttpStatusCodeRange.h b/Sources/Sentry/SentryHttpStatusCodeRange.h index f62bf3b13b0..1b1340d3c0a 100644 --- a/Sources/Sentry/SentryHttpStatusCodeRange.h +++ b/Sources/Sentry/SentryHttpStatusCodeRange.h @@ -5,15 +5,15 @@ NS_ASSUME_NONNULL_BEGIN NS_SWIFT_NAME(HttpStatusCodeRange) @interface SentryHttpStatusCodeRange : NSObject -@property (nonatomic, copy) NSNumber *min; +@property (nonatomic) NSInteger min; -@property (nonatomic, copy) NSNumber *max; +@property (nonatomic) NSInteger max; -- (instancetype)initWithMin:(NSNumber *)min andMax:(NSNumber *)max; +- (instancetype)initWithMin:(NSInteger)min andMax:(NSInteger)max; -- (instancetype)initWithStatusCode:(NSNumber *)statusCode; +- (instancetype)initWithStatusCode:(NSInteger)statusCode; -- (BOOL)isInRange:(NSNumber *)statusCode; +- (BOOL)isInRange:(NSInteger)statusCode; @end diff --git a/Sources/Sentry/SentryHttpStatusCodeRange.m b/Sources/Sentry/SentryHttpStatusCodeRange.m index 8f9ea968554..fa11ea8ab0b 100644 --- a/Sources/Sentry/SentryHttpStatusCodeRange.m +++ b/Sources/Sentry/SentryHttpStatusCodeRange.m @@ -4,7 +4,7 @@ @implementation SentryHttpStatusCodeRange -- (instancetype)initWithMin:(NSNumber *)min andMax:(NSNumber *)max { +- (instancetype)initWithMin:(NSInteger)min andMax:(NSInteger)max { if (self = [super init]) { _min = min; _max = max; @@ -12,7 +12,7 @@ - (instancetype)initWithMin:(NSNumber *)min andMax:(NSNumber *)max { return self; } -- (instancetype)initWithStatusCode:(NSNumber *)statusCode { +- (instancetype)initWithStatusCode:(NSInteger)statusCode { if (self = [super init]) { _min = statusCode; _max = statusCode; @@ -20,7 +20,7 @@ - (instancetype)initWithStatusCode:(NSNumber *)statusCode { return self; } -- (BOOL)isInRange:(NSNumber *)statusCode { +- (BOOL)isInRange:(NSInteger)statusCode { return statusCode >= _min && statusCode <= _max; } diff --git a/Sources/Sentry/SentryNetworkTracker.m b/Sources/Sentry/SentryNetworkTracker.m index b0a52253541..b327c95337c 100644 --- a/Sources/Sentry/SentryNetworkTracker.m +++ b/Sources/Sentry/SentryNetworkTracker.m @@ -294,21 +294,22 @@ - (void)captureEvent:(NSURLSessionTask *)sessionTask NSHTTPURLResponse *myResponse = (NSHTTPURLResponse *)sessionTask.response; NSNumber *responseStatusCode = [NSNumber numberWithLongLong:myResponse.statusCode]; - if (!self.isCaptureFailedRequests || ![self containsStatusCode:responseStatusCode]) { + if (!self.isCaptureFailedRequests || ![self containsStatusCode:myResponse.statusCode]) { return; } if (![self isTargetMatch:sessionTask.currentRequest.URL withTargets:SentrySDK.options.failedRequestTargets]) { return; } - + NSString *message = [NSString - stringWithFormat:@"HTTP Client Error with status code: %li", (long)(responseStatusCode)]; + stringWithFormat:@"HTTP Client Error with status code: %ld", (long)myResponse.statusCode]; SentryEvent *event = [[SentryEvent alloc] initWithLevel:kSentryLevelError]; SentryThreadInspector *threadInspector = SentrySDK.currentHub.getClient.threadInspector; - NSArray *threads = [threadInspector getCurrentThreads]; + // TODO: getCurrentThreads does not return stack traces + NSArray *threads = [threadInspector getCurrentThreadsWithStackTrace]; SentryException *sentryException = [[SentryException alloc] initWithValue:message type:@"HTTP-ClientError"]; @@ -369,9 +370,9 @@ - (void)captureEvent:(NSURLSessionTask *)sessionTask [SentrySDK captureEvent:event]; } -- (BOOL)containsStatusCode:(NSNumber *)statusCode { - for (SentryHttpStatusCodeRange *targetCheck in SentrySDK.options.failedRequestStatusCodes) { - if ([targetCheck isInRange:statusCode]) { +- (BOOL)containsStatusCode:(NSInteger)statusCode { + for (SentryHttpStatusCodeRange *range in SentrySDK.options.failedRequestStatusCodes) { + if ([range isInRange:statusCode]) { return YES; } } diff --git a/Sources/Sentry/SentryOptions.m b/Sources/Sentry/SentryOptions.m index a2bbecb693c..353312e8579 100644 --- a/Sources/Sentry/SentryOptions.m +++ b/Sources/Sentry/SentryOptions.m @@ -13,7 +13,7 @@ @property (nullable, nonatomic, copy, readonly) NSNumber *defaultSampleRate; @property (nullable, nonatomic, copy, readonly) NSNumber *defaultTracesSampleRate; -@property (nullable, nonatomic, copy, readonly) SentryHttpStatusCodeRange *defaultHttpStatusCodeRange; +//@property (nullable, nonatomic, copy, readonly) SentryHttpStatusCodeRange *defaultHttpStatusCodeRange; #if SENTRY_TARGET_PROFILING_SUPPORTED @property (nullable, nonatomic, copy, readonly) NSNumber *defaultProfilesSampleRate; @property (nonatomic, assign) BOOL enableProfiling_DEPRECATED_TEST_ONLY; @@ -120,12 +120,13 @@ - (instancetype)init options:NSRegularExpressionCaseInsensitive error:NULL]; self.tracePropagationTargets = @[ everythingAllowedRegex ]; + self.failedRequestTargets = @[ everythingAllowedRegex ]; + // TODO: revert 200 // defaults to 500 to 599 - _defaultHttpStatusCodeRange = [[SentryHttpStatusCodeRange alloc] initWithMin:[NSNumber numberWithInt:500] andMax:[NSNumber numberWithInt:599]]; - self.failedRequestStatusCodes = @[ _defaultHttpStatusCodeRange ]; - - self.failedRequestTargets = @[ everythingAllowedRegex ]; + SentryHttpStatusCodeRange *defaultHttpStatusCodeRange = + [[SentryHttpStatusCodeRange alloc] initWithMin:200 andMax:599]; + self.failedRequestStatusCodes = @[ defaultHttpStatusCodeRange ]; } return self; } diff --git a/Sources/Sentry/include/SentryNetworkTracker.h b/Sources/Sentry/include/SentryNetworkTracker.h index 906dfed4f5d..b8559a0e557 100644 --- a/Sources/Sentry/include/SentryNetworkTracker.h +++ b/Sources/Sentry/include/SentryNetworkTracker.h @@ -17,7 +17,7 @@ static NSString *const SENTRY_NETWORK_REQUEST_TRACKER_SPAN = @"SENTRY_NETWORK_RE - (void)enableNetworkBreadcrumbs; - (void)enableCaptureFailedRequests; - (BOOL)isTargetMatch:(NSURL *)URL withTargets:(NSArray *)targets; -- (BOOL)containsStatusCode:(NSNumber *)statusCode; +- (BOOL)containsStatusCode:(NSInteger)statusCode; - (void)disable; @property (nonatomic, readonly) BOOL isNetworkTrackingEnabled; From 6b9b470472bd7b66a42c8b5f31746fb0c238d72c Mon Sep 17 00:00:00 2001 From: Sentry Github Bot Date: Fri, 21 Oct 2022 11:47:20 +0000 Subject: [PATCH 09/18] Format code --- Sources/Sentry/SentryNetworkTracker.m | 2 +- Sources/Sentry/SentryOptions.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Sentry/SentryNetworkTracker.m b/Sources/Sentry/SentryNetworkTracker.m index b03276b7575..ff20da7653a 100644 --- a/Sources/Sentry/SentryNetworkTracker.m +++ b/Sources/Sentry/SentryNetworkTracker.m @@ -303,7 +303,7 @@ - (void)captureEvent:(NSURLSessionTask *)sessionTask withTargets:SentrySDK.options.failedRequestTargets]) { return; } - + NSString *message = [NSString stringWithFormat:@"HTTP Client Error with status code: %ld", (long)myResponse.statusCode]; diff --git a/Sources/Sentry/SentryOptions.m b/Sources/Sentry/SentryOptions.m index 15165226ac9..52b42d604d9 100644 --- a/Sources/Sentry/SentryOptions.m +++ b/Sources/Sentry/SentryOptions.m @@ -125,7 +125,7 @@ - (instancetype)init // TODO: revert 200 // defaults to 500 to 599 SentryHttpStatusCodeRange *defaultHttpStatusCodeRange = - [[SentryHttpStatusCodeRange alloc] initWithMin:200 andMax:599]; + [[SentryHttpStatusCodeRange alloc] initWithMin:200 andMax:599]; self.failedRequestStatusCodes = @[ defaultHttpStatusCodeRange ]; } return self; From 40663bbe7782e247477567e8f282751233a7fa17 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Fri, 21 Oct 2022 13:53:07 +0200 Subject: [PATCH 10/18] fix --- Sources/Sentry/HttpStatusCodeRange.h | 12 ------------ Sources/Sentry/SentryNetworkTracker.m | 2 -- 2 files changed, 14 deletions(-) delete mode 100644 Sources/Sentry/HttpStatusCodeRange.h diff --git a/Sources/Sentry/HttpStatusCodeRange.h b/Sources/Sentry/HttpStatusCodeRange.h deleted file mode 100644 index 37ad5800ee5..00000000000 --- a/Sources/Sentry/HttpStatusCodeRange.h +++ /dev/null @@ -1,12 +0,0 @@ -// -// HttpStatusCodeRange.h -// Sentry -// -// Created by Manoel Aranda Neto on 21.10.22. -// Copyright © 2022 Sentry. All rights reserved. -// - -#ifndef HttpStatusCodeRange_h -#define HttpStatusCodeRange_h - -#endif /* HttpStatusCodeRange_h */ diff --git a/Sources/Sentry/SentryNetworkTracker.m b/Sources/Sentry/SentryNetworkTracker.m index b03276b7575..0ef810b5775 100644 --- a/Sources/Sentry/SentryNetworkTracker.m +++ b/Sources/Sentry/SentryNetworkTracker.m @@ -226,8 +226,6 @@ - (void)urlSessionTaskResume:(NSURLSessionTask *)sessionTask - (void)urlSessionTask:(NSURLSessionTask *)sessionTask setState:(NSURLSessionTaskState)newState { - // TODO: Can I actually read isCaptureFailedRequests directly from the options? - // Why do we have them here and in the options? if (!self.isNetworkTrackingEnabled && !self.isNetworkBreadcrumbEnabled && !self.isCaptureFailedRequests) { return; From cd342199d980fef276f1d1586b3addc8a2b7bd43 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Fri, 21 Oct 2022 14:39:05 +0200 Subject: [PATCH 11/18] truncate strings --- .../iOS-ObjectiveC/AppDelegate.m | 1 + .../iOS-ObjectiveC/ViewController.m | 2 +- .../iOS-Swift/iOS-Swift/ViewController.swift | 6 ++++-- Sources/Sentry/SentryNetworkTracker.m | 20 ++++++++++++------- Sources/Sentry/SentryOptions.m | 2 -- 5 files changed, 19 insertions(+), 12 deletions(-) diff --git a/Samples/iOS-ObjectiveC/iOS-ObjectiveC/AppDelegate.m b/Samples/iOS-ObjectiveC/iOS-ObjectiveC/AppDelegate.m index 11b6c4ef3ab..a8bdfb121f2 100644 --- a/Samples/iOS-ObjectiveC/iOS-ObjectiveC/AppDelegate.m +++ b/Samples/iOS-ObjectiveC/iOS-ObjectiveC/AppDelegate.m @@ -27,6 +27,7 @@ - (BOOL)application:(UIApplication *)application if ([NSProcessInfo.processInfo.arguments containsObject:@"--io.sentry.profiling.enable"]) { options.profilesSampleRate = @1; } + options.enableCaptureFailedRequests = YES; }]; return YES; diff --git a/Samples/iOS-ObjectiveC/iOS-ObjectiveC/ViewController.m b/Samples/iOS-ObjectiveC/iOS-ObjectiveC/ViewController.m index d2405d68421..a354ac981e1 100644 --- a/Samples/iOS-ObjectiveC/iOS-ObjectiveC/ViewController.m +++ b/Samples/iOS-ObjectiveC/iOS-ObjectiveC/ViewController.m @@ -41,7 +41,7 @@ - (void)viewDidLoad NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration]; NSURLSession *session = [NSURLSession sessionWithConfiguration:config]; NSURL *url = [[NSURL alloc] - initWithString:@"https://sentry-brand.storage.googleapis.com/sentry-logo-black.png"]; + initWithString:@"https://sentry-brand.storage.googleapis.com/sentry-logo-black.png?myQuery=test#myFragment"]; NSURLSessionDataTask *task = [session dataTaskWithURL:url]; [task resume]; } diff --git a/Samples/iOS-Swift/iOS-Swift/ViewController.swift b/Samples/iOS-Swift/iOS-Swift/ViewController.swift index d3e87f34d99..3a4e3ab19e1 100644 --- a/Samples/iOS-Swift/iOS-Swift/ViewController.swift +++ b/Samples/iOS-Swift/iOS-Swift/ViewController.swift @@ -91,10 +91,12 @@ class ViewController: UIViewController { _ = FileManager.default.contents(atPath: path) } } - - guard let imgUrl = URL(string: "https://sentry-brand.storage.googleapis.com/sentry-logo-black.png") else { + guard let imgUrl = URL(string: "https://sentry-brand.storage.googleapis.com/sentry-logo-black.png?myQuery=test#myFragment") else { return } +// print("query: \(imgUrl.query)") +// print("fragment: \(imgUrl.fragment)") +// print("full url: \(imgUrl.absoluteString)") let session = URLSession(configuration: URLSessionConfiguration.default) let dataTask = session.dataTask(with: imgUrl) { (_, _, _) in } dataTask.resume() diff --git a/Sources/Sentry/SentryNetworkTracker.m b/Sources/Sentry/SentryNetworkTracker.m index e012778128f..5a6c9f516ab 100644 --- a/Sources/Sentry/SentryNetworkTracker.m +++ b/Sources/Sentry/SentryNetworkTracker.m @@ -321,21 +321,27 @@ - (void)captureEvent:(NSURLSessionTask *)sessionTask sentryStacktrace.snapshot = @(YES); sentryException.stacktrace = sentryStacktrace; - // TODO: do I need this? - // [threads enumerateObjectsUsingBlock:^(SentryThread *_Nonnull obj, NSUInteger idx, - // BOOL *_Nonnull stop) { obj.current = [NSNumber numberWithBool:idx == 0]; }]; } SentryRequest *request = [[SentryRequest alloc] init]; NSURLRequest *myRequest = (NSURLRequest *)sessionTask.currentRequest; - // TODO: strip query string and fragment from url NSURL *url = [[sessionTask currentRequest] URL]; - request.url = url.absoluteString; - request.fragment = url.fragment; - request.queryString = url.query; + NSString *urlString = url.absoluteString; + + if (nil != url.fragment) { + request.fragment = url.fragment; + urlString = [urlString stringByReplacingOccurrencesOfString:[@"#" stringByAppendingString:url.fragment] withString:@""]; + } + + if (nil != url.query) { + request.queryString = url.query; + urlString = [urlString stringByReplacingOccurrencesOfString:[@"?" stringByAppendingString:url.query] withString:@""]; + } + + request.url = urlString; request.method = myRequest.HTTPMethod; if (sessionTask.countOfBytesSent != 0) { request.bodySize = [NSNumber numberWithLongLong:sessionTask.countOfBytesSent]; diff --git a/Sources/Sentry/SentryOptions.m b/Sources/Sentry/SentryOptions.m index 52b42d604d9..c18b2e57598 100644 --- a/Sources/Sentry/SentryOptions.m +++ b/Sources/Sentry/SentryOptions.m @@ -383,8 +383,6 @@ - (BOOL)validateOptions:(NSDictionary *)options self.tracePropagationTargets = options[@"tracePropagationTargets"]; } - // TODO: do I have to check the instance type of the items? - // or can I do in the signature? if ([options[@"failedRequestStatusCodes"] isKindOfClass:[NSArray class]]) { self.failedRequestStatusCodes = options[@"failedRequestStatusCodes"]; } From 42a9ca346a14bd10bd714cee8345770dd1320123 Mon Sep 17 00:00:00 2001 From: Sentry Github Bot Date: Fri, 21 Oct 2022 12:40:10 +0000 Subject: [PATCH 12/18] Format code --- Samples/iOS-ObjectiveC/iOS-ObjectiveC/ViewController.m | 4 ++-- Sources/Sentry/SentryNetworkTracker.m | 10 +++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Samples/iOS-ObjectiveC/iOS-ObjectiveC/ViewController.m b/Samples/iOS-ObjectiveC/iOS-ObjectiveC/ViewController.m index a354ac981e1..1b7f8bc3ffc 100644 --- a/Samples/iOS-ObjectiveC/iOS-ObjectiveC/ViewController.m +++ b/Samples/iOS-ObjectiveC/iOS-ObjectiveC/ViewController.m @@ -40,8 +40,8 @@ - (void)viewDidLoad // Load an image just for HTTP swizzling NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration]; NSURLSession *session = [NSURLSession sessionWithConfiguration:config]; - NSURL *url = [[NSURL alloc] - initWithString:@"https://sentry-brand.storage.googleapis.com/sentry-logo-black.png?myQuery=test#myFragment"]; + NSURL *url = [[NSURL alloc] initWithString:@"https://sentry-brand.storage.googleapis.com/" + @"sentry-logo-black.png?myQuery=test#myFragment"]; NSURLSessionDataTask *task = [session dataTaskWithURL:url]; [task resume]; } diff --git a/Sources/Sentry/SentryNetworkTracker.m b/Sources/Sentry/SentryNetworkTracker.m index 5a6c9f516ab..93e17c97854 100644 --- a/Sources/Sentry/SentryNetworkTracker.m +++ b/Sources/Sentry/SentryNetworkTracker.m @@ -333,12 +333,16 @@ - (void)captureEvent:(NSURLSessionTask *)sessionTask if (nil != url.fragment) { request.fragment = url.fragment; - urlString = [urlString stringByReplacingOccurrencesOfString:[@"#" stringByAppendingString:url.fragment] withString:@""]; + urlString = [urlString + stringByReplacingOccurrencesOfString:[@"#" stringByAppendingString:url.fragment] + withString:@""]; } - + if (nil != url.query) { request.queryString = url.query; - urlString = [urlString stringByReplacingOccurrencesOfString:[@"?" stringByAppendingString:url.query] withString:@""]; + urlString = + [urlString stringByReplacingOccurrencesOfString:[@"?" stringByAppendingString:url.query] + withString:@""]; } request.url = urlString; From 669ebeae28fd49f3f243678056a8a8a4f6bfb37d Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Fri, 21 Oct 2022 14:55:41 +0200 Subject: [PATCH 13/18] fix --- Sources/Sentry/SentryNetworkTracker.m | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Sources/Sentry/SentryNetworkTracker.m b/Sources/Sentry/SentryNetworkTracker.m index 93e17c97854..442f4fcb2fb 100644 --- a/Sources/Sentry/SentryNetworkTracker.m +++ b/Sources/Sentry/SentryNetworkTracker.m @@ -308,8 +308,7 @@ - (void)captureEvent:(NSURLSessionTask *)sessionTask SentryEvent *event = [[SentryEvent alloc] initWithLevel:kSentryLevelError]; SentryThreadInspector *threadInspector = SentrySDK.currentHub.getClient.threadInspector; - // TODO: getCurrentThreads does not return stack traces - NSArray *threads = [threadInspector getCurrentThreadsWithStackTrace]; + NSArray *threads = [threadInspector getCurrentThreads]; SentryException *sentryException = [[SentryException alloc] initWithValue:message type:@"HTTP-ClientError"]; @@ -317,10 +316,16 @@ - (void)captureEvent:(NSURLSessionTask *)sessionTask [[SentryMechanism alloc] initWithType:@"SentryNetworkTrackingIntegration"]; if (threads.count > 0) { - SentryStacktrace *sentryStacktrace = [threads[0] stacktrace]; - sentryStacktrace.snapshot = @(YES); + for(SentryThread *thread in threads) { + if (nil != thread.current && [thread.current boolValue]) { + SentryStacktrace *sentryStacktrace = [thread stacktrace]; + sentryStacktrace.snapshot = @(YES); - sentryException.stacktrace = sentryStacktrace; + sentryException.stacktrace = sentryStacktrace; + + break; + } + } } SentryRequest *request = [[SentryRequest alloc] init]; From 0e6f89e85eb5d9850038dcfd5e7ac3157397da18 Mon Sep 17 00:00:00 2001 From: Sentry Github Bot Date: Fri, 21 Oct 2022 12:56:35 +0000 Subject: [PATCH 14/18] Format code --- Sources/Sentry/SentryNetworkTracker.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Sentry/SentryNetworkTracker.m b/Sources/Sentry/SentryNetworkTracker.m index 442f4fcb2fb..1811fde039c 100644 --- a/Sources/Sentry/SentryNetworkTracker.m +++ b/Sources/Sentry/SentryNetworkTracker.m @@ -316,7 +316,7 @@ - (void)captureEvent:(NSURLSessionTask *)sessionTask [[SentryMechanism alloc] initWithType:@"SentryNetworkTrackingIntegration"]; if (threads.count > 0) { - for(SentryThread *thread in threads) { + for (SentryThread *thread in threads) { if (nil != thread.current && [thread.current boolValue]) { SentryStacktrace *sentryStacktrace = [thread stacktrace]; sentryStacktrace.snapshot = @(YES); From d07ea544813e98145bae9204e9b4f542be80ee50 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Fri, 21 Oct 2022 14:58:51 +0200 Subject: [PATCH 15/18] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87c6b2e1d3f..8c77ba8dbfb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Offline caching improvements (#2263) - Report usage of stitchAsyncCode (#2281) +- HTTP Client errors for OkHttp (#2308) ### Fixes From f3715cf99e49ff1b228b3972bef93dde64e31f04 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Mon, 24 Oct 2022 11:49:47 +0200 Subject: [PATCH 16/18] review --- CHANGELOG.md | 2 +- .../iOS-ObjectiveC/ViewController.m | 2 +- .../iOS-Swift/iOS-Swift/ViewController.swift | 5 +- Sources/Sentry/Public/Sentry.h | 1 + Sources/Sentry/Public/SentryEvent.h | 2 +- Sources/Sentry/Public/SentryStacktrace.h | 2 +- Sources/Sentry/SentryHttpStatusCodeRange.h | 20 ------- Sources/Sentry/SentryHttpStatusCodeRange.m | 2 +- Sources/Sentry/SentryNetworkTracker.m | 56 +++++++------------ Sources/Sentry/SentryOptions.m | 2 +- Sources/Sentry/SentryRequest.h | 16 +++--- .../include/SentryHttpStatusCodeRange.h | 27 +++++++++ Sources/Sentry/include/SentryNetworkTracker.h | 2 +- 13 files changed, 63 insertions(+), 76 deletions(-) delete mode 100644 Sources/Sentry/SentryHttpStatusCodeRange.h create mode 100644 Sources/Sentry/include/SentryHttpStatusCodeRange.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c77ba8dbfb..2f106dbcbf1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ - Offline caching improvements (#2263) - Report usage of stitchAsyncCode (#2281) -- HTTP Client errors for OkHttp (#2308) +- HTTP Client errors (#2308) ### Fixes diff --git a/Samples/iOS-ObjectiveC/iOS-ObjectiveC/ViewController.m b/Samples/iOS-ObjectiveC/iOS-ObjectiveC/ViewController.m index 1b7f8bc3ffc..8917602b8ee 100644 --- a/Samples/iOS-ObjectiveC/iOS-ObjectiveC/ViewController.m +++ b/Samples/iOS-ObjectiveC/iOS-ObjectiveC/ViewController.m @@ -40,7 +40,7 @@ - (void)viewDidLoad // Load an image just for HTTP swizzling NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration]; NSURLSession *session = [NSURLSession sessionWithConfiguration:config]; - NSURL *url = [[NSURL alloc] initWithString:@"https://sentry-brand.storage.googleapis.com/" + NSURL *url = [[NSURL alloc] initWithString:@"https://sentry-brand.storage.googleapis.com/test/" @"sentry-logo-black.png?myQuery=test#myFragment"]; NSURLSessionDataTask *task = [session dataTaskWithURL:url]; [task resume]; diff --git a/Samples/iOS-Swift/iOS-Swift/ViewController.swift b/Samples/iOS-Swift/iOS-Swift/ViewController.swift index 3a4e3ab19e1..15f0f4b730e 100644 --- a/Samples/iOS-Swift/iOS-Swift/ViewController.swift +++ b/Samples/iOS-Swift/iOS-Swift/ViewController.swift @@ -91,12 +91,9 @@ class ViewController: UIViewController { _ = FileManager.default.contents(atPath: path) } } - guard let imgUrl = URL(string: "https://sentry-brand.storage.googleapis.com/sentry-logo-black.png?myQuery=test#myFragment") else { + guard let imgUrl = URL(string: "https://sentry-brand.storage.googleapis.com/sentry-logo-black.png") else { return } -// print("query: \(imgUrl.query)") -// print("fragment: \(imgUrl.fragment)") -// print("full url: \(imgUrl.absoluteString)") let session = URLSession(configuration: URLSessionConfiguration.default) let dataTask = session.dataTask(with: imgUrl) { (_, _, _) in } dataTask.resume() diff --git a/Sources/Sentry/Public/Sentry.h b/Sources/Sentry/Public/Sentry.h index 01784d2553b..6617bcba89b 100644 --- a/Sources/Sentry/Public/Sentry.h +++ b/Sources/Sentry/Public/Sentry.h @@ -49,3 +49,4 @@ FOUNDATION_EXPORT const unsigned char SentryVersionString[]; #import "SentryTransactionContext.h" #import "SentryUser.h" #import "SentryUserFeedback.h" +#import "SentryHttpStatusCodeRange.h" diff --git a/Sources/Sentry/Public/SentryEvent.h b/Sources/Sentry/Public/SentryEvent.h index f8077e28e4c..bf2fb5f9c95 100644 --- a/Sources/Sentry/Public/SentryEvent.h +++ b/Sources/Sentry/Public/SentryEvent.h @@ -162,7 +162,7 @@ NS_SWIFT_NAME(Event) /** * Set the Http request information. */ -@property (nonatomic, strong) SentryRequest *_Nullable request; +@property (nonatomic, strong, nullable) SentryRequest *request; /** * Init an SentryEvent will set all needed fields by default diff --git a/Sources/Sentry/Public/SentryStacktrace.h b/Sources/Sentry/Public/SentryStacktrace.h index 43e0e762d1a..663b22505d8 100644 --- a/Sources/Sentry/Public/SentryStacktrace.h +++ b/Sources/Sentry/Public/SentryStacktrace.h @@ -24,7 +24,7 @@ SENTRY_NO_INIT /** * Indicates that this stack trace is a snapshot triggered by an external signal. */ -@property (nonatomic, copy) NSNumber *_Nullable snapshot; +@property (nonatomic, copy, nullable) NSNumber *snapshot; /** * Initialize a SentryStacktrace with frames and registers diff --git a/Sources/Sentry/SentryHttpStatusCodeRange.h b/Sources/Sentry/SentryHttpStatusCodeRange.h deleted file mode 100644 index 1b1340d3c0a..00000000000 --- a/Sources/Sentry/SentryHttpStatusCodeRange.h +++ /dev/null @@ -1,20 +0,0 @@ -#import "SentryDefines.h" - -NS_ASSUME_NONNULL_BEGIN - -NS_SWIFT_NAME(HttpStatusCodeRange) -@interface SentryHttpStatusCodeRange : NSObject - -@property (nonatomic) NSInteger min; - -@property (nonatomic) NSInteger max; - -- (instancetype)initWithMin:(NSInteger)min andMax:(NSInteger)max; - -- (instancetype)initWithStatusCode:(NSInteger)statusCode; - -- (BOOL)isInRange:(NSInteger)statusCode; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Sources/Sentry/SentryHttpStatusCodeRange.m b/Sources/Sentry/SentryHttpStatusCodeRange.m index 5568bb52217..9f0c7392c8b 100644 --- a/Sources/Sentry/SentryHttpStatusCodeRange.m +++ b/Sources/Sentry/SentryHttpStatusCodeRange.m @@ -4,7 +4,7 @@ @implementation SentryHttpStatusCodeRange -- (instancetype)initWithMin:(NSInteger)min andMax:(NSInteger)max +- (instancetype)initWithMin:(NSInteger)min max:(NSInteger)max { if (self = [super init]) { _min = min; diff --git a/Sources/Sentry/SentryNetworkTracker.m b/Sources/Sentry/SentryNetworkTracker.m index 1811fde039c..5a8260ef5d5 100644 --- a/Sources/Sentry/SentryNetworkTracker.m +++ b/Sources/Sentry/SentryNetworkTracker.m @@ -25,7 +25,7 @@ @property (nonatomic, assign) BOOL isNetworkTrackingEnabled; @property (nonatomic, assign) BOOL isNetworkBreadcrumbEnabled; -@property (nonatomic, assign) BOOL isCaptureFailedRequests; +@property (nonatomic, assign) BOOL isCaptureFailedRequestsEnabled; @end @@ -44,7 +44,7 @@ - (instancetype)init if (self = [super init]) { _isNetworkTrackingEnabled = NO; _isNetworkBreadcrumbEnabled = NO; - _isCaptureFailedRequests = NO; + _isCaptureFailedRequestsEnabled = NO; } return self; } @@ -66,7 +66,7 @@ - (void)enableNetworkBreadcrumbs - (void)enableCaptureFailedRequests { @synchronized(self) { - _isCaptureFailedRequests = YES; + _isCaptureFailedRequestsEnabled = YES; } } @@ -75,7 +75,7 @@ - (void)disable @synchronized(self) { _isNetworkBreadcrumbEnabled = NO; _isNetworkTrackingEnabled = NO; - _isCaptureFailedRequests = NO; + _isCaptureFailedRequestsEnabled = NO; } } @@ -227,7 +227,7 @@ - (void)urlSessionTaskResume:(NSURLSessionTask *)sessionTask - (void)urlSessionTask:(NSURLSessionTask *)sessionTask setState:(NSURLSessionTaskState)newState { if (!self.isNetworkTrackingEnabled && !self.isNetworkBreadcrumbEnabled - && !self.isCaptureFailedRequests) { + && !self.isCaptureFailedRequestsEnabled) { return; } @@ -260,7 +260,7 @@ - (void)urlSessionTask:(NSURLSessionTask *)sessionTask setState:(NSURLSessionTas } if (sessionTask.state == NSURLSessionTaskStateRunning) { - [self captureEvent:sessionTask]; + [self captureFailedRequests:sessionTask]; [self addBreadcrumbForSessionTask:sessionTask]; @@ -288,16 +288,17 @@ - (void)urlSessionTask:(NSURLSessionTask *)sessionTask setState:(NSURLSessionTas SENTRY_LOG_DEBUG(@"SentryNetworkTracker finished HTTP span for sessionTask"); } -- (void)captureEvent:(NSURLSessionTask *)sessionTask +- (void)captureFailedRequests:(NSURLSessionTask *)sessionTask { + NSURLRequest *myRequest = sessionTask.currentRequest; NSHTTPURLResponse *myResponse = (NSHTTPURLResponse *)sessionTask.response; - NSNumber *responseStatusCode = [NSNumber numberWithLongLong:myResponse.statusCode]; + NSNumber *responseStatusCode = @(myResponse.statusCode); - if (!self.isCaptureFailedRequests || ![self containsStatusCode:myResponse.statusCode]) { + if (!self.isCaptureFailedRequestsEnabled || ![self containsStatusCode:myResponse.statusCode]) { return; } - if (![self isTargetMatch:sessionTask.currentRequest.URL + if (![self isTargetMatch:myRequest.URL withTargets:SentrySDK.options.failedRequestTargets]) { return; } @@ -313,42 +314,24 @@ - (void)captureEvent:(NSURLSessionTask *)sessionTask SentryException *sentryException = [[SentryException alloc] initWithValue:message type:@"HTTP-ClientError"]; sentryException.mechanism = - [[SentryMechanism alloc] initWithType:@"SentryNetworkTrackingIntegration"]; + [[SentryMechanism alloc] initWithType:@"HTTPClientError"]; - if (threads.count > 0) { - for (SentryThread *thread in threads) { - if (nil != thread.current && [thread.current boolValue]) { - SentryStacktrace *sentryStacktrace = [thread stacktrace]; - sentryStacktrace.snapshot = @(YES); + for (SentryThread *thread in threads) { + if ([thread.current boolValue]) { + SentryStacktrace *sentryStacktrace = [thread stacktrace]; + sentryStacktrace.snapshot = @(YES); - sentryException.stacktrace = sentryStacktrace; + sentryException.stacktrace = sentryStacktrace; - break; - } + break; } } SentryRequest *request = [[SentryRequest alloc] init]; - NSURLRequest *myRequest = (NSURLRequest *)sessionTask.currentRequest; - NSURL *url = [[sessionTask currentRequest] URL]; - NSString *urlString = url.absoluteString; - - if (nil != url.fragment) { - request.fragment = url.fragment; - urlString = [urlString - stringByReplacingOccurrencesOfString:[@"#" stringByAppendingString:url.fragment] - withString:@""]; - } - - if (nil != url.query) { - request.queryString = url.query; - urlString = - [urlString stringByReplacingOccurrencesOfString:[@"?" stringByAppendingString:url.query] - withString:@""]; - } + NSString *urlString = [NSString stringWithFormat:@"%@://%@%@", url.scheme, url.host, url.path]; request.url = urlString; request.method = myRequest.HTTPMethod; @@ -365,7 +348,6 @@ - (void)captureEvent:(NSURLSessionTask *)sessionTask event.request = request; NSMutableDictionary *context = [[NSMutableDictionary alloc] init]; - ; NSMutableDictionary *response = [[NSMutableDictionary alloc] init]; [response setValue:responseStatusCode forKey:@"status_code"]; diff --git a/Sources/Sentry/SentryOptions.m b/Sources/Sentry/SentryOptions.m index c18b2e57598..cf1261609a5 100644 --- a/Sources/Sentry/SentryOptions.m +++ b/Sources/Sentry/SentryOptions.m @@ -125,7 +125,7 @@ - (instancetype)init // TODO: revert 200 // defaults to 500 to 599 SentryHttpStatusCodeRange *defaultHttpStatusCodeRange = - [[SentryHttpStatusCodeRange alloc] initWithMin:200 andMax:599]; + [[SentryHttpStatusCodeRange alloc] initWithMin:200 max:599]; self.failedRequestStatusCodes = @[ defaultHttpStatusCodeRange ]; } return self; diff --git a/Sources/Sentry/SentryRequest.h b/Sources/Sentry/SentryRequest.h index 9178f289e15..23351b68e20 100644 --- a/Sources/Sentry/SentryRequest.h +++ b/Sources/Sentry/SentryRequest.h @@ -4,44 +4,44 @@ NS_ASSUME_NONNULL_BEGIN NS_SWIFT_NAME(Request) -@interface SentryRequest : NSObject +@interface SentryRequest : NSObject // TODO: data, env /** * Optional: HTTP response body size. */ -@property (atomic, copy) NSNumber *_Nullable bodySize; +@property (nonatomic, copy, nullable) NSNumber *bodySize; /** * Optional: The cookie values. */ -@property (atomic, copy) NSString *_Nullable cookies; +@property (nonatomic, copy, nullable) NSString *cookies; /** * Optional: A dictionary of submitted headers. */ -@property (nonatomic, strong) NSDictionary *_Nullable headers; +@property (nonatomic, strong, nullable) NSDictionary *headers; /** * Optional: The fragment of the request URL. */ -@property (atomic, copy) NSString *_Nullable fragment; +@property (nonatomic, copy, nullable) NSString *fragment; /** * Optional: HTTP request method. */ -@property (atomic, copy) NSString *_Nullable method; +@property (nonatomic, copy, nullable) NSString *method; /** * Optional: The query string component of the URL. */ -@property (atomic, copy) NSString *_Nullable queryString; +@property (nonatomic, copy, nullable) NSString *queryString; /** * Optional: The URL of the request if available. */ -@property (atomic, copy) NSString *_Nullable url; +@property (nonatomic, copy, nullable) NSString *url; - (instancetype)init; diff --git a/Sources/Sentry/include/SentryHttpStatusCodeRange.h b/Sources/Sentry/include/SentryHttpStatusCodeRange.h new file mode 100644 index 00000000000..dc9c5a94563 --- /dev/null +++ b/Sources/Sentry/include/SentryHttpStatusCodeRange.h @@ -0,0 +1,27 @@ +#import "SentryDefines.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * The Http status code range. Example for a range: 400 to 499, 500 to 599, 400 to 599 The range is + * inclusive so the min and max is considered part of the range. + * + * Example for a single status code 400, 500 + */ +NS_SWIFT_NAME(HttpStatusCodeRange) +@interface SentryHttpStatusCodeRange : NSObject +SENTRY_NO_INIT + +@property (nonatomic, readonly) NSInteger min; + +@property (nonatomic, readonly) NSInteger max; + +- (instancetype)initWithMin:(NSInteger)min max:(NSInteger)max; + +- (instancetype)initWithStatusCode:(NSInteger)statusCode; + +- (BOOL)isInRange:(NSInteger)statusCode; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Sources/Sentry/include/SentryNetworkTracker.h b/Sources/Sentry/include/SentryNetworkTracker.h index b8559a0e557..547ab2afe23 100644 --- a/Sources/Sentry/include/SentryNetworkTracker.h +++ b/Sources/Sentry/include/SentryNetworkTracker.h @@ -22,7 +22,7 @@ static NSString *const SENTRY_NETWORK_REQUEST_TRACKER_SPAN = @"SENTRY_NETWORK_RE @property (nonatomic, readonly) BOOL isNetworkTrackingEnabled; @property (nonatomic, readonly) BOOL isNetworkBreadcrumbEnabled; -@property (nonatomic, readonly) BOOL isCaptureFailedRequests; +@property (nonatomic, readonly) BOOL isCaptureFailedRequestsEnabled; @end From 4577ab4740cbe13820a4202a458596f8760f6f86 Mon Sep 17 00:00:00 2001 From: Sentry Github Bot Date: Mon, 24 Oct 2022 09:52:04 +0000 Subject: [PATCH 17/18] Format code --- Sources/Sentry/Public/Sentry.h | 2 +- Sources/Sentry/SentryNetworkTracker.m | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Sources/Sentry/Public/Sentry.h b/Sources/Sentry/Public/Sentry.h index 6617bcba89b..7ceb3c1db66 100644 --- a/Sources/Sentry/Public/Sentry.h +++ b/Sources/Sentry/Public/Sentry.h @@ -22,6 +22,7 @@ FOUNDATION_EXPORT const unsigned char SentryVersionString[]; #import "SentryEvent.h" #import "SentryException.h" #import "SentryFrame.h" +#import "SentryHttpStatusCodeRange.h" #import "SentryHub.h" #import "SentryId.h" #import "SentryIntegrationProtocol.h" @@ -49,4 +50,3 @@ FOUNDATION_EXPORT const unsigned char SentryVersionString[]; #import "SentryTransactionContext.h" #import "SentryUser.h" #import "SentryUserFeedback.h" -#import "SentryHttpStatusCodeRange.h" diff --git a/Sources/Sentry/SentryNetworkTracker.m b/Sources/Sentry/SentryNetworkTracker.m index 5a8260ef5d5..f255491a68e 100644 --- a/Sources/Sentry/SentryNetworkTracker.m +++ b/Sources/Sentry/SentryNetworkTracker.m @@ -298,8 +298,7 @@ - (void)captureFailedRequests:(NSURLSessionTask *)sessionTask return; } - if (![self isTargetMatch:myRequest.URL - withTargets:SentrySDK.options.failedRequestTargets]) { + if (![self isTargetMatch:myRequest.URL withTargets:SentrySDK.options.failedRequestTargets]) { return; } @@ -313,8 +312,7 @@ - (void)captureFailedRequests:(NSURLSessionTask *)sessionTask SentryException *sentryException = [[SentryException alloc] initWithValue:message type:@"HTTP-ClientError"]; - sentryException.mechanism = - [[SentryMechanism alloc] initWithType:@"HTTPClientError"]; + sentryException.mechanism = [[SentryMechanism alloc] initWithType:@"HTTPClientError"]; for (SentryThread *thread in threads) { if ([thread.current boolValue]) { From 6477646d686ef5767219a34cdd4543c79cffcc5c Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Mon, 24 Oct 2022 13:12:49 +0200 Subject: [PATCH 18/18] fix public interface --- Samples/iOS-Swift/iOS-Swift/ViewController.swift | 1 + Sentry.xcodeproj/project.pbxproj | 8 ++++---- .../{include => Public}/SentryHttpStatusCodeRange.h | 0 Sources/Sentry/SentryHttpStatusCodeRange.m | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) rename Sources/Sentry/{include => Public}/SentryHttpStatusCodeRange.h (100%) diff --git a/Samples/iOS-Swift/iOS-Swift/ViewController.swift b/Samples/iOS-Swift/iOS-Swift/ViewController.swift index 15f0f4b730e..4f60c4dec14 100644 --- a/Samples/iOS-Swift/iOS-Swift/ViewController.swift +++ b/Samples/iOS-Swift/iOS-Swift/ViewController.swift @@ -91,6 +91,7 @@ class ViewController: UIViewController { _ = FileManager.default.contents(atPath: path) } } + guard let imgUrl = URL(string: "https://sentry-brand.storage.googleapis.com/sentry-logo-black.png") else { return } diff --git a/Sentry.xcodeproj/project.pbxproj b/Sentry.xcodeproj/project.pbxproj index ff48ed9af1b..d2785f61b4b 100644 --- a/Sentry.xcodeproj/project.pbxproj +++ b/Sentry.xcodeproj/project.pbxproj @@ -661,9 +661,9 @@ A811D867248E2770008A41EA /* SentrySystemEventBreadcrumbsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = A811D866248E2770008A41EA /* SentrySystemEventBreadcrumbsTest.swift */; }; A839D89824864B80003B7AFD /* SentrySystemEventBreadcrumbs.h in Headers */ = {isa = PBXBuildFile; fileRef = A839D89724864B80003B7AFD /* SentrySystemEventBreadcrumbs.h */; }; A839D89A24864BA8003B7AFD /* SentrySystemEventBreadcrumbs.m in Sources */ = {isa = PBXBuildFile; fileRef = A839D89924864BA8003B7AFD /* SentrySystemEventBreadcrumbs.m */; }; + A8AFFCCD29069C3E00967CD7 /* SentryHttpStatusCodeRange.h in Headers */ = {isa = PBXBuildFile; fileRef = A8AFFCCC29069C3E00967CD7 /* SentryHttpStatusCodeRange.h */; settings = {ATTRIBUTES = (Public, ); }; }; A8F17B2C29016BD100990B25 /* SentryRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = A8F17B2B29016BD100990B25 /* SentryRequest.h */; }; A8F17B2E2901765900990B25 /* SentryRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = A8F17B2D2901765900990B25 /* SentryRequest.m */; }; - A8F17B32290283C100990B25 /* SentryHttpStatusCodeRange.h in Headers */ = {isa = PBXBuildFile; fileRef = A8F17B31290283C100990B25 /* SentryHttpStatusCodeRange.h */; }; A8F17B342902870300990B25 /* SentryHttpStatusCodeRange.m in Sources */ = {isa = PBXBuildFile; fileRef = A8F17B332902870300990B25 /* SentryHttpStatusCodeRange.m */; }; D8019910286B089000C277F0 /* SentryCrashReportSinkTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = D801990F286B089000C277F0 /* SentryCrashReportSinkTest.swift */; }; D808FB88281AB33C009A2A33 /* SentryUIEventTrackerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D808FB86281AB31D009A2A33 /* SentryUIEventTrackerTests.swift */; }; @@ -1448,9 +1448,9 @@ A811D866248E2770008A41EA /* SentrySystemEventBreadcrumbsTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentrySystemEventBreadcrumbsTest.swift; sourceTree = ""; }; A839D89724864B80003B7AFD /* SentrySystemEventBreadcrumbs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentrySystemEventBreadcrumbs.h; path = include/SentrySystemEventBreadcrumbs.h; sourceTree = ""; }; A839D89924864BA8003B7AFD /* SentrySystemEventBreadcrumbs.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentrySystemEventBreadcrumbs.m; sourceTree = ""; }; + A8AFFCCC29069C3E00967CD7 /* SentryHttpStatusCodeRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SentryHttpStatusCodeRange.h; path = Public/SentryHttpStatusCodeRange.h; sourceTree = ""; }; A8F17B2B29016BD100990B25 /* SentryRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SentryRequest.h; sourceTree = ""; }; A8F17B2D2901765900990B25 /* SentryRequest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryRequest.m; sourceTree = ""; }; - A8F17B31290283C100990B25 /* SentryHttpStatusCodeRange.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SentryHttpStatusCodeRange.h; sourceTree = ""; }; A8F17B332902870300990B25 /* SentryHttpStatusCodeRange.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryHttpStatusCodeRange.m; sourceTree = ""; }; D801990F286B089000C277F0 /* SentryCrashReportSinkTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryCrashReportSinkTest.swift; sourceTree = ""; }; D808FB86281AB31D009A2A33 /* SentryUIEventTrackerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryUIEventTrackerTests.swift; sourceTree = ""; }; @@ -2579,8 +2579,8 @@ 8E564AE7267AF22600FE117D /* SentryNetworkTracker.m */, D8370B6B273DF20F00F66E2D /* SentryNSURLSessionTaskSearch.h */, D8370B68273DF1E900F66E2D /* SentryNSURLSessionTaskSearch.m */, - A8F17B31290283C100990B25 /* SentryHttpStatusCodeRange.h */, A8F17B332902870300990B25 /* SentryHttpStatusCodeRange.m */, + A8AFFCCC29069C3E00967CD7 /* SentryHttpStatusCodeRange.h */, ); name = Network; sourceTree = ""; @@ -3004,7 +3004,7 @@ 8EA1ED0D2669028C00E62B98 /* SentryUIViewControllerSwizzling.h in Headers */, 7B98D7E425FB7A7200C5A389 /* SentryAppState.h in Headers */, 7BDEAA022632A4580001EA25 /* SentryOptions+Private.h in Headers */, - A8F17B32290283C100990B25 /* SentryHttpStatusCodeRange.h in Headers */, + A8AFFCCD29069C3E00967CD7 /* SentryHttpStatusCodeRange.h in Headers */, 15E0A8EA240F2C9000F044E3 /* SentrySerialization.h in Headers */, 63FE70EF20DA4C1000CDBAE8 /* SentryCrashMonitor_AppState.h in Headers */, 635B3F381EBC6E2500A6176D /* SentryAsynchronousOperation.h in Headers */, diff --git a/Sources/Sentry/include/SentryHttpStatusCodeRange.h b/Sources/Sentry/Public/SentryHttpStatusCodeRange.h similarity index 100% rename from Sources/Sentry/include/SentryHttpStatusCodeRange.h rename to Sources/Sentry/Public/SentryHttpStatusCodeRange.h diff --git a/Sources/Sentry/SentryHttpStatusCodeRange.m b/Sources/Sentry/SentryHttpStatusCodeRange.m index 9f0c7392c8b..d095752cf60 100644 --- a/Sources/Sentry/SentryHttpStatusCodeRange.m +++ b/Sources/Sentry/SentryHttpStatusCodeRange.m @@ -1,4 +1,4 @@ -#import +#import "SentryHttpStatusCodeRange.h" NS_ASSUME_NONNULL_BEGIN