Beispiel #1
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 #2
0
        private void TriggerIngestion(State state, IList <Log> logs, string batchId)
        {
            // Before sending logs, trigger the sending event for this channel
            if (SendingLog != null)
            {
                foreach (var eventArgs in logs.Select(log => new SendingLogEventArgs(log)))
                {
                    SendingLog?.Invoke(this, eventArgs);
                }
            }

            // If the optional Install ID has no value, default to using empty GUID
            // TODO When InstallId will really be async, we should not use Result anymore
            var rawInstallId = AppCenter.GetInstallIdAsync().Result;
            var installId    = rawInstallId.HasValue ? rawInstallId.Value : Guid.Empty;

            using (var serviceCall = _ingestion.PrepareServiceCall(_appSecret, installId, logs))
            {
                serviceCall.ExecuteAsync().ContinueWith(completedTask =>
                {
                    var ingestionException = completedTask.Exception?.InnerException as IngestionException;
                    if (ingestionException == null)
                    {
                        HandleSendingSuccess(state, batchId);
                    }
                    else
                    {
                        HandleSendingFailure(state, batchId, ingestionException);
                    }
                });
            }
        }
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
        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 #5
0
        private async Task TriggerIngestionAsync(State state)
        {
            using (await _mutex.GetLockAsync(state).ConfigureAwait(false))
            {
                if (!_enabled || !_batchScheduled)
                {
                    return;
                }
                AppCenterLog.Debug(AppCenterLog.LogTag,
                                   $"TriggerIngestion({Name}) pending log count: {_pendingLogCount}");
                _batchScheduled = false;
                if (_sendingBatches.Count >= _maxParallelBatches)
                {
                    AppCenterLog.Debug(AppCenterLog.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
                {
                    // Before sending logs, trigger the sending event for this channel
                    if (SendingLog != null)
                    {
                        foreach (var log in logs)
                        {
                            AppCenterLog.Debug(AppCenterLog.LogTag, $"Invoke SendingLog event for channel '{Name}'");
                            SendingLog?.Invoke(this, new SendingLogEventArgs(log));
                        }
                    }

                    // If the optional Install ID has no value, default to using empty GUID
                    var installId = await AppCenter.GetInstallIdAsync().ConfigureAwait(false) ?? Guid.Empty;

                    var ingestionCall = _ingestion.Call(_appSecret, installId, logs);
                    using (await _mutex.GetLockAsync(state).ConfigureAwait(false))
                    {
                        _calls.Add(ingestionCall);
                    }
                    ingestionCall.ContinueWith(call => HandleSendingResult(state, batchId, call));
                    CheckPendingLogs(state);
                }
                catch (StorageException)
                {
                    AppCenterLog.Warn(AppCenterLog.LogTag, "Something went wrong sending logs to ingestion");
                }
            }
        }
Beispiel #6
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 #7
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 #8
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 AnyChannelSendingLog(object sender, SendingLogEventArgs e)
 {
     SendingLog?.Invoke(sender, e);
 }
Beispiel #10
0
        private void TriggerIngestion(IList <Log> logs, State stateSnapshot, string batchId)
        {
            // Before sending logs, trigger the sending event for this channel
            if (SendingLog != null)
            {
                foreach (var eventArgs in logs.Select(log => new SendingLogEventArgs(log)))
                {
                    _mutex.Unlock();
                    SendingLog?.Invoke(this, eventArgs);
                    _mutex.Lock(stateSnapshot);
                }
            }
            // If the optional Install ID has no value, default to using empty GUID
            var installId   = MobileCenter.InstallId.HasValue ? MobileCenter.InstallId.Value : Guid.Empty;
            var serviceCall = _ingestion.PrepareServiceCall(_appSecret, installId, logs);

            serviceCall.ServiceCallFailedCallback = exception =>
            {
                serviceCall.Dispose();
                HandleSendingFailure(batchId, exception);
            };

            serviceCall.ServiceCallSucceededCallback = async() =>
            {
                serviceCall.Dispose();
                if (!_stateKeeper.IsCurrent(stateSnapshot))
                {
                    return;
                }
                try
                {
                    await _storage.DeleteLogsAsync(Name, batchId).ConfigureAwait(false);
                }
                catch (StorageException e)
                {
                    MobileCenterLog.Warn(MobileCenterLog.LogTag, $"Could not delete logs for batch {batchId}", e);
                }
                try
                {
                    await _mutex.LockAsync(stateSnapshot).ConfigureAwait(false);

                    var removedLogs = _sendingBatches[batchId];
                    _sendingBatches.Remove(batchId);
                    if (SentLog != null)
                    {
                        foreach (var log in removedLogs)
                        {
                            _mutex.Unlock();
                            SentLog?.Invoke(this, new SentLogEventArgs(log));
                            _mutex.Lock(stateSnapshot);
                        }
                    }
                    CheckPendingLogs();
                }
                catch (StatefulMutexException)
                {
                }
                finally
                {
                    _mutex.Unlock();
                }
            };
            serviceCall.Execute();
        }