Add a “critical” severity level for analytics events.

// FREEBIE
pull/1/head
Matthew Chen 8 years ago
parent 9962c936c6
commit 543c05b2c5

@ -42,19 +42,19 @@
NS_ASSUME_NONNULL_BEGIN
#define kOWSProdAssertParameterEnvelopeIsLegacy @"envelope_is_legacy"
#define kOWSProdAssertParameterEnvelopeHasContent @"has_content"
#define kOWSProdAssertParameterEnvelopeDescription @"envelope_description"
#define kOWSProdAssertParameterEnvelopeEncryptedLength @"encrypted_length"
#define kOWSAnalyticsParameterEnvelopeIsLegacy @"envelope_is_legacy"
#define kOWSAnalyticsParameterEnvelopeHasContent @"has_content"
#define kOWSAnalyticsParameterEnvelopeDescription @"envelope_description"
#define kOWSAnalyticsParameterEnvelopeEncryptedLength @"encrypted_length"
#define AnalyticsParametersFromEnvelope(__envelope) \
^{ \
NSData *__encryptedData = __envelope.hasContent ? __envelope.content : __envelope.legacyMessage; \
return (@{ \
kOWSProdAssertParameterEnvelopeIsLegacy : @(__envelope.hasLegacyMessage), \
kOWSProdAssertParameterEnvelopeHasContent : @(__envelope.hasContent), \
kOWSProdAssertParameterEnvelopeDescription : [self descriptionForEnvelopeType:__envelope], \
kOWSProdAssertParameterEnvelopeEncryptedLength : @(__encryptedData.length), \
kOWSAnalyticsParameterEnvelopeIsLegacy : @(__envelope.hasLegacyMessage), \
kOWSAnalyticsParameterEnvelopeHasContent : @(__envelope.hasContent), \
kOWSAnalyticsParameterEnvelopeDescription : [self descriptionForEnvelopeType:__envelope], \
kOWSAnalyticsParameterEnvelopeEncryptedLength : @(__encryptedData.length), \
}); \
}

@ -121,14 +121,16 @@ static NSString *keychainDBPassAccount = @"TSDatabasePass";
// The best we can try to do is to discard the current database
// and behave like a clean install.
OWSProdError(@"storage_error_could_not_load_database");
// NOTE: This analytics event will never be delivered, since the database isn't working.
OWSProdCritical(@"storage_error_could_not_load_database");
// Try to reset app by deleting database.
// Disabled resetting storage until we have better data on why this happens.
// [self resetSignalStorage];
if (![self tryToLoadDatabase]) {
OWSProdError(@"storage_error_could_not_load_database_second_attempt");
// NOTE: This analytics event will never be delivered, since the database isn't working.
OWSProdCritical(@"storage_error_could_not_load_database_second_attempt");
[NSException raise:TSStorageManagerExceptionNameNoDatabase format:@"Failed to initialize database."];
}
@ -187,9 +189,9 @@ static NSString *keychainDBPassAccount = @"TSDatabasePass";
OWSProdErrorWParams(@"storage_error_deserialization", ^{
return (@{
@"collection" : collection,
kOWSProdAssertParameterNSExceptionName : exception.name,
kOWSProdAssertParameterNSExceptionReason : exception.reason,
kOWSProdAssertParameterNSExceptionClassName : NSStringFromClass([exception class]),
kOWSAnalyticsParameterNSExceptionName : exception.name,
kOWSAnalyticsParameterNSExceptionReason : exception.reason,
kOWSAnalyticsParameterNSExceptionClassName : NSStringFromClass([exception class]),
});
});
@throw exception;
@ -260,7 +262,8 @@ static NSString *keychainDBPassAccount = @"TSDatabasePass";
BOOL success = [ressourceURL setResourceValues:resourcesAttrs error:&error];
if (error || !success) {
OWSProdErrorWNSError(@"storage_error_file_protecion", error);
// NOTE: This analytics event will never be delivered, since the database isn't working.
OWSProdCriticalWNSError(@"storage_error_file_protection", error);
return;
}
}
@ -358,7 +361,8 @@ static NSString *keychainDBPassAccount = @"TSDatabasePass";
BOOL shouldHavePassword = [NSFileManager.defaultManager fileExistsAtPath:[self dbPath]];
if (shouldHavePassword) {
OWSProdError(@"storage_error_could_not_load_database_second_attempt");
// NOTE: This analytics event will never be delivered, since the database isn't working.
OWSProdCritical(@"storage_error_could_not_load_database_second_attempt");
}
// Try to reset app by deleting database.
@ -377,7 +381,8 @@ static NSString *keychainDBPassAccount = @"TSDatabasePass";
NSError *keySetError;
[SAMKeychain setPassword:newDBPassword forService:keychainService account:keychainDBPassAccount error:&keySetError];
if (keySetError) {
OWSProdErrorWNSError(@"storage_error_could_not_store_database_password", keySetError);
// NOTE: This analytics event will never be delivered, since the database isn't working.
OWSProdCriticalWNSError(@"storage_error_could_not_store_database_password", keySetError);
[self deletePasswordFromKeychain];

@ -6,23 +6,17 @@ NS_ASSUME_NONNULL_BEGIN
// TODO: We probably don't need all of these levels.
typedef NS_ENUM(NSUInteger, OWSAnalyticsSeverity) {
OWSAnalyticsSeverityDebug = 0,
// Info events are routine.
//
// It's safe to discard a large fraction of these events.
OWSAnalyticsSeverityInfo = 1,
OWSAnalyticsSeverityWarn = 2,
// Error events should never be discarded.
OWSAnalyticsSeverityError = 3,
// I suspect we'll stage the development of our analytics,
// initially building only a minimal solution: an endpoint which
// ignores most requests, and sends only the highest-severity
// events as email to developers.
//
// This "critical" level of severity is intended for that purpose (for now).
// Critical events should never be discarded.
//
// We might want to have an additional level of severity for
// critical (crashing) bugs that occur during app startup. These
// events should be sent to the service immediately and the app
// should block until that request completes.
OWSAnalyticsSeverityCritical = 4,
OWSAnalyticsSeverityOff = 5
// Additionally, to avoid losing critical events they should
// be persisted synchronously.
OWSAnalyticsSeverityCritical = 4
};
// This is a placeholder. We don't yet serialize or transmit analytics events.
@ -54,13 +48,32 @@ typedef NS_ENUM(NSUInteger, OWSAnalyticsSeverity) {
typedef NSDictionary<NSString *, id> *_Nonnull (^OWSProdAssertParametersBlock)();
#define kOWSProdAssertParameterDescription @"description"
#define kOWSProdAssertParameterNSErrorDomain @"nserror_domain"
#define kOWSProdAssertParameterNSErrorCode @"nserror_code"
#define kOWSProdAssertParameterNSErrorDescription @"nserror_description"
#define kOWSProdAssertParameterNSExceptionName @"nsexception_name"
#define kOWSProdAssertParameterNSExceptionReason @"nsexception_reason"
#define kOWSProdAssertParameterNSExceptionClassName @"nsexception_classname"
#define kOWSAnalyticsParameterDescription @"description"
#define kOWSAnalyticsParameterNSErrorDomain @"nserror_domain"
#define kOWSAnalyticsParameterNSErrorCode @"nserror_code"
#define kOWSAnalyticsParameterNSErrorDescription @"nserror_description"
#define kOWSAnalyticsParameterNSExceptionName @"nsexception_name"
#define kOWSAnalyticsParameterNSExceptionReason @"nsexception_reason"
#define kOWSAnalyticsParameterNSExceptionClassName @"nsexception_classname"
#define AnalyticsParametersFromNSError(__nserror) \
^{ \
return (@{ \
kOWSAnalyticsParameterNSErrorDomain : (__nserror.domain ?: @"unknown"), \
kOWSAnalyticsParameterNSErrorCode : @(__nserror.code), \
kOWSAnalyticsParameterNSErrorDescription : (__nserror.description ?: @"unknown"), \
}); \
}
#define AnalyticsParametersFromNSException(__exception) \
^{ \
return (@{ \
kOWSAnalyticsParameterNSExceptionName : (__exception.name ?: @"unknown"), \
kOWSAnalyticsParameterNSExceptionReason : (__exception.reason ?: @"unknown"), \
kOWSAnalyticsParameterNSExceptionClassName : \
(__exception ? NSStringFromClass([__exception class]) : @"unknown"), \
}); \
}
// These methods should be used to assert errors for which we want to fire analytics events.
//
@ -116,25 +129,6 @@ typedef NSDictionary<NSString *, id> *_Nonnull (^OWSProdAssertParametersBlock)()
#define OWSProdCFail(__analyticsEventName) OWSProdCFailWParams(__analyticsEventName, nil)
#define AnalyticsParametersFromNSError(__nserror) \
^{ \
return (@{ \
kOWSProdAssertParameterNSErrorDomain : (__nserror.domain ?: @"unknown"), \
kOWSProdAssertParameterNSErrorCode : @(__nserror.code), \
kOWSProdAssertParameterNSErrorDescription : (__nserror.description ?: @"unknown"), \
}); \
}
#define AnalyticsParametersFromNSException(__exception) \
^{ \
return (@{ \
kOWSProdAssertParameterNSExceptionName : (__exception.name ?: @"unknown"), \
kOWSProdAssertParameterNSExceptionReason : (__exception.reason ?: @"unknown"), \
kOWSProdAssertParameterNSExceptionClassName : \
(__exception ? NSStringFromClass([__exception class]) : @"unknown"), \
}); \
}
#define OWSProdFailWNSError(__analyticsEventName, __nserror) \
{ \
DDLogError(@"%s:%d %@: %@", __PRETTY_FUNCTION__, __LINE__, __analyticsEventName, __nserror.debugDescription); \
@ -147,28 +141,32 @@ typedef NSDictionary<NSString *, id> *_Nonnull (^OWSProdAssertParametersBlock)()
OWSProdFailWParams(__analyticsEventName, AnalyticsParametersFromNSException(__exception)) \
}
#define OWSProdCFail(__analyticsEventName) OWSProdCFailWParams(__analyticsEventName, nil)
#define OWSProdEventWParams(__severityLevel, __analyticsEventName, __parametersBlock) \
{ \
NSDictionary<NSString *, id> *__eventParameters \
= (__parametersBlock ? ((OWSProdAssertParametersBlock)__parametersBlock)() : nil); \
[OWSAnalytics logEvent:__analyticsEventName \
severity:OWSAnalyticsSeverityCritical \
severity:__severityLevel \
parameters:__eventParameters \
location:__PRETTY_FUNCTION__ \
line:__LINE__]; \
}
#define OWSProdErrorWParams(__analyticsEventName, __parametersBlock) \
OWSProdEventWParams(OWSAnalyticsSeverityCritical, __analyticsEventName, __parametersBlock)
#define OWSProdError(__analyticsEventName) OWSProdEventWParams(OWSAnalyticsSeverityCritical, __analyticsEventName, nil)
#pragma mark - Info Events
#define OWSProdInfoWParams(__analyticsEventName, __parametersBlock) \
OWSProdEventWParams(OWSAnalyticsSeverityInfo, __analyticsEventName, __parametersBlock)
#define OWSProdInfo(__analyticsEventName) OWSProdEventWParams(OWSAnalyticsSeverityInfo, __analyticsEventName, nil)
#define OWSProdCFail(__analyticsEventName) OWSProdCFailWParams(__analyticsEventName, nil)
#pragma mark - Error Events
#define OWSProdErrorWParams(__analyticsEventName, __parametersBlock) \
OWSProdEventWParams(OWSAnalyticsSeverityError, __analyticsEventName, __parametersBlock)
#define OWSProdError(__analyticsEventName) OWSProdEventWParams(OWSAnalyticsSeverityError, __analyticsEventName, nil)
#define OWSProdErrorWNSError(__analyticsEventName, __nserror) \
{ \
@ -182,4 +180,24 @@ typedef NSDictionary<NSString *, id> *_Nonnull (^OWSProdAssertParametersBlock)()
OWSProdErrorWParams(__analyticsEventName, AnalyticsParametersFromNSException(__exception)) \
}
#pragma mark - Critical Events
#define OWSProdCriticalWParams(__analyticsEventName, __parametersBlock) \
OWSProdEventWParams(OWSAnalyticsSeverityCritical, __analyticsEventName, __parametersBlock)
#define OWSProdCritical(__analyticsEventName) \
OWSProdEventWParams(OWSAnalyticsSeverityCritical, __analyticsEventName, nil)
#define OWSProdCriticalWNSError(__analyticsEventName, __nserror) \
{ \
DDLogError(@"%s:%d %@: %@", __PRETTY_FUNCTION__, __LINE__, __analyticsEventName, __nserror.debugDescription); \
OWSProdCriticalWParams(__analyticsEventName, AnalyticsParametersFromNSError(__nserror)) \
}
#define OWSProdCriticalWNSException(__analyticsEventName, __exception) \
{ \
DDLogError(@"%s:%d %@: %@", __PRETTY_FUNCTION__, __LINE__, __analyticsEventName, __exception); \
OWSProdCriticalWParams(__analyticsEventName, AnalyticsParametersFromNSException(__exception)) \
}
NS_ASSUME_NONNULL_END

@ -223,7 +223,7 @@ const int kOWSAnalytics_DiscardFrequency = 0;
return (long)round(pow(10, floor(log10(value))));
}
- (void)addEvent:(NSString *)eventName properties:(NSDictionary *)properties
- (void)addEvent:(NSString *)eventName async:(BOOL)async properties:(NSDictionary *)properties
{
OWSAssert(eventName.length > 0);
@ -234,7 +234,7 @@ const int kOWSAnalytics_DiscardFrequency = 0;
}
#ifndef NO_SIGNAL_ANALYTICS
dispatch_async(self.serialQueue, ^{
void (^writeEvent)() = ^{
// Add super properties.
NSMutableDictionary *eventProperties = (properties ? [properties mutableCopy] : [NSMutableDictionary new]);
[eventProperties addEntriesFromDictionary:self.eventSuperProperties];
@ -250,12 +250,18 @@ const int kOWSAnalytics_DiscardFrequency = 0;
DDLogError(@"%@ Event queue overflow.", self.tag);
return;
}
[transaction setObject:eventDictionary forKey:eventKey inCollection:kOWSAnalytics_EventsCollection];
}];
[self tryToSyncEvents];
});
};
if (async) {
dispatch_async(self.serialQueue, writeEvent);
} else {
dispatch_sync(self.serialQueue, writeEvent);
}
#endif
}
@ -277,18 +283,11 @@ const int kOWSAnalytics_DiscardFrequency = 0;
DDLogFlag logFlag;
BOOL async = YES;
switch (severity) {
case OWSAnalyticsSeverityDebug:
logFlag = DDLogFlagDebug;
break;
case OWSAnalyticsSeverityInfo:
logFlag = DDLogFlagInfo;
break;
case OWSAnalyticsSeverityWarn:
logFlag = DDLogFlagWarning;
break;
case OWSAnalyticsSeverityError:
logFlag = DDLogFlagError;
async = NO;
break;
case OWSAnalyticsSeverityCritical:
logFlag = DDLogFlagError;
@ -313,7 +312,7 @@ const int kOWSAnalytics_DiscardFrequency = 0;
NSMutableDictionary *eventProperties = (parameters ? [parameters mutableCopy] : [NSMutableDictionary new]);
eventProperties[@"event_location"] = [NSString stringWithFormat:@"%s:%d", location, line];
[self addEvent:eventName properties:eventProperties];
[self addEvent:eventName async:async properties:eventProperties];
}
#pragma mark - Logging

Loading…
Cancel
Save