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

Track all errors in Sentry #1558

Merged
merged 5 commits into from
Aug 24, 2022
Merged

Track all errors in Sentry #1558

merged 5 commits into from
Aug 24, 2022

Conversation

Anderas
Copy link
Contributor

@Anderas Anderas commented Aug 22, 2022

Following up on #1517, which tracked only some of MXLogError and MXLogFailure in analytics (Sentry for element-ios, assuming user consent), this PR extends this approach across the entire SDK and makes each error / failure trackable. This requires a number of changes:

  • add AnalyticsDestination to MXLog which sends errors to AnalyticsDelegate. Previous implementation simply hooked into the existing error methods and was a little hacky. Using destinations is the preffered approach
  • error and failure logs now require StaticString instead of String, meaning no variables can be present in the message. This may sound annoying but will make tracing of parameters more explicit by:
    • not accidentally leaking sensitive data
    • grouping errors by message without variable components
  • replace details argument with existing context argument that can be of any type. This is to both reduce the number of arguments as well as stay consistent with SwiftyBeaver
  • extract all variables from logs and pass them in the context, sometimes as a dictionary of values (this is the largest number of changes)

@Anderas Anderas marked this pull request as ready for review August 22, 2022 16:25
@Anderas Anderas requested review from a team and pixlwave and removed request for a team August 22, 2022 16:26
@@ -153,7 +153,8 @@ - (void)checkAndStartWithKeyBackupVersion:(nullable MXKeyBackupVersion*)keyBacku
Class<MXKeyBackupAlgorithm> algorithmClass = AlgorithmClassesByName[keyBackupVersion.algorithm];
if (algorithmClass == NULL)
{
MXLogError(@"[MXKeyBackup] checkAndStartWithKeyBackupVersion: unknown algorithm: %@", keyBackupVersion.algorithm);
NSString *message = [NSString stringWithFormat:@"[MXKeyBackup] checkAndStartWithKeyBackupVersion: unknown algorithm: %@", keyBackupVersion.algorithm];
Copy link
Contributor Author

Choose a reason for hiding this comment

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

In some cases the variable is one of very few and it is okay making it a part of the message itself (objc has no StaticString equivalent, so this works)

@@ -653,7 +661,12 @@ - (MXEventDecryptionResult *)decryptEvent2:(MXEvent *)event inTimeline:(NSString
result = [alg decryptEvent:event inTimeline:timeline];
if (result.error)
{
MXLogError(@"[MXCrypto] decryptEvent: Error for %@: %@\nEvent: %@", event.eventId, result.error, event.JSONDictionary);
NSDictionary *details = @{
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Annoyingly objc will crash if we ever add nil value to a dictionary, meaning it is safer to always default to something rather than risk logs crashing the app

Copy link
Contributor

Choose a reason for hiding this comment

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

Whereabouts does this crash actually happen? I'm wondering if there would be an opportune place we could map all of the nil values in the dictionary into @"unknown" before the crash takes place?

Otherwise it kind of feels like it would be an easy place for someone to introduce a crash by either not knowing this pitfall, or by not realising a value is nullable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is the actual construction of dictionary, for example this will crash:

NSString *value = nil;
NSDictionary *dict = @{
  @"value": value // If I passed nil here directly the compiler would catch it
};

So we can't really put any kind of safety wrapper around it. The rest of the codebase has this issue as well but is seems we rarely have unexpected nil values. My justification for allowing this was that most new code we write is in swift and thus we won't be really adding new dictionary contexts in objective-c, but of course I could be wrong

Copy link
Contributor

Choose a reason for hiding this comment

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

TIL that this is standard objc behaviour! Ignore me 🤐

@codecov-commenter
Copy link

codecov-commenter commented Aug 23, 2022

Codecov Report

Merging #1558 (5f4c854) into develop (62ec1ec) will decrease coverage by 0.07%.
The diff coverage is 12.67%.

@@             Coverage Diff             @@
##           develop    #1558      +/-   ##
===========================================
- Coverage    45.25%   45.17%   -0.08%     
===========================================
  Files          520      521       +1     
  Lines        84791    84957     +166     
  Branches     37520    37500      -20     
===========================================
+ Hits         38369    38381      +12     
- Misses       45320    45476     +156     
+ Partials      1102     1100       -2     
Impacted Files Coverage Δ
...gations/LocationSharing/MXBeaconAggregations.swift 46.66% <0.00%> (-0.30%) ⬇️
...ng/Store/Realm/MXBeaconInfoSummaryRealmStore.swift 69.37% <0.00%> (ø)
...rixSDK/Aggregations/MXAggregatedReactionsUpdater.m 84.51% <0.00%> (-0.37%) ⬇️
MatrixSDK/Background/MXBackgroundSyncService.swift 63.25% <0.00%> (-0.35%) ⬇️
...atrixSDK/Crypto/Dehydration/MXDehydrationService.m 59.57% <0.00%> (-3.35%) ⬇️
...KeyBackup/Data/Aes256/MXAes256KeyBackupAlgorithm.m 74.76% <0.00%> (-0.72%) ⬇️
...p/Data/Curve25519/MXCurve25519KeyBackupAlgorithm.m 70.00% <0.00%> (-0.84%) ⬇️
MatrixSDK/Crypto/KeyBackup/MXKeyBackup.m 69.47% <0.00%> (-0.19%) ⬇️
...SDK/Crypto/Verification/MXKeyVerificationManager.m 4.06% <0.00%> (-0.01%) ⬇️
...xSDK/Data/EventTimeline/Room/MXRoomEventTimeline.m 74.29% <0.00%> (-0.25%) ⬇️
... and 37 more

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

Copy link
Contributor

@pixlwave pixlwave left a comment

Choose a reason for hiding this comment

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

This looks like a great change overall to me 😎

@@ -552,7 +554,9 @@ - (void)setIsEncrypted:(BOOL)isEncrypted
// This should never happen
if (_isEncrypted && !isEncrypted)
{
MXLogError(@"[MXRoomSummary] setIsEncrypted: Attempt to reset isEncrypted for room %@. Ignote it. Call stack: %@", self.roomId, [NSThread callStackSymbols]);
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm presuming we don't need to worry about call stacks now that these go to Sentry.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Exactly, though it will be missing from rageshake files ... I think that is okay?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yep yep, makes sense to me 👍

@@ -993,7 +993,7 @@ - (RoomReceiptsStore*)getOrCreateRoomReceiptsStore:(NSString *)roomId
@"roomId": roomId ?: @"",
@"exception": exception
};
MXLogErrorWithDetails(@"[MXFileStore] Warning: loadReceipts file for room as been corrupted", logDetails);
// MXLogErrorWithDetails(@"[MXFileStore] Warning: loadReceipts file for room as been corrupted", logDetails);
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this intentionally left commented?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oops sorry, thanks

import SwiftyBeaver

/// SwiftyBeaver log destination that sends errors to analytics tracker
class AnalyticsDestination: BaseDestination {
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe this should be MXAnalyticsDestination?

}

// TODO: failure context
Copy link
Contributor

Choose a reason for hiding this comment

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

Is that todo different to the MXLogFailures above?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Missed that, thanks 🤦


/// Log failure with additional details
///
/// A failure is any type of programming error which should never occur in production. In `DEBUG` confuguration
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
/// A failure is any type of programming error which should never occur in production. In `DEBUG` confuguration
/// A failure is any type of programming error which should never occur in production. In `DEBUG` configuration

}
}

/// Convenience wrapper around `MXLog` which formats all logs as "[Name] function: <message>"
///
/// Note: Ideallly the `format` of `ConsoleDestination` is set to track filename and function automatically
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
/// Note: Ideallly the `format` of `ConsoleDestination` is set to track filename and function automatically
/// Note: Ideally the `format` of `ConsoleDestination` is set to track filename and function automatically

@@ -653,7 +661,12 @@ - (MXEventDecryptionResult *)decryptEvent2:(MXEvent *)event inTimeline:(NSString
result = [alg decryptEvent:event inTimeline:timeline];
if (result.error)
{
MXLogError(@"[MXCrypto] decryptEvent: Error for %@: %@\nEvent: %@", event.eventId, result.error, event.JSONDictionary);
NSDictionary *details = @{
Copy link
Contributor

Choose a reason for hiding this comment

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

Whereabouts does this crash actually happen? I'm wondering if there would be an opportune place we could map all of the nil values in the dictionary into @"unknown" before the crash takes place?

Otherwise it kind of feels like it would be an easy place for someone to introduce a crash by either not knowing this pitfall, or by not realising a value is nullable.

@Anderas Anderas requested a review from pixlwave August 23, 2022 13:33
Copy link
Contributor

@pixlwave pixlwave left a comment

Choose a reason for hiding this comment

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

LGTM 👍

@Anderas Anderas merged commit 66a3c3f into develop Aug 24, 2022
@Anderas Anderas deleted the andy/sentry branch August 24, 2022 07:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants