Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add name and geo to User #2710

Merged
merged 29 commits into from
Mar 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
5da7181
add name to user
denrase Feb 21, 2023
2ccf64e
Merge branch 'main' into feat/user-name-and-geo
denrase Feb 21, 2023
59ed2ae
add geo
denrase Feb 21, 2023
7dcc3ce
add geo to user
denrase Feb 21, 2023
9f36ea3
add changelog entry
denrase Feb 21, 2023
c7de7cd
Format code
getsentry-bot Feb 21, 2023
83abdfd
add files to project and fix tests
denrase Feb 21, 2023
7c61c2d
Merge branch 'feat/user-name-and-geo' of github.com:getsentry/sentry-…
denrase Feb 21, 2023
afd5daf
change prop to strong
denrase Feb 21, 2023
2f6437e
use correct nullable syntax
denrase Feb 27, 2023
d8e4d8e
copy geo
denrase Feb 27, 2023
ba0f3f5
use assignment syntax
denrase Feb 27, 2023
f5dd593
use shorter init syntax
denrase Feb 27, 2023
a687e50
Merge branch 'main' into feat/user-name-and-geo
denrase Feb 27, 2023
c4d82c6
move entry to unreleased section
denrase Feb 27, 2023
dde6b42
Merge branch 'main' into feat/user-name-and-geo
denrase Mar 7, 2023
7d6693c
use diefferent nullability syntax
denrase Mar 7, 2023
f497206
add newline
denrase Mar 7, 2023
a76140e
Merge branch 'main' into feat/user-name-and-geo
denrase Mar 13, 2023
2bf9294
remove redundant init override
denrase Mar 13, 2023
f3aef79
Merge branch 'main' into feat/user-name-and-geo
denrase Mar 20, 2023
990c8ea
remove synchronized blocks in geo, handle name in user
denrase Mar 20, 2023
3c261e0
Format code
getsentry-bot Mar 20, 2023
f41a14e
Merge branch 'main' into feat/user-name-and-geo
denrase Mar 27, 2023
ba655db
refactor code
denrase Mar 27, 2023
7d04382
add sample data in comment
denrase Mar 27, 2023
70cc238
Format code
getsentry-bot Mar 27, 2023
d929410
update changelog entry
denrase Mar 27, 2023
6cc9013
Merge branch 'main' into feat/user-name-and-geo
denrase Mar 28, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

### Features

- Add `name` and `geo` to User (#2710)
### Fixes

- Correctly track and send GPU frame render data in profiles (#2823)
Expand Down
12 changes: 12 additions & 0 deletions Sentry.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,9 @@
8ED2D28026A6581C00CA8329 /* NSURLProtocolSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = 8ED2D27F26A6581C00CA8329 /* NSURLProtocolSwizzle.m */; };
8ED3D306264DFE700049393B /* SwiftDescriptorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8ED3D305264DFE700049393B /* SwiftDescriptorTests.swift */; };
8EE017A126704CD500470616 /* SentryUIViewControllerPerformanceTrackerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EA1ED0E2669152F00E62B98 /* SentryUIViewControllerPerformanceTrackerTests.swift */; };
9286059529A5096600F96038 /* SentryGeo.h in Headers */ = {isa = PBXBuildFile; fileRef = 9286059429A5096600F96038 /* SentryGeo.h */; settings = {ATTRIBUTES = (Public, ); }; };
9286059729A5098900F96038 /* SentryGeo.m in Sources */ = {isa = PBXBuildFile; fileRef = 9286059629A5098900F96038 /* SentryGeo.m */; };
9286059929A50BAB00F96038 /* SentryGeoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9286059829A50BAA00F96038 /* SentryGeoTests.swift */; };
A2475E1325FB63A3007D9080 /* fishhook.h in Headers */ = {isa = PBXBuildFile; fileRef = A2475E1225FB63A3007D9080 /* fishhook.h */; };
A2475E1725FB63AF007D9080 /* SentryHook.h in Headers */ = {isa = PBXBuildFile; fileRef = A2475E1625FB63AF007D9080 /* SentryHook.h */; };
A2475E1B25FB63D7007D9080 /* SentryHook.c in Sources */ = {isa = PBXBuildFile; fileRef = A2475E1A25FB63D7007D9080 /* SentryHook.c */; };
Expand Down Expand Up @@ -1589,6 +1592,9 @@
8ED2D27E26A6581C00CA8329 /* NSURLProtocolSwizzle.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NSURLProtocolSwizzle.h; sourceTree = "<group>"; };
8ED2D27F26A6581C00CA8329 /* NSURLProtocolSwizzle.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NSURLProtocolSwizzle.m; sourceTree = "<group>"; };
8ED3D305264DFE700049393B /* SwiftDescriptorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftDescriptorTests.swift; sourceTree = "<group>"; };
9286059429A5096600F96038 /* SentryGeo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SentryGeo.h; path = Public/SentryGeo.h; sourceTree = "<group>"; };
9286059629A5098900F96038 /* SentryGeo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SentryGeo.m; sourceTree = "<group>"; };
9286059829A50BAA00F96038 /* SentryGeoTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SentryGeoTests.swift; sourceTree = "<group>"; };
A2475E1225FB63A3007D9080 /* fishhook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fishhook.h; sourceTree = "<group>"; };
A2475E1625FB63AF007D9080 /* SentryHook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SentryHook.h; sourceTree = "<group>"; };
A2475E1A25FB63D7007D9080 /* SentryHook.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SentryHook.c; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1836,6 +1842,8 @@
639FCF9B1EBC7F9500778193 /* SentryThread.m */,
639FCFAA1EBC811400778193 /* SentryUser.h */,
639FCFAB1EBC811400778193 /* SentryUser.m */,
9286059429A5096600F96038 /* SentryGeo.h */,
9286059629A5098900F96038 /* SentryGeo.m */,
63B818F71EC34639002FDF4C /* SentryDebugMeta.h */,
63B818F81EC34639002FDF4C /* SentryDebugMeta.m */,
6360850B1ED2AFE100E8599E /* SentryBreadcrumb.h */,
Expand Down Expand Up @@ -2507,6 +2515,7 @@
7B6D98E824C6D336005502FA /* SentrySdkInfo+Equality.m */,
7B82D54824E2A2D400EE670F /* SentryIdTests.swift */,
7B04A9AA24EA5F8D00E710B1 /* SentryUserTests.swift */,
9286059829A50BAA00F96038 /* SentryGeoTests.swift */,
7BB42EEF24F3B7B700D7B39A /* SentrySession+Equality.h */,
7BB42EF024F3B7B700D7B39A /* SentrySession+Equality.m */,
7B0A5451252311CE00A71716 /* SentryBreadcrumbTests.swift */,
Expand Down Expand Up @@ -3519,6 +3528,7 @@
63FE714F20DA4C1100CDBAE8 /* NSError+SentrySimpleConstructor.h in Headers */,
7BC5B6FA290BCDE500D99477 /* SentryHttpStatusCodeRange+Private.h in Headers */,
7B04A9AF24EAC02C00E710B1 /* SentryRetryAfterHeaderParser.h in Headers */,
9286059529A5096600F96038 /* SentryGeo.h in Headers */,
7DC83100239826280043DD9A /* SentryIntegrationProtocol.h in Headers */,
7B98D7BC25FB607300C5A389 /* SentryWatchdogTerminationTracker.h in Headers */,
7BA61CB9247BC57B00C130A8 /* SentryCrashDefaultBinaryImageProvider.h in Headers */,
Expand Down Expand Up @@ -3974,6 +3984,7 @@
7B98D7CF25FB650F00C5A389 /* SentryWatchdogTerminationTrackingIntegration.m in Sources */,
8E5D38DD261D4A3E000D363D /* SentryPerformanceTrackingIntegration.m in Sources */,
7B4E23C2251A2C2B00060D68 /* SentrySessionCrashedHandler.m in Sources */,
9286059729A5098900F96038 /* SentryGeo.m in Sources */,
7B42C48227E08F4B009B58C2 /* SentryDependencyContainer.m in Sources */,
7BA61E9225F21AF80008CAA2 /* SentryLogOutput.m in Sources */,
639FCFAD1EBC811400778193 /* SentryUser.m in Sources */,
Expand Down Expand Up @@ -4076,6 +4087,7 @@
0A5370A128A3EC2400B2DCDE /* SentryViewHierarchyTests.swift in Sources */,
D8FFE50C2703DBB400607131 /* SwizzlingCallTests.swift in Sources */,
7BFAA6E7297AA16A00E7E02E /* SentryCrashMonitor_CppException_Tests.mm in Sources */,
9286059929A50BAB00F96038 /* SentryGeoTests.swift in Sources */,
D8B76B0828081461000A58C4 /* TestSentryScreenShot.swift in Sources */,
A8AFFCD22907DA7600967CD7 /* SentryHttpStatusCodeRangeTests.swift in Sources */,
7BE2C7F8257000A4003B66C7 /* SentryTestIntegration.m in Sources */,
Expand Down
1 change: 1 addition & 0 deletions Sources/Sentry/Public/Sentry.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ FOUNDATION_EXPORT const unsigned char SentryVersionString[];
#import "SentryEvent.h"
#import "SentryException.h"
#import "SentryFrame.h"
#import "SentryGeo.h"
#import "SentryHttpStatusCodeRange.h"
#import "SentryHub.h"
#import "SentryId.h"
Expand Down
2 changes: 1 addition & 1 deletion Sources/Sentry/Public/SentryDebugMeta.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ NS_SWIFT_NAME(DebugMeta)
/**
* Name of the image. Use @c codeFile when using "macho" as the @c type .
*/
@property (nonatomic, copy) NSString *_Nullable name;
@property (nullable, nonatomic, copy) NSString *name;

/**
* The size of the image in virtual memory. If missing, Sentry will assume that the image spans up
Expand Down
43 changes: 43 additions & 0 deletions Sources/Sentry/Public/SentryGeo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#import "SentryDefines.h"
#import "SentrySerializable.h"
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

/// Approximate geographical location of the end user or device.
///
/// Example of serialized data:
/// {
/// "geo": {
/// "country_code": "US",
/// "city": "Ashburn",
/// "region": "San Francisco"
/// }
/// }
NS_SWIFT_NAME(Geo)
@interface SentryGeo : NSObject <SentrySerializable, NSCopying>

/**
* Optional: Human readable city name.
*/
@property (nullable, atomic, copy) NSString *city;

/**
* Optional: Two-letter country code (ISO 3166-1 alpha-2).
*/
@property (nullable, atomic, copy) NSString *countryCode;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we can't just grab the NSLocale object that would probably be used to populate this, so we can get any other info from that we need at a later date, as well as ensure the right value is actually set in our serialize implementation (there's a lot going on in NSLocale and some people might not get it right).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As i understood this is filled out manually by users, so i'm not sure if we should do things automatically to populate these fields. What other info that we might need are you refering to?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose even if we know sure we won't want anything other than country code, we could still just get it directly from the NSLocale. I've seen plenty of mistakes mixing up country codes, language codes and locale identifiers. I would ask for some validation logic, but that would be more work than us just using the locale object in a known safe way.

this is filled out manually by users

Do you mean end-users of apps consuming this SDK? Or users of the SDK, as in app developers? If the former, even more reason to validate input, but again, that's more work.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the server infers that automatically from the IP if provided, this should only be set if the user wanna override the inferred value by the server as explained here #2710 (comment)


/**
* Optional: Human readable region name or code.
*/
@property (nullable, atomic, copy) NSString *region;
denrase marked this conversation as resolved.
Show resolved Hide resolved

- (BOOL)isEqual:(id _Nullable)other;

- (BOOL)isEqualToGeo:(SentryGeo *)geo;

- (NSUInteger)hash;

@end

NS_ASSUME_NONNULL_END
13 changes: 13 additions & 0 deletions Sources/Sentry/Public/SentryUser.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
#import "SentryDefines.h"
#import "SentryGeo.h"
#import "SentrySerializable.h"

NS_ASSUME_NONNULL_BEGIN

@class SentryGeo;

NS_SWIFT_NAME(User)
@interface SentryUser : NSObject <SentrySerializable, NSCopying>

Expand Down Expand Up @@ -31,6 +34,16 @@ NS_SWIFT_NAME(User)
*/
@property (atomic, copy) NSString *_Nullable segment;

/**
* Optional: Human readable name
*/
@property (atomic, copy) NSString *_Nullable name;
philipphofmann marked this conversation as resolved.
Show resolved Hide resolved
denrase marked this conversation as resolved.
Show resolved Hide resolved

/**
* Optional: Geo location of user
*/
@property (nullable, nonatomic, strong) SentryGeo *geo;

/**
* Optional: Additional data
*/
Expand Down
80 changes: 80 additions & 0 deletions Sources/Sentry/SentryGeo.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#import "SentryGeo.h"

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@implementation SentryGeo

- (id)copyWithZone:(nullable NSZone *)zone
{
SentryGeo *copy = [[[self class] allocWithZone:zone] init];

if (copy != nil) {
copy.city = self.city;
copy.countryCode = self.countryCode;
copy.region = self.region;
}

return copy;
}

- (NSDictionary<NSString *, id> *)serialize
{
return @{ @"city" : self.city, @"country_code" : self.countryCode, @"region" : self.region };
}

- (BOOL)isEqual:(id _Nullable)other
{
if (other == self) {
return YES;
}
if (!other || ![[other class] isEqual:[self class]]) {
return NO;
}

return [self isEqualToGeo:other];
}

- (BOOL)isEqualToGeo:(SentryGeo *)geo
{
if (self == geo) {
return YES;
}
if (geo == nil) {
return NO;
}

NSString *otherCity = geo.city;
if (self.city != otherCity && ![self.city isEqualToString:otherCity]) {
return NO;
}

NSString *otherCountryCode = geo.countryCode;
if (self.countryCode != otherCountryCode
&& ![self.countryCode isEqualToString:otherCountryCode]) {
return NO;
}

NSString *otherRegion = geo.region;
if (self.region != otherRegion && ![self.region isEqualToString:otherRegion]) {
return NO;
}

return YES;
}

- (NSUInteger)hash
{
NSUInteger hash = 17;

hash = hash * 23 + [self.city hash];
hash = hash * 23 + [self.countryCode hash];
hash = hash * 23 + [self.region hash];

return hash;
}

@end

NS_ASSUME_NONNULL_END
16 changes: 16 additions & 0 deletions Sources/Sentry/SentryUser.m
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ - (id)copyWithZone:(nullable NSZone *)zone
copy.username = self.username;
copy.ipAddress = self.ipAddress;
copy.segment = self.segment;
copy.name = self.name;
copy.geo = self.geo.copy;
copy.data = self.data.copy;
}

Expand All @@ -44,6 +46,8 @@ - (id)copyWithZone:(nullable NSZone *)zone
[serializedData setValue:self.username forKey:@"username"];
[serializedData setValue:self.ipAddress forKey:@"ip_address"];
[serializedData setValue:self.segment forKey:@"segment"];
[serializedData setValue:self.name forKey:@"name"];
[serializedData setValue:[self.geo serialize] forKey:@"geo"];
[serializedData setValue:[self.data sentry_sanitize] forKey:@"data"];

return serializedData;
Expand Down Expand Up @@ -96,6 +100,16 @@ - (BOOL)isEqualToUser:(SentryUser *)user
return NO;
}

NSString *otherName = user.name;
if (self.name != otherName && ![self.name isEqualToString:otherName]) {
return NO;
}

SentryGeo *otherGeo = user.geo;
if (self.geo != otherGeo && ![self.geo isEqualToGeo:otherGeo]) {
return NO;
}

NSDictionary<NSString *, id> *otherUserData = user.data;
if (self.data != otherUserData && ![self.data isEqualToDictionary:otherUserData]) {
return NO;
Expand All @@ -113,6 +127,8 @@ - (NSUInteger)hash
hash = hash * 23 + [self.username hash];
hash = hash * 23 + [self.ipAddress hash];
hash = hash * 23 + [self.segment hash];
hash = hash * 23 + [self.name hash];
hash = hash * 23 + [self.geo hash];
hash = hash * 23 + [self.data hash];

return hash;
Expand Down
62 changes: 62 additions & 0 deletions Tests/SentryTests/Protocol/SentryGeoTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import XCTest

class SentryGeoTests: XCTestCase {
philipphofmann marked this conversation as resolved.
Show resolved Hide resolved
func testSerializationWithAllProperties() {
let geo = TestData.geo.copy() as! Geo
let actual = geo.serialize()

// Changing the original doesn't modify the serialized
geo.city = ""
geo.countryCode = ""
geo.region = ""

XCTAssertEqual(TestData.geo.city, actual["city"] as? String)
XCTAssertEqual(TestData.geo.countryCode, actual["country_code"] as? String)
XCTAssertEqual(TestData.geo.region, actual["region"] as? String)
}

func testHash() {
XCTAssertEqual(TestData.geo.hash(), TestData.geo.hash())

let geo2 = TestData.geo
geo2.city = "Berlin"
XCTAssertNotEqual(TestData.geo.hash(), geo2.hash())
}

func testIsEqualToSelf() {
XCTAssertEqual(TestData.geo, TestData.geo)
XCTAssertTrue(TestData.geo.isEqual(to: TestData.geo))
}

func testIsNotEqualToOtherClass() {
XCTAssertFalse(TestData.geo.isEqual(1))
}

func testIsEqualToCopy() {
XCTAssertEqual(TestData.geo, TestData.geo.copy() as! Geo)
}

func testNotIsEqual() {
testIsNotEqual { geo in geo.city = "" }
testIsNotEqual { geo in geo.countryCode = "" }
testIsNotEqual { geo in geo.region = "" }
}

func testIsNotEqual(block: (Geo) -> Void ) {
let geo = TestData.geo.copy() as! Geo
block(geo)
XCTAssertNotEqual(TestData.geo, geo)
}

func testCopyWithZone_CopiesDeepCopy() {
let geo = TestData.geo
let copiedGeo = geo.copy() as! Geo

// Modifying the original does not change the copy
geo.city = ""
geo.countryCode = ""
geo.region = ""

XCTAssertEqual(TestData.geo, copiedGeo)
}
}
Loading