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"); } }
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(); } }
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 PersistLogAsync(Log log, State stateSnapshot) { try { await _storage.PutLogAsync(Name, log).ConfigureAwait(false); } catch (StorageException e) { MobileCenterLog.Error(MobileCenterLog.LogTag, "Error persisting log", e); return; } try { await _mutex.LockAsync(stateSnapshot).ConfigureAwait(false); _pendingLogCount++; if (_enabled) { CheckPendingLogs(); return; } MobileCenterLog.Warn(MobileCenterLog.LogTag, "Channel is temporarily disabled; log was saved to disk"); } catch (StatefulMutexException e) { MobileCenterLog.Warn(MobileCenterLog.LogTag, "The PersistLog operation has been cancelled", e); } finally { _mutex.Unlock(); } }
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 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 InitializeDatabaseAsync() { try { await _storageAdapter.CreateTableAsync <LogEntry>().ConfigureAwait(false); } catch (StorageException e) { MobileCenterLog.Error(MobileCenterLog.LogTag, "An error occurred while initializing storage", e); } }
private static void OnUnhandledException(object sender, RaiseThrowableEventArgs e) { var exception = e.Exception; MobileCenterLog.Error(Crashes.LogTag, "Unhandled Exception:", exception); if (!(exception is Java.Lang.Exception)) { var modelException = GenerateModelException(exception, true); byte[] rawException = CrashesUtils.SerializeException(exception); WrapperSdkExceptionManager.SaveWrapperException(Thread.CurrentThread(), modelException, rawException); } }
private async Task InitializeDatabaseAsync() { // The mutex should already be owned and the task should be started try { await _storageAdapter.CreateTableAsync <LogEntry>().ConfigureAwait(false); } catch (StorageException e) { MobileCenterLog.Error(MobileCenterLog.LogTag, "An error occurred while initializing storage", e); } }
/// <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> /// Validates name. /// </summary> /// <param name="name">Log name to validate.</param> /// <param name="logType">Log type.</param> /// <returns><c>true</c> if validation succeeds, otherwise <с>false</с>.</returns> private bool ValidateName(string name, string logType) { if (string.IsNullOrEmpty(name)) { MobileCenterLog.Error(LogTag, logType + " name cannot be null or empty."); return(false); } if (name.Length > MaxEventNameLength) { MobileCenterLog.Error(LogTag, string.Format("{0} '{1}' : name length cannot be longer than {2} characters.", logType, name, MaxEventNameLength)); return(false); } return(true); }
/// <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); } }
/// <summary> /// Validates name. /// </summary> /// <param name="name">Log name to validate.</param> /// <param name="logType">Log type.</param> /// <returns><c>true</c> if validation succeeds, otherwise <с>false</с>.</returns> private bool ValidateName(ref string name, string logType) { if (string.IsNullOrEmpty(name)) { MobileCenterLog.Error(LogTag, $"{logType} name cannot be null or empty."); return(false); } if (name.Length > MaxEventNameLength) { MobileCenterLog.Warn(LogTag, $"{logType} '{name}' : name length cannot be longer than {MaxEventNameLength} characters. Name will be truncated."); name = name.Substring(0, MaxEventNameLength); return(true); } return(true); }
/// <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 void Suspend(State state, bool deleteLogs, Exception exception) { try { IEnumerable <Log> unsentLogs = null; using (_mutex.GetLock(state)) { _enabled = false; _batchScheduled = false; _discardLogs = deleteLogs; if (deleteLogs) { unsentLogs = _sendingBatches.Values.SelectMany(batch => batch); _sendingBatches.Clear(); } state = _mutex.InvalidateState(); } if (unsentLogs != null) { foreach (var log in unsentLogs) { FailedToSendLog?.Invoke(this, new FailedToSendLogEventArgs(log, exception)); } } if (deleteLogs) { try { _ingestion.Close(); } catch (IngestionException e) { MobileCenterLog.Error(MobileCenterLog.LogTag, "Failed to close ingestion", e); } using (_mutex.GetLock(state)) { _pendingLogCount = 0; TriggerDeleteLogsOnSuspending(); } } _storage.ClearPendingLogState(Name); } catch (StatefulMutexException) { MobileCenterLog.Warn(MobileCenterLog.LogTag, "The Suspend operation has been cancelled"); } }
private Task Suspend(bool deleteLogs, Exception exception) { _enabled = false; _batchScheduled = false; _discardLogs = deleteLogs; _stateKeeper.InvalidateState(); var stateSnapshot = _stateKeeper.GetStateSnapshot(); try { if (deleteLogs && FailedToSendLog != null) { foreach (var log in _sendingBatches.Values.SelectMany(batch => batch)) { _mutex.Unlock(); FailedToSendLog?.Invoke(this, new FailedToSendLogEventArgs(log, exception)); _mutex.Lock(stateSnapshot); } } try { _ingestion.Close(); } catch (IngestionException e) { MobileCenterLog.Error(MobileCenterLog.LogTag, "Failed to close ingestion", e); } if (deleteLogs) { _pendingLogCount = 0; return(Task.Run(DeleteLogsOnSuspendedAsync)); } return(_storage.ClearPendingLogStateAsync(Name)); } catch (StatefulMutexException e) { MobileCenterLog.Warn(MobileCenterLog.LogTag, "The CountFromDisk operation has been cancelled", e); return(null); } }
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"); } }
public void LogException(Exception exception) { MobileCenterLog.Error(MobileCenterLog.LogTag, exception.Message, exception); }
private static void OnUnhandledException(object sender, RaiseThrowableEventArgs e) { _exception = e.Exception; MobileCenterLog.Error(Crashes.LogTag, "Unhandled Exception:", _exception); JoinExceptionAndLog(); }