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");
     }
 }
Example #2
0
        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();
            }
        }
Example #3
0
        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");
            }
        }
Example #4
0
        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();
            }
        }
Example #5
0
        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);
            }
        }
Example #9
0
 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);
     }
 }
Example #10
0
        /// <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);
 }
Example #12
0
        /// <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");
     }
 }
Example #16
0
        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);
            }
        }
Example #17
0
        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");
            }
        }
Example #18
0
 public void LogException(Exception exception)
 {
     MobileCenterLog.Error(MobileCenterLog.LogTag, exception.Message, exception);
 }
Example #19
0
 private static void OnUnhandledException(object sender, RaiseThrowableEventArgs e)
 {
     _exception = e.Exception;
     MobileCenterLog.Error(Crashes.LogTag, "Unhandled Exception:", _exception);
     JoinExceptionAndLog();
 }