private void HandleSendingFailure(string batchId, IngestionException e) { var isRecoverable = e?.IsRecoverable ?? false; MobileCenterLog.Error(MobileCenterLog.LogTag, $"Sending logs for channel '{Name}', batch '{batchId}' failed", e); var removedLogs = _sendingBatches[batchId]; _sendingBatches.Remove(batchId); if (!isRecoverable && FailedToSendLog != null) { foreach (var log in removedLogs) { FailedToSendLog?.Invoke(this, new FailedToSendLogEventArgs(log, e)); } } _mutex.Lock(); try { Suspend(!isRecoverable, e); if (isRecoverable) { _pendingLogCount += removedLogs.Count; } } finally { _mutex.Unlock(); } }
// Determines whether the application has started already and is not suspended, // but ApplicationLifecycleHelper has not yet fired an initial "resume" event. private static async Task <bool> HasStartedAndNeedsResume() { var needsResume = false; try { // Don't use CurrentSynchronizationContext as that seems to cause an error in Unity applications. var asyncAction = CoreApplication.MainView?.CoreWindow?.Dispatcher.RunAsync( CoreDispatcherPriority.Normal, () => { // If started already, a resume has already occurred. if (_started) { return; } if (CoreApplication.Views.Any(view => view.CoreWindow != null && view.CoreWindow.Visible)) { needsResume = true; } }); if (asyncAction != null) { await asyncAction; } } catch (Exception e) when(e is COMException || e is InvalidOperationException) { // If MainView can't be accessed, a COMException or InvalidOperationException is thrown. It means that the // MainView hasn't been created, and thus the UI hasn't appeared yet. MobileCenterLog.Debug(MobileCenterLog.LogTag, "Not invoking resume immediately because UI is not ready."); } return(needsResume); }
private void OnPushNotificationReceivedHandler(PushNotificationChannel sender, WindowsPushNotificationReceivedEventArgs e) { if (e.NotificationType == PushNotificationType.Toast) { var content = e.ToastNotification.Content; MobileCenterLog.Debug(LogTag, $"Received push notification payload: {content.GetXml()}"); if (ApplicationLifecycleHelper.Instance.IsSuspended) { MobileCenterLog.Debug(LogTag, "Application in background. Push callback will be called when user clicks the toast notification."); } else { var pushNotification = ParseMobileCenterPush(content); if (pushNotification != null) { e.Cancel = true; PushNotificationReceived?.Invoke(sender, pushNotification); MobileCenterLog.Debug(LogTag, "Application in foreground. Intercept push notification and invoke push callback."); } else { MobileCenterLog.Debug(LogTag, "Push ignored. It was not sent through Mobile Center."); } } } else { MobileCenterLog.Debug(LogTag, $"Push ignored. We only handle Toast notifications but PushNotificationType is '{e.NotificationType}'."); } }
protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); // Set our view from the "main" layout resource SetContentView(Resource.Layout.Main); // Get our button from the layout resource, // and attach an event to it var button = FindViewById <Button>(Resource.Id.MyButton); button.Click += delegate { // Crash button.Text = button.Text.Substring(42); }; // Mobile Center integration MobileCenterLog.Assert(LogTag, "MobileCenter.LogLevel=" + MobileCenter.LogLevel); MobileCenter.LogLevel = LogLevel.Verbose; MobileCenterLog.Info(LogTag, "MobileCenter.LogLevel=" + MobileCenter.LogLevel); MobileCenter.Start("44cd8722-bfe0-4748-ac14-7692e031a8a5", typeof(Analytics), typeof(Crashes)); Analytics.TrackEvent("myEvent", new Dictionary <string, string> { { "someKey", "someValue" } }); MobileCenterLog.Info(LogTag, "MobileCenter.InstallId=" + MobileCenter.InstallId); MobileCenterLog.Info(LogTag, "MobileCenter.HasCrashedInLastSession=" + Crashes.HasCrashedInLastSession); MobileCenterLog.Info(LogTag, "MobileCenter.LastSessionCrashReport=" + Crashes.LastSessionCrashReport?.AndroidDetails?.Throwable); }
bool ConfirmationHandler() { Xamarin.Forms.Device.BeginInvokeOnMainThread(() => { Current.MainPage.DisplayActionSheet("Crash detected. Send anonymous crash report?", null, null, "Send", "Always Send", "Don't Send").ContinueWith((arg) => { var answer = arg.Result; UserConfirmation userConfirmationSelection; if (answer == "Send") { userConfirmationSelection = UserConfirmation.Send; } else if (answer == "Always Send") { userConfirmationSelection = UserConfirmation.AlwaysSend; } else { userConfirmationSelection = UserConfirmation.DontSend; } MobileCenterLog.Debug(LogTag, "User selected confirmation option: \"" + answer + "\""); Crashes.NotifyUserConfirmation(userConfirmationSelection); }); }); return(true); }
internal ErrorReport(AndroidErrorReport androidReport) { Id = androidReport.Id; AppStartTime = DateTimeOffset.FromUnixTimeMilliseconds(androidReport.AppStartTime.Time); AppErrorTime = DateTimeOffset.FromUnixTimeMilliseconds(androidReport.AppErrorTime.Time); Device = androidReport.Device == null ? null : new Device(androidReport.Device); object androidThrowable; try { androidThrowable = androidReport.Throwable; } catch (Exception e) { MobileCenterLog.Debug(Crashes.LogTag, "Cannot read throwable from java point of view, probably a .NET exception", e); androidThrowable = null; byte[] exceptionBytes = AndroidExceptionDataManager.LoadWrapperExceptionData(Java.Util.UUID.FromString(Id)); if (exceptionBytes != null) { Exception = CrashesUtils.DeserializeException(exceptionBytes); } } AndroidDetails = new AndroidErrorDetails(androidThrowable, androidReport.ThreadName); iOSDetails = null; }
protected override void OnStart() { MobileCenterLog.Assert(LogTag, "MobileCenter.LogLevel=" + MobileCenter.LogLevel); MobileCenter.LogLevel = LogLevel.Verbose; MobileCenterLog.Info(LogTag, "MobileCenter.LogLevel=" + MobileCenter.LogLevel); MobileCenterLog.Info(LogTag, "MobileCenter.Configured=" + MobileCenter.Configured); //set event handlers Crashes.SendingErrorReport += SendingErrorReportHandler; Crashes.SentErrorReport += SentErrorReportHandler; Crashes.FailedToSendErrorReport += FailedToSendErrorReportHandler; //set callbacks Crashes.ShouldProcessErrorReport = ShouldProcess; Crashes.ShouldAwaitUserConfirmation = ConfirmationHandler; MobileCenterLog.Assert(LogTag, "MobileCenter.Configured=" + MobileCenter.Configured); MobileCenterLog.Assert(LogTag, "MobileCenter.InstallId (before configure)=" + MobileCenter.InstallId); MobileCenter.SetLogUrl("https://in-integration.dev.avalanch.es"); MobileCenter.Start("android=bff0949b-7970-439d-9745-92cdc59b10fe;ios=b889c4f2-9ac2-4e2e-ae16-dae54f2c5899", typeof(Analytics), typeof(Crashes)); Analytics.TrackEvent("myEvent"); Analytics.TrackEvent("myEvent2", new Dictionary <string, string> { { "someKey", "someValue" } }); MobileCenterLog.Info(LogTag, "MobileCenter.InstallId=" + MobileCenter.InstallId); MobileCenterLog.Info(LogTag, "Crashes.HasCrashedInLastSession=" + Crashes.HasCrashedInLastSession); Crashes.GetLastSessionCrashReportAsync().ContinueWith(report => { MobileCenterLog.Info(LogTag, " Crashes.LastSessionCrashReport.Exception=" + report.Result?.Exception); }); }
private void CheckPendingLogs(State state) { if (!_enabled) { MobileCenterLog.Info(MobileCenterLog.LogTag, "The service has been disabled. Stop processing logs."); return; } MobileCenterLog.Debug(MobileCenterLog.LogTag, $"CheckPendingLogs({Name}) pending log count: {_pendingLogCount}"); using (_mutex.GetLock()) { if (_pendingLogCount >= _maxLogsPerBatch) { _batchScheduled = true; Task.Run(async() => { await TriggerIngestionAsync(state).ConfigureAwait(false); }); } else if (_pendingLogCount > 0 && !_batchScheduled) { _batchScheduled = true; // No need wait _batchTimeInterval here. Task.Run(async() => { await Task.Delay((int)_batchTimeInterval.TotalMilliseconds).ConfigureAwait(false); if (_batchScheduled) { await TriggerIngestionAsync(_mutex.State).ConfigureAwait(false); } }); } } }
protected override void OnCreate() { base.OnCreate(); LoadApplication(new App()); try { MobileCenter.Start("54aa94d6-753f-40c3-b3f7-5af2767c7a42", typeof(Analytics) //, typeof(Crashes) ); MobileCenterLog.Assert(MobileCenterLog.LogTag, "SUCCESSFULLY STARTED"); } catch (Exception e) { MobileCenterLog.Error(MobileCenterLog.LogTag, "EXCEPTION!!!\n" + e.GetType() + '\n' + e.Message); } try { Analytics.TrackEvent("Video clicked", new Dictionary <string, string> { { "Category", "Music" }, { "FileName", "favorite.avi" } }); MobileCenterLog.Assert(MobileCenterLog.LogTag, "EVENT SENT"); } catch (Exception e) { MobileCenterLog.Error(MobileCenterLog.LogTag, "EXCEPTION!!!\n" + e.GetType() + '\n' + e.Message); } }
private void HandleSendingSuccess(State state, string batchId) { if (!_mutex.IsCurrent(state)) { return; } try { _storage.DeleteLogs(Name, batchId); } catch (StorageException e) { MobileCenterLog.Warn(MobileCenterLog.LogTag, $"Could not delete logs for batch {batchId}", e); throw; } finally { List <Log> removedLogs; using (_mutex.GetLock(state)) { removedLogs = _sendingBatches[batchId]; _sendingBatches.Remove(batchId); } if (SentLog != null) { foreach (var log in removedLogs) { SentLog?.Invoke(this, new SentLogEventArgs(log)); } } } }
private void HandleSendingFailure(State state, string batchId, IngestionException e) { var isRecoverable = e?.IsRecoverable ?? false; MobileCenterLog.Error(MobileCenterLog.LogTag, $"Sending logs for channel '{Name}', batch '{batchId}' failed: {e?.Message}"); List <Log> removedLogs; using (_mutex.GetLock(state)) { removedLogs = _sendingBatches[batchId]; _sendingBatches.Remove(batchId); if (isRecoverable) { _pendingLogCount += removedLogs.Count; } } if (!isRecoverable && FailedToSendLog != null) { foreach (var log in removedLogs) { FailedToSendLog?.Invoke(this, new FailedToSendLogEventArgs(log, e)); } } Suspend(state, !isRecoverable, e); }
private async Task PersistLogAsync(Log log, State state) { try { await _storage.PutLog(Name, log).ConfigureAwait(false); } catch (StorageException e) { MobileCenterLog.Error(MobileCenterLog.LogTag, "Error persisting log", e); return; } try { bool enabled; using (await _mutex.GetLockAsync(state).ConfigureAwait(false)) { _pendingLogCount++; enabled = _enabled; } if (enabled) { CheckPendingLogs(state); return; } MobileCenterLog.Warn(MobileCenterLog.LogTag, "Channel is temporarily disabled; log was saved to disk"); } catch (StatefulMutexException) { MobileCenterLog.Warn(MobileCenterLog.LogTag, "The PersistLog operation has been cancelled"); } }
public async Task EnqueueAsync(Log log) { try { State state; bool discardLogs; using (await _mutex.GetLockAsync().ConfigureAwait(false)) { state = _mutex.State; discardLogs = _discardLogs; } if (discardLogs) { MobileCenterLog.Warn(MobileCenterLog.LogTag, "Channel is disabled; logs are discarded"); SendingLog?.Invoke(this, new SendingLogEventArgs(log)); FailedToSendLog?.Invoke(this, new FailedToSendLogEventArgs(log, new CancellationException())); } EnqueuingLog?.Invoke(this, new EnqueuingLogEventArgs(log)); await PrepareLogAsync(log, state).ConfigureAwait(false); await PersistLogAsync(log, state).ConfigureAwait(false); } catch (StatefulMutexException) { MobileCenterLog.Warn(MobileCenterLog.LogTag, "The Enqueue operation has been cancelled"); } }
private void CheckPendingLogs() { if (!_enabled) { MobileCenterLog.Info(MobileCenterLog.LogTag, "The service has been disabled. Stop processing logs."); return; } MobileCenterLog.Debug(MobileCenterLog.LogTag, $"CheckPendingLogs({Name}) pending log count: {_pendingLogCount}"); if (_pendingLogCount >= _maxLogsPerBatch) { Task.Run(TriggerIngestionAsync); } else if (_pendingLogCount > 0 && !_batchScheduled) { _batchScheduled = true; Task.Delay((int)_batchTimeInterval.TotalMilliseconds).ContinueWith(async completedTask => { if (_batchScheduled) { await TriggerIngestionAsync().ConfigureAwait(false); } }); } }
public override NSArray AttachmentsWithCrashes(MSCrashes crashes, MSErrorReport msReport) { if (_owner.GetErrorAttachments == null) { return(null); } var report = ErrorReportCache.GetErrorReport(msReport); var attachments = _owner.GetErrorAttachments(report); if (attachments != null) { var nsArray = new NSMutableArray(); foreach (var attachment in attachments) { if (attachment != null) { nsArray.Add(attachment.internalAttachment); } else { MobileCenterLog.Warn(Crashes.LogTag, "Skipping null ErrorAttachmentLog in Crashes.GetErrorAttachments."); } } return(nsArray); } return(null); }
/// <summary> /// Asynchronously deletes all logs for a particular channel /// </summary> /// <param name="channelName">Name of the channel to delete logs for</param> /// <exception cref="StorageException"/> public async Task DeleteLogsAsync(string channelName) { using (await _taskLockSource.GetTaskLockAsync().ConfigureAwait(false)) { MobileCenterLog.Debug(MobileCenterLog.LogTag, $"Deleting all logs from storage for channel '{channelName}'"); var fullIdentifiers = new List <string>(); try { foreach (var fullIdentifier in _pendingDbIdentifierGroups.Keys) { if (!ChannelMatchesIdentifier(channelName, fullIdentifier)) { continue; } foreach (var id in _pendingDbIdentifierGroups[fullIdentifier]) { _pendingDbIdentifiers.Remove(id); } fullIdentifiers.Add(fullIdentifier); } foreach (var fullIdentifier in fullIdentifiers) { _pendingDbIdentifierGroups.Remove(fullIdentifier); } } catch (KeyNotFoundException e) { throw new StorageException(e); } await _storageAdapter.DeleteAsync <LogEntry>(entry => entry.Channel == channelName) .ConfigureAwait(false); } }
/// <exception cref="IngestionException"/> public async Task ExecuteCallAsync(IServiceCall call) { if (call.CancellationToken.IsCancellationRequested) { return; } var baseUrl = string.IsNullOrEmpty(_baseLogUrl) ? DefaultBaseUrl : _baseLogUrl; MobileCenterLog.Verbose(MobileCenterLog.LogTag, $"Calling {baseUrl + ApiVersion}..."); // Create request headers. var requestHeaders = CreateHeaders(call.AppSecret, call.InstallId); MobileCenterLog.Verbose(MobileCenterLog.LogTag, "Headers: " + $"{AppSecret}={GetRedactedAppSecret(call.AppSecret)}, " + $"{InstallId}={call.InstallId}"); // Create request content. var requestContent = CreateLogsContent(call.Logs); MobileCenterLog.Verbose(MobileCenterLog.LogTag, requestContent); // Send request. await _httpNetwork.SendAsync(baseUrl + ApiVersion, HttpMethod.Post, requestHeaders, requestContent, call.CancellationToken).ConfigureAwait(false); }
/// <summary> /// Asynchronously deletes all logs in a particular batch /// </summary> /// <param name="channelName">The name of the channel associated with the batch</param> /// <param name="batchId">The batch identifier</param> /// <exception cref="StorageException"/> public async Task DeleteLogsAsync(string channelName, string batchId) { using (await _taskLockSource.GetTaskLockAsync().ConfigureAwait(false)) { MobileCenterLog.Debug(MobileCenterLog.LogTag, $"Deleting logs from storage for channel '{channelName}' with batch id '{batchId}'"); try { var identifiers = _pendingDbIdentifierGroups[GetFullIdentifier(channelName, batchId)]; _pendingDbIdentifierGroups.Remove(GetFullIdentifier(channelName, batchId)); var deletedIdsMessage = "The IDs for deleting log(s) is/ are:"; foreach (var id in identifiers) { deletedIdsMessage += "\n\t" + id; _pendingDbIdentifiers.Remove(id); } MobileCenterLog.Debug(MobileCenterLog.LogTag, deletedIdsMessage); foreach (var id in identifiers) { await _storageAdapter.DeleteAsync <LogEntry>(entry => entry.Channel == channelName && entry.Id == id).ConfigureAwait(false); } } catch (KeyNotFoundException e) { throw new StorageException(e); } } }
/// <summary> /// Asynchronously deletes all logs for a particular channel /// </summary> /// <param name="channelName">Name of the channel to delete logs for</param> /// <exception cref="StorageException"/> public Task DeleteLogs(string channelName) { var task = new Task(() => { try { MobileCenterLog.Debug(MobileCenterLog.LogTag, $"Deleting all logs from storage for channel '{channelName}'"); ClearPendingLogStateWithoutEnqueue(channelName); _storageAdapter.DeleteAsync <LogEntry>(entry => entry.Channel == channelName) .Wait(); } catch (KeyNotFoundException e) { throw new StorageException(e); } }); try { _queue.Add(task); } catch (InvalidOperationException) { throw new StorageException("The operation has been cancelled"); } _flushSemaphore.Release(); return(task); }
public SessionTracker(IChannelGroup channelGroup, IChannelUnit channel, IApplicationSettings applicationSettings) { // Need to lock in constructor because of the event handler being set for channelGroup. lock (_lockObject) { _channel = channel; _applicationSettings = applicationSettings; channelGroup.EnqueuingLog += HandleEnqueuingLog; var sessionsString = _applicationSettings.GetValue <string>(StorageKey, null); if (sessionsString == null) { return; } _sessions = SessionsFromString(sessionsString); // Re-write sessions in storage in case of any invalid strings _applicationSettings.SetValue(StorageKey, SessionsAsString()); if (_sessions.Count == 0) { return; } var loadedSessionsString = _sessions.Values.Aggregate("Loaded stored sessions:\n", (current, session) => current + ("\t" + session + "\n")); MobileCenterLog.Debug(Analytics.Instance.LogTag, loadedSessionsString); } }
internal HttpRequestMessage CreateRequest(string appSecret, Guid installId, string requestContent) { var baseUrl = string.IsNullOrEmpty(_baseLogUrl) ? DefaultBaseUrl : _baseLogUrl; // Create HTTP transport objects var request = new HttpRequestMessage { Method = HttpMethod.Post, RequestUri = new Uri(baseUrl + ApiVersion) }; MobileCenterLog.Verbose(MobileCenterLog.LogTag, $"Calling {request.RequestUri}..."); // Set Headers request.Headers.Add(AppSecret, appSecret); request.Headers.Add(InstallId, installId.ToString()); // Log headers var headers = $"Headers: Content-Type={ContentTypeValue}, " + $"{AppSecret}={GetRedactedAppSecret(appSecret)}, " + $"{InstallId}={installId}"; MobileCenterLog.Verbose(MobileCenterLog.LogTag, headers); // Request content MobileCenterLog.Verbose(MobileCenterLog.LogTag, requestContent); request.Content = new StringContent(requestContent, System.Text.Encoding.UTF8); request.Content.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse(ContentTypeValue); return(request); }
protected override void OnStart() { MobileCenterLog.Assert(LogTag, "MobileCenter.LogLevel=" + MobileCenter.LogLevel); MobileCenter.LogLevel = LogLevel.Verbose; MobileCenterLog.Info(LogTag, "MobileCenter.LogLevel=" + MobileCenter.LogLevel); MobileCenterLog.Info(LogTag, "MobileCenter.Configured=" + MobileCenter.Configured); //set event handlers Crashes.SendingErrorReport += SendingErrorReportHandler; Crashes.SentErrorReport += SentErrorReportHandler; Crashes.FailedToSendErrorReport += FailedToSendErrorReportHandler; //set callbacks Crashes.ShouldProcessErrorReport = ShouldProcess; Crashes.GetErrorAttachment = ErrorAttachmentForReport; Crashes.ShouldAwaitUserConfirmation = ConfirmationHandler; MobileCenter.Start(typeof(Analytics), typeof(Crashes)); Analytics.TrackEvent("myEvent"); Analytics.TrackEvent("myEvent2", new Dictionary <string, string> { { "someKey", "someValue" } }); MobileCenterLog.Info(LogTag, "MobileCenter.InstallId=" + MobileCenter.InstallId); MobileCenterLog.Info(LogTag, "Crashes.HasCrashedInLastSession=" + Crashes.HasCrashedInLastSession); if (Crashes.HasCrashedInLastSession && Crashes.LastSessionCrashReport.Exception != null) { string message = Crashes.LastSessionCrashReport.Exception.Message; MobileCenterLog.Info(LogTag, "Last Session Crash Report exception message: " + message); } }
protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); // Set our view from the "main" layout resource SetContentView(Resource.Layout.Main); // Get our button from the layout resource, // and attach an event to it var button = FindViewById <Button>(Resource.Id.MyButton); button.Click += delegate { // Crash button.Text = button.Text.Substring(42); }; // Mobile Center integration MobileCenterLog.Assert(LogTag, "MobileCenter.LogLevel=" + MobileCenter.LogLevel); MobileCenter.LogLevel = LogLevel.Verbose; MobileCenterLog.Info(LogTag, "MobileCenter.LogLevel=" + MobileCenter.LogLevel); MobileCenter.SetLogUrl("https://in-integration.dev.avalanch.es"); MobileCenter.Start("bff0949b-7970-439d-9745-92cdc59b10fe", typeof(Analytics), typeof(Crashes)); Analytics.TrackEvent("myEvent", new Dictionary <string, string> { { "someKey", "someValue" } }); MobileCenterLog.Info(LogTag, "MobileCenter.InstallId=" + MobileCenter.InstallId); MobileCenterLog.Info(LogTag, "MobileCenter.HasCrashedInLastSession=" + Crashes.HasCrashedInLastSession); Crashes.GetLastSessionCrashReportAsync().ContinueWith(report => { MobileCenterLog.Info(LogTag, "MobileCenter.LastSessionCrashReport=" + report.Result?.AndroidDetails?.Throwable); }); }
internal static Dictionary <long, Guid> SessionsFromString(string sessionsString) { var sessionsDict = new Dictionary <long, Guid>(); if (sessionsString == null) { return(sessionsDict); } var sessions = sessionsString.Split(StorageEntrySeparator); foreach (var sessionString in sessions) { var splitSession = sessionString.Split(StorageKeyValueSeparator); try { var time = long.Parse(splitSession[0]); var sid = Guid.Parse(splitSession[1]); sessionsDict.Add(time, sid); } catch (FormatException e) //TODO other exceptions? { MobileCenterLog.Warn(Analytics.Instance.LogTag, $"Ignore invalid session in store: {sessionString}", e); } } return(sessionsDict); }
bool OnReleaseAvailable(ReleaseDetails releaseDetails) { MobileCenterLog.Info(LogTag, "OnReleaseAvailable id=" + releaseDetails.Id + " version=" + releaseDetails.Version + " releaseNotesUrl=" + releaseDetails.ReleaseNotesUrl); var custom = releaseDetails.ReleaseNotes?.ToLowerInvariant().Contains("custom") ?? false; if (custom) { var title = "Version " + releaseDetails.ShortVersion + " available!"; Task answer; if (releaseDetails.MandatoryUpdate) { answer = Current.MainPage.DisplayAlert(title, releaseDetails.ReleaseNotes, "Update now!"); } else { answer = Current.MainPage.DisplayAlert(title, releaseDetails.ReleaseNotes, "Update now!", "Maybe tomorrow..."); } answer.ContinueWith((task) => { if (releaseDetails.MandatoryUpdate || ((Task <bool>)task).Result) { Distribute.NotifyUpdateAction(UpdateAction.Update); } else { Distribute.NotifyUpdateAction(UpdateAction.Postpone); } }); } return(custom); }
bool OnReleaseAvailable(ReleaseDetails releaseDetails) { MobileCenterLog.Info(LogTag, "OnReleaseAvailable id=" + releaseDetails.Id + " version=" + releaseDetails.Version + " releaseNotesUrl=" + releaseDetails.ReleaseNotesUrl); var custom = releaseDetails.ReleaseNotes?.ToLowerInvariant().Contains("custom") ?? false; if (custom) { var builder = new AlertDialog.Builder(this); builder.SetTitle(string.Format(GetString(Resource.String.version_x_available), releaseDetails.ShortVersion)); builder.SetMessage(releaseDetails.ReleaseNotes); builder.SetPositiveButton(Microsoft.Azure.Mobile.Distribute.Resource.String.mobile_center_distribute_update_dialog_download, delegate { Distribute.NotifyUpdateAction(UpdateAction.Update); }); builder.SetCancelable(false); if (!releaseDetails.MandatoryUpdate) { builder.SetNegativeButton(Microsoft.Azure.Mobile.Distribute.Resource.String.mobile_center_distribute_update_dialog_postpone, delegate { Distribute.NotifyUpdateAction(UpdateAction.Postpone); }); } builder.Create().Show(); } return(custom); }
public void OnChannelGroupReady(IChannelGroup channelGroup, string appSecret) { MobileCenterLog.Warn(MobileCenterLog.LogTag, "Crashes service is not yet supported on this platform."); try { #if REFERENCE #else WatsonRegistrationManager.Start(appSecret); #pragma warning disable CS0612 // Type or member is obsolete MobileCenter.CorrelationIdChanged += (s, id) => { WatsonRegistrationManager.SetCorrelationId(id.ToString()); }; // Checking for null and setting id needs to be atomic to avoid // overwriting Guid newId = Guid.NewGuid(); MobileCenter.TestAndSetCorrelationId(Guid.Empty, ref newId); #pragma warning restore CS0612 // Type or member is obsolete #endif } catch (Exception e) { #if DEBUG throw new MobileCenterException("Failed to register crashes with Watson", e); #endif } }
///<exception cref="IngestionException"/> private async Task ExecuteAsyncHelper() { while (true) { try { await Ingestion.ExecuteCallAsync(this).ConfigureAwait(false); return; } catch (IngestionException e) { if (!e.IsRecoverable || _retryCount >= _retryIntervals.Length) { throw; } MobileCenterLog.Warn(MobileCenterLog.LogTag, "Failed to execute service call", e); } await _retryIntervals[_retryCount++]().ConfigureAwait(false); if (_tokenSource.Token.IsCancellationRequested) { throw new IngestionException("The operation has been cancelled"); } } }
public static void Log(string tag, string message, Exception exception = null, MobileCenterLogType type = MobileCenterLogType.Warn) { switch (type) { case MobileCenterLogType.Info: MobileCenterLog.Info(tag, message, exception); break; case MobileCenterLogType.Warn: MobileCenterLog.Warn(tag, message, exception); break; case MobileCenterLogType.Error: MobileCenterLog.Error(tag, message, exception); break; case MobileCenterLogType.Assert: MobileCenterLog.Assert(tag, message, exception); break; case MobileCenterLogType.Verbose: MobileCenterLog.Verbose(tag, message, exception); break; case MobileCenterLogType.Debug: MobileCenterLog.Debug(tag, message, exception); break; default: throw new Exception("MobileCenterLogType Does Not Exist"); } }
private async Task DeleteLogsOnSuspendedAsync() { await _mutex.LockAsync().ConfigureAwait(false); var stateSnapshot = _stateKeeper.GetStateSnapshot(); try { if (SendingLog != null || FailedToSendLog != null) { await SignalDeletingLogs(stateSnapshot).ConfigureAwait(false); } } catch (StorageException) { MobileCenterLog.Warn(MobileCenterLog.LogTag, "Failed to invoke events for logs being deleted."); return; } catch (StatefulMutexException e) { MobileCenterLog.Warn(MobileCenterLog.LogTag, "The DeleteLogs operation has been cancelled", e); return; } finally { _mutex.Unlock(); } await _storage.DeleteLogsAsync(Name).ConfigureAwait(false); }