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

feat: add culture context to event #2036

Merged
merged 8 commits into from
Aug 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
### Features

- Include app permissions with event (#1984)
- Add culture context to event (#2036)

## 7.23.0

Expand Down
8 changes: 8 additions & 0 deletions Sentry.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
03F9D37C2819A65C00602916 /* SentryProfilerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 03F9D37B2819A65C00602916 /* SentryProfilerTests.mm */; };
0A1C3592287D7107007D01E3 /* SentryMetaTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A1C3591287D7107007D01E3 /* SentryMetaTests.swift */; };
0A2690B72885C2E000E4432D /* TestSentryPermissionsObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AABE2EF2885C2120057ED69 /* TestSentryPermissionsObserver.swift */; };
0A2D8D9628997845008720F6 /* NSLocale+Sentry.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A2D8D9428997845008720F6 /* NSLocale+Sentry.m */; };
0A2D8D9828997887008720F6 /* NSLocale+Sentry.h in Headers */ = {isa = PBXBuildFile; fileRef = 0A2D8D9728997887008720F6 /* NSLocale+Sentry.h */; };
0A8F0A392886CC70000B15F6 /* SentryPermissionsObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 0AABE2EE288592750057ED69 /* SentryPermissionsObserver.h */; };
0AABE2ED2885924A0057ED69 /* SentryPermissionsObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 0AABE2EC2885924A0057ED69 /* SentryPermissionsObserver.m */; };
15360CCF2432777500112302 /* SentrySessionTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = 15360CCE2432777400112302 /* SentrySessionTracker.m */; };
Expand Down Expand Up @@ -716,6 +718,8 @@
03F84D3127DD4191008FE43F /* SentryBacktrace.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SentryBacktrace.cpp; path = Sources/Sentry/SentryBacktrace.cpp; sourceTree = SOURCE_ROOT; };
03F9D37B2819A65C00602916 /* SentryProfilerTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SentryProfilerTests.mm; sourceTree = "<group>"; };
0A1C3591287D7107007D01E3 /* SentryMetaTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryMetaTests.swift; sourceTree = "<group>"; };
0A2D8D9428997845008720F6 /* NSLocale+Sentry.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSLocale+Sentry.m"; sourceTree = "<group>"; };
0A2D8D9728997887008720F6 /* NSLocale+Sentry.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "NSLocale+Sentry.h"; path = "include/NSLocale+Sentry.h"; sourceTree = "<group>"; };
0AABE2EC2885924A0057ED69 /* SentryPermissionsObserver.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryPermissionsObserver.m; sourceTree = "<group>"; };
0AABE2EE288592750057ED69 /* SentryPermissionsObserver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryPermissionsObserver.h; path = include/SentryPermissionsObserver.h; sourceTree = "<group>"; };
0AABE2EF2885C2120057ED69 /* TestSentryPermissionsObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestSentryPermissionsObserver.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1555,6 +1559,8 @@
861265F82404EC1500C4AFDE /* NSArray+SentrySanitize.m */,
7B6438A826A70F24000D0F65 /* UIViewController+Sentry.h */,
7B6438A926A70F24000D0F65 /* UIViewController+Sentry.m */,
0A2D8D9728997887008720F6 /* NSLocale+Sentry.h */,
0A2D8D9428997845008720F6 /* NSLocale+Sentry.m */,
);
name = Categories;
sourceTree = "<group>";
Expand Down Expand Up @@ -3012,6 +3018,7 @@
7BD729962463E83300EA3610 /* SentryDateUtil.h in Headers */,
63FE707B20DA4C1000CDBAE8 /* Container+SentryDeepSearch.h in Headers */,
6344DDB91EC3115C00D9160D /* SentryCrashReportConverter.h in Headers */,
0A2D8D9828997887008720F6 /* NSLocale+Sentry.h in Headers */,
71F116E8F40D530BB68A2987 /* SentryCrashUUIDConversion.h in Headers */,
A2475E1725FB63AF007D9080 /* SentryHook.h in Headers */,
);
Expand Down Expand Up @@ -3127,6 +3134,7 @@
63FE717B20DA4C1100CDBAE8 /* SentryCrashReport.c in Sources */,
7B7A599726B692F00060A676 /* SentryScreenFrames.m in Sources */,
7B3398652459C15200BD9C96 /* SentryEnvelopeRateLimit.m in Sources */,
0A2D8D9628997845008720F6 /* NSLocale+Sentry.m in Sources */,
A2475E1F25FB648B007D9080 /* fishhook.c in Sources */,
7BD4BD4527EB29F50071F4FF /* SentryClientReport.m in Sources */,
631E6D341EBC679C00712345 /* SentryQueueableRequestManager.m in Sources */,
Expand Down
18 changes: 18 additions & 0 deletions Sources/Sentry/NSLocale+Sentry.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#import "NSLocale+Sentry.h"

@implementation
NSLocale (Sentry)

- (BOOL)timeIs24HourFormat
{
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterNoStyle];
[formatter setTimeStyle:NSDateFormatterShortStyle];
NSString *dateString = [formatter stringFromDate:[NSDate date]];
NSRange amRange = [dateString rangeOfString:[formatter AMSymbol]];
NSRange pmRange = [dateString rangeOfString:[formatter PMSymbol]];
BOOL is24Hour = amRange.location == NSNotFound && pmRange.location == NSNotFound;
return is24Hour;
}

@end
29 changes: 28 additions & 1 deletion Sources/Sentry/SentryClient.m
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#import "SentryClient.h"
#import "NSDictionary+SentrySanitize.h"
#import "NSLocale+Sentry.h"
#import "SentryAttachment.h"
#import "SentryClient+Private.h"
#import "SentryCrashDefaultMachineContextWrapper.h"
Expand Down Expand Up @@ -59,6 +60,8 @@
@property (nonatomic, weak) id<SentryClientAttachmentProcessor> attachmentProcessor;
@property (nonatomic, strong) SentryCrashWrapper *crashWrapper;
@property (nonatomic, strong) SentryPermissionsObserver *permissionsObserver;
@property (nonatomic, strong) NSLocale *locale;
@property (nonatomic, strong) NSTimeZone *timezone;

@end

Expand Down Expand Up @@ -111,7 +114,9 @@ - (_Nullable instancetype)initWithOptions:(SentryOptions *)options
threadInspector:threadInspector
random:[SentryDependencyContainer sharedInstance].random
crashWrapper:[SentryCrashWrapper sharedInstance]
permissionsObserver:permissionsObserver];
permissionsObserver:permissionsObserver
locale:[NSLocale autoupdatingCurrentLocale]
timezone:[NSCalendar autoupdatingCurrentCalendar].timeZone];
}

- (instancetype)initWithOptions:(SentryOptions *)options
Expand All @@ -121,6 +126,8 @@ - (instancetype)initWithOptions:(SentryOptions *)options
random:(id<SentryRandom>)random
crashWrapper:(SentryCrashWrapper *)crashWrapper
permissionsObserver:(SentryPermissionsObserver *)permissionsObserver
locale:(NSLocale *)locale
timezone:(NSTimeZone *)timezone
{
if (self = [super init]) {
self.options = options;
Expand All @@ -131,6 +138,8 @@ - (instancetype)initWithOptions:(SentryOptions *)options
self.crashWrapper = crashWrapper;
self.permissionsObserver = permissionsObserver;
self.debugImageProvider = [SentryDependencyContainer sharedInstance].debugImageProvider;
self.locale = locale;
self.timezone = timezone;
}
return self;
}
Expand Down Expand Up @@ -510,6 +519,7 @@ - (SentryEvent *_Nullable)prepareEvent:(SentryEvent *)event
}

[self applyPermissionsToEvent:event];
[self applyCultureContextToEvent:event];

// With scope applied, before running callbacks run:
if (nil == event.environment) {
Expand Down Expand Up @@ -695,6 +705,23 @@ - (NSString *)stringForPermissionStatus:(SentryPermissionStatus)status
}
}

- (void)applyCultureContextToEvent:(SentryEvent *)event
{
[self modifyContext:event
key:@"culture"
block:^(NSMutableDictionary *culture) {
if (@available(iOS 10, macOS 10.12, watchOS 3, tvOS 10, macCatalyst 13, *)) {
culture[@"calendar"] = [self.locale
localizedStringForCalendarIdentifier:self.locale.calendarIdentifier];
culture[@"display_name"] = [self.locale
localizedStringForLocaleIdentifier:self.locale.localeIdentifier];
}
culture[@"locale"] = self.locale.localeIdentifier;
culture[@"is_24_hour_format"] = @(self.locale.timeIs24HourFormat);
culture[@"timezone"] = self.timezone.name;
}];
}

- (void)storeFreeMemoryToDeviceContext:(SentryEvent *)event
{
[self modifyContext:event
Expand Down
8 changes: 8 additions & 0 deletions Sources/Sentry/include/NSLocale+Sentry.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#import <Foundation/Foundation.h>

@interface
NSLocale (Sentry)

- (BOOL)timeIs24HourFormat;

@end
3 changes: 1 addition & 2 deletions Tests/SentryTests/Protocol/SentryDebugMetaEquality.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ extension DebugMeta {
if let other = object as? DebugMeta {
return uuid == other.uuid &&
type == other.type &&
name == other.name &&
imageSize == other.imageSize &&
name == other.name && imageSize == other.imageSize &&
imageAddress == other.imageAddress &&
imageVmAddress == other.imageVmAddress
} else {
Expand Down
3 changes: 1 addition & 2 deletions Tests/SentryTests/Protocol/SentryThreadEquality.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ extension Sentry.Thread {
return threadId == other.threadId &&
name == other.name &&
stacktrace == other.stacktrace &&
crashed == other.crashed &&
current == other.current
crashed == other.crashed && current == other.current
} else {
return false
}
Expand Down
4 changes: 3 additions & 1 deletion Tests/SentryTests/SentryClient+TestInit.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ SentryClient (TestInit)
threadInspector:(SentryThreadInspector *)threadInspector
random:(id<SentryRandom>)random
crashWrapper:(SentryCrashWrapper *)crashWrapper
permissionsObserver:(SentryPermissionsObserver *)permissionsObserver;
permissionsObserver:(SentryPermissionsObserver *)permissionsObserver
locale:(NSLocale *)locale
timezone:(NSTimeZone *)timezone;

@end

Expand Down
23 changes: 22 additions & 1 deletion Tests/SentryTests/SentryClientTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ class SentryClientTest: XCTestCase {
let transaction: Transaction
let crashWrapper = TestSentryCrashWrapper.sharedInstance()
let permissionsObserver = TestSentryPermissionsObserver()
let locale = Locale(identifier: "en_US")
let timezone = TimeZone(identifier: "Europe/Vienna")!

init() {
session = SentrySession(releaseName: "release")
Expand Down Expand Up @@ -68,7 +70,9 @@ class SentryClientTest: XCTestCase {
threadInspector: threadInspector,
random: random,
crashWrapper: crashWrapper,
permissionsObserver: permissionsObserver
permissionsObserver: permissionsObserver,
locale: locale,
timezone: timezone
)
} catch {
XCTFail("Options could not be created")
Expand Down Expand Up @@ -542,6 +546,23 @@ class SentryClientTest: XCTestCase {
}
}

func testCaptureCrash_Culture() {
let event = TestData.event
event.threads = nil
event.debugMeta = nil

fixture.getSut().captureCrash(event, with: fixture.scope)

assertLastSentEventWithAttachment { actual in
let culture = actual.context?["culture"]
XCTAssertEqual(culture?["calendar"] as? String, "Gregorian Calendar")
XCTAssertEqual(culture?["display_name"] as? String, "English (United States)")
XCTAssertEqual(culture?["locale"] as? String, "en_US")
XCTAssertEqual(culture?["is_24_hour_format"] as? Bool, false)
XCTAssertEqual(culture?["timezone"] as? String, "Europe/Vienna")
}
}

func testCaptureErrorWithUserInfo() {
let expectedValue = "val"
let error = NSError(domain: "domain", code: 0, userInfo: ["key": expectedValue])
Expand Down
14 changes: 12 additions & 2 deletions Tests/SentryTests/TestClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,19 @@ class TestClient: Client {

// Without this override we get a fatal error: use of unimplemented initializer
// see https://stackoverflow.com/questions/28187261/ios-swift-fatal-error-use-of-unimplemented-initializer-init
override init(options: Options, transportAdapter: SentryTransportAdapter, fileManager: SentryFileManager, threadInspector: SentryThreadInspector, random: SentryRandomProtocol, crashWrapper: SentryCrashWrapper, permissionsObserver: SentryPermissionsObserver) {
override init(options: Options, transportAdapter: SentryTransportAdapter, fileManager: SentryFileManager, threadInspector: SentryThreadInspector, random: SentryRandomProtocol, crashWrapper: SentryCrashWrapper, permissionsObserver: SentryPermissionsObserver, locale: Locale, timezone: TimeZone) {
sentryFileManager = try! SentryFileManager(options: options, andCurrentDateProvider: TestCurrentDateProvider())
super.init(options: options, transportAdapter: transportAdapter, fileManager: fileManager, threadInspector: threadInspector, random: random, crashWrapper: crashWrapper, permissionsObserver: permissionsObserver)
super.init(
options: options,
transportAdapter: transportAdapter,
fileManager: fileManager,
threadInspector: threadInspector,
random: random,
crashWrapper: crashWrapper,
permissionsObserver: permissionsObserver,
locale: locale,
timezone: timezone
)
}

override func fileManager() -> SentryFileManager {
Expand Down