Beispiel #1
0
        private void HandleSendingFailure(State state, string batchId, IngestionException e)
        {
            var isRecoverable = e?.IsRecoverable ?? false;

            AppCenterLog.Error(AppCenterLog.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);
        }
Beispiel #2
0
        private void HandleSendingFailure(State state, string batchId, Exception exception)
        {
            IList <Log> removedLogs;

            using (_mutex.GetLock(state))
            {
                removedLogs = _sendingBatches[batchId];
                _sendingBatches.Remove(batchId);
            }
            if (FailedToSendLog != null)
            {
                foreach (var log in removedLogs)
                {
                    AppCenterLog.Debug(AppCenterLog.LogTag, $"Invoke FailedToSendLog event for channel '{Name}'");
                    FailedToSendLog?.Invoke(this, new FailedToSendLogEventArgs(log, exception));
                }
            }
            try
            {
                _storage.DeleteLogs(Name, batchId);
            }
            catch (StorageException e)
            {
                AppCenterLog.Warn(AppCenterLog.LogTag, $"Could not delete logs for batch {batchId}", e);
            }
        }
Beispiel #3
0
 public async Task EnqueueAsync(Log log)
 {
     try
     {
         State state;
         bool  discardLogs;
         using (await _mutex.GetLockAsync().ConfigureAwait(false))
         {
             state       = _mutex.State;
             discardLogs = _discardLogs;
         }
         if (discardLogs)
         {
             AppCenterLog.Warn(AppCenterLog.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)
     {
         AppCenterLog.Warn(AppCenterLog.LogTag, "The Enqueue operation has been cancelled");
     }
 }
Beispiel #4
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();
            }
        }
Beispiel #5
0
        private async Task SignalDeletingLogs(IList <string> sendingBatches)
        {
            var logs = new List <Log>();

            try
            {
                do
                {
                    var batchId = await _storage.GetLogsAsync(Name, ClearBatchSize, logs).ConfigureAwait(false);

                    if (sendingBatches.Contains(batchId))
                    {
                        continue;
                    }
                    foreach (var log in logs)
                    {
                        AppCenterLog.Debug(AppCenterLog.LogTag, $"Invoke SendingLog for channel '{Name}'");
                        SendingLog?.Invoke(this, new SendingLogEventArgs(log));
                        AppCenterLog.Debug(AppCenterLog.LogTag, $"Invoke FailedToSendLog event for channel '{Name}'");
                        FailedToSendLog?.Invoke(this, new FailedToSendLogEventArgs(log, new CancellationException()));
                    }
                }while (logs.Count >= ClearBatchSize);
            }
            catch
            {
                AppCenterLog.Warn(AppCenterLog.LogTag, "Failed to invoke events for logs being deleted.");
            }
        }
Beispiel #6
0
        public Task Enqueue(Log log)
        {
            _mutex.Lock();
            var stateSnapshot = _stateKeeper.GetStateSnapshot();

            try
            {
                if (_discardLogs)
                {
                    MobileCenterLog.Warn(MobileCenterLog.LogTag, "Channel is disabled; logs are discarded");
                    _mutex.Unlock();
                    SendingLog?.Invoke(this, new SendingLogEventArgs(log));
                    FailedToSendLog?.Invoke(this, new FailedToSendLogEventArgs(log, new CancellationException()));
                    return(null);
                }
                _mutex.Unlock();
                EnqueuingLog?.Invoke(this, new EnqueuingLogEventArgs(log));
                _mutex.Lock(stateSnapshot);
                return(Task.Run(async() =>
                {
                    await PrepareLogAsync(log).ConfigureAwait(false);
                    await PersistLogAsync(log, stateSnapshot).ConfigureAwait(false);
                }));
            }
            catch (StatefulMutexException e)
            {
                MobileCenterLog.Warn(MobileCenterLog.LogTag, "The Enqueue operation has been cancelled", e);
                return(null);
            }
            finally
            {
                _mutex.Unlock();
            }
        }
Beispiel #7
0
 /// <summary>
 /// Suspend channel.
 /// </summary>
 /// <param name="state">Current state.</param>
 /// <param name="deleteLogs">Value indicating whether logs should be enabled or disabled.</param>
 /// <param name="exception">Possible error if unsuccessful.</param>
 /// <param name="needDisableChannel">Value indicating whether channel should be disabled. True by default.</param>
 private void Suspend(State state, bool deleteLogs, Exception exception, bool needDisableChannel = true)
 {
     AppCenterLog.Debug(AppCenterLog.LogTag, $"Suspend channel: '{Name}'");
     try
     {
         IList <string> sendingBatches = null;
         IList <Log>    unsentLogs     = null;
         using (_mutex.GetLock(state))
         {
             if (needDisableChannel)
             {
                 _enabled = false;
             }
             _batchScheduled = false;
             _discardLogs    = deleteLogs;
             if (deleteLogs)
             {
                 sendingBatches = _sendingBatches.Keys.ToList();
                 unsentLogs     = _sendingBatches.Values.SelectMany(batch => batch).ToList();
                 _sendingBatches.Clear();
             }
             state = _mutex.InvalidateState();
         }
         if (unsentLogs != null && FailedToSendLog != null)
         {
             foreach (var log in unsentLogs)
             {
                 AppCenterLog.Debug(AppCenterLog.LogTag, $"Invoke FailedToSendLog event for channel '{Name}'");
                 FailedToSendLog?.Invoke(this, new FailedToSendLogEventArgs(log, exception));
             }
         }
         if (deleteLogs)
         {
             IList <IServiceCall> calls;
             using (_mutex.GetLock(state))
             {
                 calls = _calls.ToList();
                 _calls.Clear();
                 _pendingLogCount = 0;
                 TriggerDeleteLogsOnSuspending(sendingBatches);
             }
             foreach (var call in calls)
             {
                 call.Cancel();
             }
         }
         _storage.ClearPendingLogState(Name);
     }
     catch (StatefulMutexException)
     {
         AppCenterLog.Warn(AppCenterLog.LogTag, "The suspend operation has been canceled");
     }
 }
Beispiel #8
0
 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)
             {
                 AppCenterLog.Error(AppCenterLog.LogTag, "Failed to close ingestion", e);
             }
             using (_mutex.GetLock(state))
             {
                 _pendingLogCount = 0;
                 TriggerDeleteLogsOnSuspending();
             }
         }
         _storage.ClearPendingLogState(Name);
     }
     catch (StatefulMutexException)
     {
         AppCenterLog.Warn(AppCenterLog.LogTag, "The Suspend operation has been cancelled");
     }
 }
Beispiel #9
0
        /// <summary>
        /// Enqueue a log asynchronously.
        /// </summary>
        /// <param name="log">log to enqueue.</param>
        /// <returns>The async Task for this operation.</returns>
        public async Task EnqueueAsync(Log log)
        {
            try
            {
                State state;
                bool  discardLogs;
                using (await _mutex.GetLockAsync().ConfigureAwait(false))
                {
                    state       = _mutex.State;
                    discardLogs = _discardLogs;
                }
                if (discardLogs)
                {
                    AppCenterLog.Warn(AppCenterLog.LogTag, "Channel is disabled; logs are discarded");
                    AppCenterLog.Debug(AppCenterLog.LogTag, $"Invoke SendingLog event for channel '{Name}'");
                    SendingLog?.Invoke(this, new SendingLogEventArgs(log));
                    AppCenterLog.Debug(AppCenterLog.LogTag, $"Invoke FailedToSendLog event for channel '{Name}'");
                    FailedToSendLog?.Invoke(this, new FailedToSendLogEventArgs(log, new CancellationException()));
                    return;
                }
                AppCenterLog.Debug(AppCenterLog.LogTag, $"Invoke EnqueuingLog event for channel '{Name}'");
                EnqueuingLog?.Invoke(this, new EnqueuingLogEventArgs(log));
                await PrepareLogAsync(log, state).ConfigureAwait(false);

                AppCenterLog.Debug(AppCenterLog.LogTag, $"Invoke FilteringLog event for channel '{Name}'");
                var filteringLogEventArgs = new FilteringLogEventArgs(log);
                FilteringLog?.Invoke(this, filteringLogEventArgs);
                if (filteringLogEventArgs.FilterRequested)
                {
                    AppCenterLog.Warn(AppCenterLog.LogTag, $"Filtering out a log of type '{log.GetType()}' at the request of an event handler.");
                }
                else
                {
                    await PersistLogAsync(log, state).ConfigureAwait(false);
                }
            }
            catch (StatefulMutexException)
            {
                AppCenterLog.Warn(AppCenterLog.LogTag, "The Enqueue operation has been canceled");
            }
        }
Beispiel #10
0
        private async Task SignalDeletingLogs(State stateSnapshot)
        {
            var logs = new List <Log>();

            _mutex.Unlock();
            await _storage.GetLogsAsync(Name, ClearBatchSize, logs).ConfigureAwait(false);

            await _mutex.LockAsync(stateSnapshot).ConfigureAwait(false);

            foreach (var log in logs)
            {
                _mutex.Unlock();
                SendingLog?.Invoke(this, new SendingLogEventArgs(log));
                FailedToSendLog?.Invoke(this, new FailedToSendLogEventArgs(log, new CancellationException()));
                await _mutex.LockAsync(stateSnapshot).ConfigureAwait(false);
            }
            if (logs.Count >= ClearBatchSize)
            {
                await SignalDeletingLogs(stateSnapshot).ConfigureAwait(false);
            }
        }
Beispiel #11
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);
            }
        }
Beispiel #12
0
        private Task SignalDeletingLogs()
        {
            var logs = new List <Log>();

            return(_storage.GetLogsAsync(Name, ClearBatchSize, logs)
                   .ContinueWith(completedTask =>
            {
                if (completedTask.IsFaulted)
                {
                    AppCenterLog.Warn(AppCenterLog.LogTag,
                                      "Failed to invoke events for logs being deleted.");
                    return;
                }
                foreach (var log in logs)
                {
                    SendingLog?.Invoke(this, new SendingLogEventArgs(log));
                    FailedToSendLog?.Invoke(this, new FailedToSendLogEventArgs(log, new CancellationException()));
                }
                if (logs.Count >= ClearBatchSize)
                {
                    SignalDeletingLogs();
                }
            }));
        }
 private void AnyChannelFailedToSendLog(object sender, FailedToSendLogEventArgs e)
 {
     FailedToSendLog?.Invoke(sender, e);
 }