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; }
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"); } }
// 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); }
/// <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); } } }
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); } }
/// <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); } }
/// <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); }
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); }
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); } }); } } }
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); } }); } }
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}'."); } }
/// <exception cref="MobileCenterException">Attempted to add duplicate channel to group</exception> public IChannelUnit AddChannel(string name, int maxLogsPerBatch, TimeSpan batchTimeInterval, int maxParallelBatches) { ThrowIfDisposed(); lock (_channelGroupLock) { MobileCenterLog.Debug(MobileCenterLog.LogTag, $"AddChannel({name})"); var newChannel = new Channel(name, maxLogsPerBatch, batchTimeInterval, maxParallelBatches, AppSecret, _ingestion, _storage); AddChannel(newChannel); return(newChannel); } }
protected override void OnCreate() { base.OnCreate(); AppResourcePath = DirectoryInfo.Resource; DebuggingPort.MainWindow = MainWindow; app = new Calculator(IsLandscape()); LoadApplication(app); try { MobileCenter.LogLevel = LogLevel.Verbose; MobileCenter.Configure("efc52dfb-3133-4f7e-b73f-b798474204b2"); MobileCenter.Start(typeof(Analytics)); } catch (System.Exception exc) { MobileCenterLog.Debug(MobileCenterLog.LogTag, $"{exc}"); } // Registration for device orientation changing detection. MainWindow.RotationChanged += (s, e) => { if (IsLandscape()) { try { Analytics.TrackEvent("Mode Changed", new Dictionary <string, string> { { "mode", "Scientific" } }); } catch (System.Exception exc) { MobileCenterLog.Debug(MobileCenterLog.LogTag, $"{exc}"); } app.OnOrientationChanged(AppOrientation.Landscape); } else { try { Analytics.TrackEvent("Mode Changed", new Dictionary <string, string> { { "mode", "Regular" } }); } catch (System.Exception exc) { MobileCenterLog.Debug(MobileCenterLog.LogTag, $"{exc}"); } app.OnOrientationChanged(AppOrientation.Portrait); } }; }
/// <summary> /// If enabled, register push channel and send URI to backend. /// Also start intercepting pushes. /// If disabled and previously enabled, stop listening for pushes (they will still be received though). /// </summary> private void ApplyEnabledState(bool enabled) { if (enabled) { // We expect caller of this method to lock on _mutex, we can't do it here as that lock is not recursive MobileCenterLog.Debug(LogTag, "Getting push token..."); var state = _mutex.State; Task.Run(async() => { var channel = await new WindowsPushNotificationChannelManager().CreatePushNotificationChannelForApplicationAsync() .AsTask().ConfigureAwait(false); try { using (await _mutex.GetLockAsync(state).ConfigureAwait(false)) { var pushToken = channel.Uri; if (!string.IsNullOrEmpty(pushToken)) { // Save channel member _channel = channel; // Subscribe to push channel.PushNotificationReceived += OnPushNotificationReceivedHandler; // Send channel URI to backend MobileCenterLog.Debug(LogTag, $"Push token '{pushToken}'"); var pushInstallationLog = new PushInstallationLog(null, null, pushToken, Guid.NewGuid()); // Do not await the call to EnqueueAsync or the UI thread can be blocked! #pragma warning disable CS4014 Channel.EnqueueAsync(pushInstallationLog); #pragma warning restore } else { MobileCenterLog.Error(LogTag, "Push service registering with Mobile Center backend has failed."); } } } catch (StatefulMutexException) { MobileCenterLog.Warn(LogTag, "Push Enabled state changed after creating channel."); } }); } else if (_channel != null) { _channel.PushNotificationReceived -= OnPushNotificationReceivedHandler; } }
/// <summary> /// Asynchronously retrieves logs from storage and flags them to avoid duplicate retrievals on subsequent calls /// </summary> /// <param name="channelName">Name of the channel to retrieve logs from</param> /// <param name="limit">The maximum number of logs to retrieve</param> /// <param name="logs">A list to which the retrieved logs will be added</param> /// <returns>A batch ID for the set of returned logs; null if no logs are found</returns> /// <exception cref="StorageException"/> public async Task <string> GetLogsAsync(string channelName, int limit, List <Log> logs) { using (await _taskLockSource.GetTaskLockAsync().ConfigureAwait(false)) { logs?.Clear(); var retrievedLogs = new List <Log>(); MobileCenterLog.Debug(MobileCenterLog.LogTag, $"Trying to get up to {limit} logs from storage for {channelName}"); var idPairs = new List <Tuple <Guid?, long> >(); var failedToDeserializeALog = false; var retrievedEntries = await _storageAdapter.GetAsync <LogEntry>(entry => entry.Channel == channelName, limit) .ConfigureAwait(false); foreach (var entry in retrievedEntries) { if (_pendingDbIdentifiers.Contains(entry.Id)) { continue; } try { var log = LogSerializer.DeserializeLog(entry.Log); retrievedLogs.Add(log); idPairs.Add(Tuple.Create(log.Sid, Convert.ToInt64(entry.Id))); } catch (JsonException e) { MobileCenterLog.Error(MobileCenterLog.LogTag, "Cannot deserialize a log in storage", e); failedToDeserializeALog = true; await _storageAdapter.DeleteAsync <LogEntry>(row => row.Id == entry.Id).ConfigureAwait(false); } } if (failedToDeserializeALog) { MobileCenterLog.Warn(MobileCenterLog.LogTag, "Deleted logs that could not be deserialized"); } if (idPairs.Count == 0) { MobileCenterLog.Debug(MobileCenterLog.LogTag, $"No available logs in storage for channel '{channelName}'"); return(null); } // Process the results var batchId = Guid.NewGuid().ToString(); ProcessLogIds(channelName, batchId, idPairs); logs?.AddRange(retrievedLogs); return(batchId); } }
public void Pause() { lock (_lockObject) { if (_currentSessionState == SessionState.Inactive) { MobileCenterLog.Warn(Analytics.Instance.LogTag, "Trying to pause already inactive session."); return; } MobileCenterLog.Debug(Analytics.Instance.LogTag, "SessionTracker.Pause"); _lastPausedTime = TimeHelper.CurrentTimeInMilliseconds(); _currentSessionState = SessionState.Inactive; } }
private void ProcessLogIds(string channelName, string batchId, IEnumerable <Tuple <Guid?, long> > idPairs) { var ids = new List <long>(); var message = "The SID/ID pairs for returning logs are:"; foreach (var idPair in idPairs) { var sidString = idPair.Item1?.ToString() ?? "(null)"; message += "\n\t" + sidString + " / " + idPair.Item2; _pendingDbIdentifiers.Add(idPair.Item2); ids.Add(idPair.Item2); } _pendingDbIdentifierGroups.Add(GetFullIdentifier(channelName, batchId), ids); MobileCenterLog.Debug(MobileCenterLog.LogTag, message); }
public void Resume() { lock (_lockObject) { if (_currentSessionState == SessionState.Active) { MobileCenterLog.Warn(Analytics.Instance.LogTag, "Trying to resume already active session."); return; } MobileCenterLog.Debug(Analytics.Instance.LogTag, "SessionTracker.Resume"); _lastResumedTime = TimeHelper.CurrentTimeInMilliseconds(); _currentSessionState = SessionState.Active; SendStartSessionIfNeeded(); } }
/// <summary> /// If enabled, register push channel and send URI to backend. /// Also start intercepting pushes. /// If disabled and previously enabled, stop listening for pushes (they will still be received though). /// </summary> private void ApplyEnabledState(bool enabled) { if (enabled) { // We expect caller of this method to lock on _mutex, we can't do it here as that lock is not recursive var stateSnapshot = _stateKeeper.GetStateSnapshot(); Task.Run(async() => { var channel = await new WindowsPushNotificationChannelManager().CreatePushNotificationChannelForApplicationAsync() .AsTask().ConfigureAwait(false); try { _mutex.Lock(stateSnapshot); var pushToken = channel.Uri; if (!string.IsNullOrEmpty(pushToken)) { // Save channel member _channel = channel; // Subscribe to push channel.PushNotificationReceived += OnPushNotificationReceivedHandler; // Send channel URI to backend MobileCenterLog.Debug(LogTag, $"Push token '{pushToken}'"); var pushInstallationLog = new PushInstallationLog(0, null, pushToken, Guid.NewGuid()); await Channel.Enqueue(pushInstallationLog).ConfigureAwait(false); } else { MobileCenterLog.Error(LogTag, "Push service registering with Mobile Center backend has failed."); } } catch (StatefulMutexException) { MobileCenterLog.Warn(LogTag, "Push Enabled state changed after creating channel."); } finally { _mutex.Unlock(); } }); } else if (_channel != null) { _channel.PushNotificationReceived -= OnPushNotificationReceivedHandler; } }
private async Task TriggerIngestionAsync() { await _mutex.LockAsync().ConfigureAwait(false); var stateSnapshot = _stateKeeper.GetStateSnapshot(); try { if (!_enabled) { return; } MobileCenterLog.Debug(MobileCenterLog.LogTag, $"triggerIngestion({Name}) pendingLogCount={_pendingLogCount}"); _batchScheduled = false; if (_sendingBatches.Count >= _maxParallelBatches) { MobileCenterLog.Debug(MobileCenterLog.LogTag, "Already sending " + _maxParallelBatches + " batches of analytics data to the server"); return; } // Get a batch from storage var logs = new List <Log>(); _mutex.Unlock(); var batchId = await _storage.GetLogsAsync(Name, _maxLogsPerBatch, logs).ConfigureAwait(false); await _mutex.LockAsync(stateSnapshot).ConfigureAwait(false); if (batchId != null) { _sendingBatches.Add(batchId, logs); _pendingLogCount -= logs.Count; TriggerIngestion(logs, stateSnapshot, batchId); } } catch (StatefulMutexException e) { MobileCenterLog.Warn(MobileCenterLog.LogTag, "The TriggerIngestion operation has been cancelled", e); } finally { _mutex.Unlock(); } }
public Task Shutdown() { ThrowIfDisposed(); var tasks = new List <Task>(); lock (_channelGroupLock) { foreach (var channel in _channels) { tasks.Add(channel.Shutdown()); } MobileCenterLog.Debug(MobileCenterLog.LogTag, "Waiting for storage to finish operations"); if (!_storage.Shutdown(_shutdownTimeout)) { MobileCenterLog.Warn(MobileCenterLog.LogTag, "Storage taking too long to finish operations; shutting down channel without waiting any longer."); } } return(Task.WhenAll(tasks)); }
/// <summary> /// Asynchronously clears the stored state of logs that have been retrieved /// </summary> /// <param name="channelName"></param> public Task ClearPendingLogState(string channelName) { var task = new Task(() => { ClearPendingLogStateWithoutEnqueue(channelName); MobileCenterLog.Debug(MobileCenterLog.LogTag, $"Clear pending log states for channel {channelName}"); }); try { _queue.Add(task); } catch (InvalidOperationException) { throw new StorageException("The operation has been cancelled"); } _flushSemaphore.Release(); return(task); }
public override bool FinishedLaunching(UIApplication app, NSDictionary options) { Microsoft.WindowsAzure.MobileServices.CurrentPlatform.Init(); global::Xamarin.Forms.Forms.Init(); // Code for starting up the Xamarin Test Cloud Agent #if ENABLE_TEST_CLOUD Xamarin.Calabash.Start(); #endif Appearance.Configure(); MobileCenter.Start("b7cd7b07-85af-45eb-87e0-74f05d88acd4"); LoadApplication(new App()); MobileCenterLog.Debug("AppDelegate", "DidFinishLaunchingWithOptions"); return(base.FinishedLaunching(app, options)); }
// Internal and static so that it can be tested more easily internal static bool HasSessionTimedOut(long now, long lastQueuedLogTime, long lastResumedTime, long lastPausedTime) { var noLogSentForLong = lastQueuedLogTime == 0 || (now - lastQueuedLogTime) >= SessionTimeout; if (lastPausedTime == 0) { return(lastResumedTime == 0 && noLogSentForLong); } if (lastResumedTime == 0) { return(noLogSentForLong); } var isBackgroundForLong = (lastPausedTime >= lastResumedTime) && ((now - lastPausedTime) >= SessionTimeout); var wasBackgroundForLong = (lastResumedTime - Math.Max(lastPausedTime, lastQueuedLogTime)) >= SessionTimeout; MobileCenterLog.Debug(Analytics.Instance.LogTag, $"noLogSentForLong={noLogSentForLong} " + $"isBackgroundForLong={isBackgroundForLong} " + $"wasBackgroundForLong={wasBackgroundForLong}"); return(noLogSentForLong && (isBackgroundForLong || wasBackgroundForLong)); }
private async Task TriggerIngestionAsync(State state) { using (await _mutex.GetLockAsync(state).ConfigureAwait(false)) { if (!_enabled || !_batchScheduled) { return; } MobileCenterLog.Debug(MobileCenterLog.LogTag, $"triggerIngestion({Name}) pendingLogCount={_pendingLogCount}"); _batchScheduled = false; if (_sendingBatches.Count >= _maxParallelBatches) { MobileCenterLog.Debug(MobileCenterLog.LogTag, "Already sending " + _maxParallelBatches + " batches of analytics data to the server"); return; } } // Get a batch from storage var logs = new List <Log>(); var batchId = await _storage.GetLogsAsync(Name, _maxLogsPerBatch, logs).ConfigureAwait(false); if (batchId != null) { using (await _mutex.GetLockAsync(state).ConfigureAwait(false)) { _sendingBatches.Add(batchId, logs); _pendingLogCount -= logs.Count; } try { TriggerIngestion(state, logs, batchId); CheckPendingLogs(state); } catch (StorageException) { MobileCenterLog.Warn(MobileCenterLog.LogTag, "Something went wrong sending logs to ingestion"); } } }
/// <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 Task DeleteLogs(string channelName, string batchId) { var task = new Task(() => { try { MobileCenterLog.Debug(MobileCenterLog.LogTag, $"Deleting logs from storage for channel '{channelName}' with batch id '{batchId}'"); 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) { _storageAdapter .DeleteAsync <LogEntry>(entry => entry.Channel == channelName && entry.Id == id) .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) { _channel = channel; 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[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); }
private void PushNotificationReceivedHandler(object sender, PushNotificationReceivedEventArgs args) { string title = args.Title; string message = args.Message; var customData = args.CustomData; string customDataString = string.Empty; foreach (var pair in customData) { customDataString += $"key='{pair.Key}', value='{pair.Value}'"; } if (!string.IsNullOrEmpty(title) && !string.IsNullOrEmpty(message)) { MobileCenterLog.Debug(MobileCenterLog.LogTag, $"PushNotificationReceivedHandler received title:'{title}', message:'{message}', customData:{customDataString}"); } else { MobileCenterLog.Debug(MobileCenterLog.LogTag, $"PushNotificationReceivedHandler received customData:{customDataString}"); } }
public static void Log(Exception exception, MobileCenterLogType type = MobileCenterLogType.Warn) { var exceptionType = exception.GetType().ToString(); var message = exception.Message; System.Diagnostics.Debug.WriteLine(exceptionType); System.Diagnostics.Debug.WriteLine($"Error: {message}"); switch (type) { case MobileCenterLogType.Info: MobileCenterLog.Info(exceptionType, message, exception); break; case MobileCenterLogType.Warn: MobileCenterLog.Warn(exceptionType, message, exception); break; case MobileCenterLogType.Error: MobileCenterLog.Error(exceptionType, message, exception); break; case MobileCenterLogType.Assert: MobileCenterLog.Assert(exceptionType, message, exception); break; case MobileCenterLogType.Verbose: MobileCenterLog.Verbose(exceptionType, message, exception); break; case MobileCenterLogType.Debug: MobileCenterLog.Debug(exceptionType, message, exception); break; default: throw new Exception("MobileCenterLogType Does Not Exist"); } }
//NOTE: This method MUST be called from the UI thread public static void RefreshDisplayCache() { lock (LockObject) { DisplayInformation displayInfo = null; try { // This can throw exceptions that aren't well documented, so catch-all and ignore displayInfo = DisplayInformation.GetForCurrentView(); } catch (Exception e) { MobileCenterLog.Warn(MobileCenterLog.LogTag, "Could not get display information.", e); return; } if (_cachedScreenSize == ScreenSizeFromDisplayInfo(displayInfo)) { return; } _cachedScreenSize = ScreenSizeFromDisplayInfo(displayInfo); MobileCenterLog.Debug(MobileCenterLog.LogTag, $"Cached screen size updated to {_cachedScreenSize}"); InformationInvalidated?.Invoke(null, EventArgs.Empty); } }