Skip to content

Commit

Permalink
feat: add culture context to event (#2036)
Browse files Browse the repository at this point in the history
Added culture context to event payload
  • Loading branch information
kevinrenskers authored Aug 4, 2022
1 parent 4fb00e9 commit 04619e5
Show file tree
Hide file tree
Showing 10 changed files with 102 additions and 9 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

- Report App Memory Usage (#2027)
- 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 @@ -557,6 +561,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

0 comments on commit 04619e5

Please sign in to comment.