Adds VS App Center analytics + crash reporting

Currently tracks install, refresh, and update app events.
This commit is contained in:
Riley Testut
2020-03-31 14:31:34 -07:00
parent cd89741827
commit 193ca28c98
71 changed files with 3548 additions and 314 deletions

View File

@@ -0,0 +1,11 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
#import "MSCrashHandlerSetupDelegate.h"
#import "MSCrashes.h"
#import "MSCrashesDelegate.h"
#import "MSErrorAttachmentLog+Utility.h"
#import "MSErrorAttachmentLog.h"
#import "MSWrapperCrashesHelper.h"

View File

@@ -0,0 +1,13 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MS_ABSTRACT_LOG_H
#define MS_ABSTRACT_LOG_H
#import <Foundation/Foundation.h>
@interface MSAbstractLog : NSObject
@end
#endif

View File

@@ -0,0 +1,33 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
/**
* This is required for Wrapper SDKs that need to provide custom behavior surrounding the setup of crash handlers.
*/
@protocol MSCrashHandlerSetupDelegate <NSObject>
@optional
/**
* Callback method that will be called immediately before crash handlers are set up.
*/
- (void)willSetUpCrashHandlers;
/**
* Callback method that will be called immediately after crash handlers are set up.
*/
- (void)didSetUpCrashHandlers;
/**
* Callback method that gets a value indicating whether the SDK should enable an uncaught exception handler.
*
* @return YES if SDK should enable uncaught exception handler, otherwise NO.
*
* @discussion Do not register an UncaughtExceptionHandler for Xamarin as we rely on the Xamarin runtime to report NSExceptions. Registering
* our own UncaughtExceptionHandler will cause the Xamarin debugger to not work properly (it will not stop for NSExceptions).
*/
- (BOOL)shouldEnableUncaughtExceptionHandler;
@end

View File

@@ -0,0 +1,171 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import "MSErrorReport.h"
#import "MSServiceAbstract.h"
@class MSCrashesDelegate;
/**
* Custom block that handles the alert that prompts the user whether crash reports need to be processed or not.
*
* @return Returns YES to discard crash reports, otherwise NO.
*/
typedef BOOL (^MSUserConfirmationHandler)(NSArray<MSErrorReport *> *_Nonnull errorReports);
/**
* Error Logging status.
*/
typedef NS_ENUM(NSUInteger, MSErrorLogSetting) {
/**
* Crash reporting is disabled.
*/
MSErrorLogSettingDisabled = 0,
/**
* User is asked each time before sending error logs.
*/
MSErrorLogSettingAlwaysAsk = 1,
/**
* Each error log is send automatically.
*/
MSErrorLogSettingAutoSend = 2
};
/**
* Crash Manager alert user input.
*/
typedef NS_ENUM(NSUInteger, MSUserConfirmation) {
/**
* User chose not to send the crash report.
*/
MSUserConfirmationDontSend = 0,
/**
* User wants the crash report to be sent.
*/
MSUserConfirmationSend = 1,
/**
* User wants to send all error logs.
*/
MSUserConfirmationAlways = 2
};
@protocol MSCrashesDelegate;
@interface MSCrashes : MSServiceAbstract
///-----------------------------------------------------------------------------
/// @name Testing Crashes Feature
///-----------------------------------------------------------------------------
/**
* Lets the app crash for easy testing of the SDK.
*
* The best way to use this is to trigger the crash with a button action.
*
* Make sure not to let the app crash in `applicationDidFinishLaunching` or any other startup method! Since otherwise the app would crash
* before the SDK could process it.
*
* Note that our SDK provides support for handling crashes that happen early on startup. Check the documentation for more information on how
* to use this.
*
* If the SDK detects an App Store environment, it will _NOT_ cause the app to crash!
*/
+ (void)generateTestCrash;
///-----------------------------------------------------------------------------
/// @name Helpers
///-----------------------------------------------------------------------------
/**
* Check if the app has crashed in the last session.
*
* @return Returns YES is the app has crashed in the last session.
*/
+ (BOOL)hasCrashedInLastSession;
/**
* Check if the app received memory warning in the last session.
*
* @return Returns YES is the app received memory warning in the last session.
*/
+ (BOOL)hasReceivedMemoryWarningInLastSession;
/**
* Provides details about the crash that occurred in the last app session
*/
+ (nullable MSErrorReport *)lastSessionCrashReport;
#if TARGET_OS_OSX
/**
* Callback for report exception.
*
* NOTE: This method should be called only if you explicitly disabled swizzling for it.
*
* On OS X runtime, not all uncaught exceptions end in a custom `NSUncaughtExceptionHandler`.
* Forward exception from overrided `[NSApplication reportException:]` to catch additional exceptions.
*/
+ (void)applicationDidReportException:(NSException *_Nonnull)exception;
#endif
///-----------------------------------------------------------------------------
/// @name Configuration
///-----------------------------------------------------------------------------
#if !TARGET_OS_TV
/**
* Disable the Mach exception server.
*
* By default, the SDK uses the Mach exception handler to catch fatal signals, e.g. stack overflows, via a Mach exception server. If you
* want to disable the Mach exception handler, you should call this method _BEFORE_ starting the SDK. Your typical setup code would look
* like this:
*
* `[MSCrashes disableMachExceptionHandler]`;
* `[MSAppCenter start:@"YOUR_APP_ID" withServices:@[[MSCrashes class]]];`
*
* or if you are using Swift:
*
* `MSCrashes.disableMachExceptionHandler()`
* `MSAppCenter.start("YOUR_APP_ID", withServices: [MSAnalytics.self, MSCrashes.self])`
*
* tvOS does not support the Mach exception handler, thus crashes that are caused by stack overflows cannot be detected. As a result,
* disabling the Mach exception server is not available in the tvOS SDK.
*
* @discussion It can be useful to disable the Mach exception handler when you are debugging the Crashes service while developing,
* especially when you attach the debugger to your application after launch.
*/
+ (void)disableMachExceptionHandler;
#endif
/**
* Set the delegate
* Defines the class that implements the optional protocol `MSCrashesDelegate`.
*
* @see MSCrashesDelegate
*/
+ (void)setDelegate:(_Nullable id<MSCrashesDelegate>)delegate;
/**
* Set a user confirmation handler that is invoked right before processing crash reports to determine whether sending crash reports or not.
*
* @param userConfirmationHandler A handler for user confirmation.
*
* @see MSUserConfirmationHandler
*/
+ (void)setUserConfirmationHandler:(_Nullable MSUserConfirmationHandler)userConfirmationHandler;
/**
* Notify SDK with a confirmation to handle the crash report.
*
* @param userConfirmation A user confirmation.
*
* @see MSUserConfirmation.
*/
+ (void)notifyWithUserConfirmation:(MSUserConfirmation)userConfirmation;
@end

View File

@@ -0,0 +1,65 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
@class MSCrashes;
@class MSErrorReport;
@class MSErrorAttachmentLog;
@protocol MSCrashesDelegate <NSObject>
@optional
/**
* Callback method that will be called before processing errors.
*
* @param crashes The instance of MSCrashes.
* @param errorReport The errorReport that will be sent.
*
* @discussion Crashes will send logs to the server or discard/delete logs based on this method's return value.
*/
- (BOOL)crashes:(MSCrashes *)crashes shouldProcessErrorReport:(MSErrorReport *)errorReport;
/**
* Callback method that will be called before each error will be send to the server.
*
* @param crashes The instance of MSCrashes.
* @param errorReport The errorReport that will be sent.
*
* @discussion Use this callback to display custom UI while crashes are sent to the server.
*/
- (void)crashes:(MSCrashes *)crashes willSendErrorReport:(MSErrorReport *)errorReport;
/**
* Callback method that will be called in case the SDK was unable to send an error report to the server.
*
* @param crashes The instance of MSCrashes.
* @param errorReport The errorReport that App Center sent.
*
* @discussion Use this method to hide your custom UI.
*/
- (void)crashes:(MSCrashes *)crashes didSucceedSendingErrorReport:(MSErrorReport *)errorReport;
/**
* Callback method that will be called in case the SDK was unable to send an error report to the server.
*
* @param crashes The instance of MSCrashes.
* @param errorReport The errorReport that App Center tried to send.
* @param error The error that occurred.
*/
- (void)crashes:(MSCrashes *)crashes didFailSendingErrorReport:(MSErrorReport *)errorReport withError:(NSError *)error;
/**
* Method to get the attachments associated to an error report.
*
* @param crashes The instance of MSCrashes.
* @param errorReport The errorReport associated with the returned attachments.
*
* @return The attachments associated with the given error report or nil if the error report doesn't have any attachments.
*
* @discussion Implement this method if you want attachments to the given error report.
*/
- (NSArray<MSErrorAttachmentLog *> *)attachmentsWithCrashes:(MSCrashes *)crashes forErrorReport:(MSErrorReport *)errorReport;
@end

View File

@@ -0,0 +1,32 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import "MSErrorAttachmentLog.h"
// Exporting symbols for category.
extern NSString *MSMSErrorLogAttachmentLogUtilityCategory;
@interface MSErrorAttachmentLog (Utility)
/**
* Create an attachment with a given filename and text.
*
* @param filename The filename the attachment should get. If nil will get an automatically generated filename.
* @param text The attachment text.
*
* @return An instance of `MSErrorAttachmentLog`.
*/
+ (MSErrorAttachmentLog *)attachmentWithText:(NSString *)text filename:(NSString *)filename;
/**
* Create an attachment with a given filename and `NSData` object.
*
* @param filename The filename the attachment should get. If nil will get an automatically generated filename.
* @param data The attachment data as NSData.
* @param contentType The content type of your data as MIME type.
*
* @return An instance of `MSErrorAttachmentLog`.
*/
+ (MSErrorAttachmentLog *)attachmentWithBinary:(NSData *)data filename:(NSString *)filename contentType:(NSString *)contentType;
@end

View File

@@ -0,0 +1,49 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
#import "MSAbstractLog.h"
/**
* Error attachment log.
*/
@interface MSErrorAttachmentLog : MSAbstractLog
/**
* Content type (text/plain for text).
*/
@property(nonatomic, copy) NSString *contentType;
/**
* File name.
*/
@property(nonatomic, copy) NSString *filename;
/**
* The attachment data.
*/
@property(nonatomic, copy) NSData *data;
/**
* Initialize an attachment with a given filename and `NSData` object.
*
* @param filename The filename the attachment should get. If nil will get an automatically generated filename.
* @param data The attachment data as `NSData`.
* @param contentType The content type of your data as MIME type.
*
* @return An instance of `MSErrorAttachmentLog`.
*/
- (instancetype)initWithFilename:(NSString *)filename attachmentBinary:(NSData *)data contentType:(NSString *)contentType;
/**
* Initialize an attachment with a given filename and text.
*
* @param filename The filename the attachment should get. If nil will get an automatically generated filename.
* @param text The attachment text.
*
* @return An instance of `MSErrorAttachmentLog`.
*/
- (instancetype)initWithFilename:(NSString *)filename attachmentText:(NSString *)text;
@end

View File

@@ -0,0 +1,68 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
@class MSDevice;
@interface MSErrorReport : NSObject
/**
* UUID for the crash report.
*/
@property(nonatomic, copy, readonly) NSString *incidentIdentifier;
/**
* UUID for the app installation on the device.
*/
@property(nonatomic, copy, readonly) NSString *reporterKey;
/**
* Signal that caused the crash.
*/
@property(nonatomic, copy, readonly) NSString *signal;
/**
* Exception name that triggered the crash, nil if the crash was not caused by an exception.
*/
@property(nonatomic, copy, readonly) NSString *exceptionName;
/**
* Exception reason, nil if the crash was not caused by an exception.
*/
@property(nonatomic, copy, readonly) NSString *exceptionReason;
/**
* Date and time the app started, nil if unknown.
*/
@property(nonatomic, readonly, strong) NSDate *appStartTime;
/**
* Date and time the error occurred, nil if unknown
*/
@property(nonatomic, readonly, strong) NSDate *appErrorTime;
/**
* Device information of the app when it crashed.
*/
@property(nonatomic, readonly, strong) MSDevice *device;
/**
* Identifier of the app process that crashed.
*/
@property(nonatomic, readonly, assign) NSUInteger appProcessIdentifier;
/**
* Indicates if the app was killed while being in foreground from the iOS.
*
* This can happen if it consumed too much memory or the watchdog killed the app because it took too long to startup or blocks the main
* thread for too long, or other reasons. See Apple documentation:
* https://developer.apple.com/library/ios/qa/qa1693/_index.html.
*
* @return YES if the details represent an app kill instead of a crash.
*
* @see `[MSCrashes didReceiveMemoryWarningInLastSession]`
*/
- (BOOL)isAppKill;
@end

View File

@@ -0,0 +1,35 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MS_SERVICE_H
#define MS_SERVICE_H
#import <Foundation/Foundation.h>
/**
* Protocol declaring service logic.
*/
@protocol MSService <NSObject>
/**
* Enable or disable this service.
* The state is persisted in the device's storage across application launches.
*
* @param isEnabled Whether this service is enabled or not.
*
* @see isEnabled
*/
+ (void)setEnabled:(BOOL)isEnabled;
/**
* Indicates whether this service is enabled.
*
* @return `YES` if this service is enabled, `NO` if it is not.
*
* @see setEnabled:
*/
+ (BOOL)isEnabled;
@end
#endif

View File

@@ -0,0 +1,55 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MS_SERVICE_ABSTRACT_H
#define MS_SERVICE_ABSTRACT_H
#import <Foundation/Foundation.h>
#import "MSService.h"
@protocol MSChannelGroupProtocol;
/**
* Abstraction of services common logic.
* This class is intended to be subclassed only not instantiated directly.
*/
@interface MSServiceAbstract : NSObject <MSService>
/**
* The flag indicates whether the service is started from application or not.
*/
@property(nonatomic, assign) BOOL startedFromApplication;
/**
* Start this service with a channel group. Also sets the flag that indicates that a service has been started.
*
* @param channelGroup channel group used to persist and send logs.
* @param appSecret app secret for the SDK.
* @param token default transmission target token for this service.
* @param fromApplication indicates whether the service started from an application or not.
*/
- (void)startWithChannelGroup:(id<MSChannelGroupProtocol>)channelGroup
appSecret:(NSString *)appSecret
transmissionTargetToken:(NSString *)token
fromApplication:(BOOL)fromApplication;
/**
* Update configuration when the service requires to start again. This method should only be called if the service is started from libraries
* and then is being started from an application.
*
* @param appSecret app secret for the SDK.
* @param token default transmission target token for this service.
*/
- (void)updateConfigurationWithAppSecret:(NSString *)appSecret transmissionTargetToken:(NSString *)token;
/**
* Checks if the service needs the application secret.
*
* @return `YES` if the application secret is required, `NO` otherwise.
*/
- (BOOL)isAppSecretRequired;
@end
#endif

View File

@@ -0,0 +1,90 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
#import "MSCrashHandlerSetupDelegate.h"
NS_ASSUME_NONNULL_BEGIN
@class MSErrorReport;
@class MSErrorAttachmentLog;
@class MSException;
/**
* This general class allows wrappers to supplement the Crashes SDK with their own behavior.
*/
@interface MSWrapperCrashesHelper : NSObject
/**
* Sets the crash handler setup delegate.
*
* @param delegate The delegate to set.
*/
+ (void)setCrashHandlerSetupDelegate:(id<MSCrashHandlerSetupDelegate>)delegate;
/**
* Gets the crash handler setup delegate.
*
* @return The delegate being used by Crashes.
*/
+ (id<MSCrashHandlerSetupDelegate>)getCrashHandlerSetupDelegate;
/**
* Enables or disables automatic crash processing.
*
* @param automaticProcessing Passing NO causes SDK not to send reports immediately, even if "Always Send" is true.
*/
+ (void)setAutomaticProcessing:(BOOL)automaticProcessing;
/**
* Gets a list of unprocessed crash reports. Will block until the service starts.
*
* @return An array of unprocessed error reports.
*/
+ (NSArray<MSErrorReport *> *)unprocessedCrashReports;
/**
* Resumes processing for a given subset of the unprocessed reports.
*
* @param filteredIds An array containing the errorId/incidentIdentifier of each report that should be sent.
*
* @return YES if should "Always Send" is true.
*/
+ (BOOL)sendCrashReportsOrAwaitUserConfirmationForFilteredIds:(NSArray<NSString *> *)filteredIds;
/**
* Sends error attachments for a particular error report.
*
* @param errorAttachments An array of error attachments that should be sent.
* @param incidentIdentifier The identifier of the error report that the attachments will be associated with.
*/
+ (void)sendErrorAttachments:(NSArray<MSErrorAttachmentLog *> *)errorAttachments withIncidentIdentifier:(NSString *)incidentIdentifier;
/**
* Track handled exception directly as model form.
* This API is used by wrapper SDKs.
*
* @param exception model form exception.
* @param properties dictionary of properties.
* @param attachments a list of attachments.
*
* @return handled error ID.
*/
+ (NSString *)trackModelException:(MSException *)exception
withProperties:(nullable NSDictionary<NSString *, NSString *> *)properties
withAttachments:(nullable NSArray<MSErrorAttachmentLog *> *)attachments;
/**
* Get a generic error report representation for an handled exception.
* This API is used by wrapper SDKs.
*
* @param errorID handled error ID.
*
* @return an error report.
*/
+ (MSErrorReport *)buildHandledErrorReportWithErrorID:(NSString *)errorID;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,10 @@
framework module AppCenterCrashes {
umbrella header "AppCenterCrashes.h"
export *
module * { export * }
link framework "Foundation"
link "c++"
link "z"
}