/// <summary>
        /// Saves an error log on disk.
        /// </summary>
        /// <param name="exception">The exception that caused the crash.</param>
        /// <param name="errorLog">The error log.</param>
        public virtual void InstanceSaveErrorLogFiles(System.Exception exception, ManagedErrorLog errorLog)
        {
            try
            {
                // Serialize main log file.
                var errorLogString   = LogSerializer.Serialize(errorLog);
                var errorLogFileName = errorLog.Id + ErrorLogFileExtension;
                AppCenterLog.Debug(Crashes.LogTag, "Saving uncaught exception.");
                var directory = InstanceGetErrorStorageDirectory();
                directory.CreateFile(errorLogFileName, errorLogString);
                AppCenterLog.Debug(Crashes.LogTag, $"Saved error log in directory {ErrorStorageDirectoryName} with name {errorLogFileName}.");

                try
                {
                    // Serialize exception as raw stack trace.
                    var exceptionFileName = errorLog.Id + ExceptionFileExtension;
                    directory.CreateFile(exceptionFileName, exception.ToString());
                    AppCenterLog.Debug(Crashes.LogTag, $"Saved exception in directory {ErrorStorageDirectoryName} with name {exceptionFileName}.");
                }
                catch (System.Exception ex)
                {
                    AppCenterLog.Warn(Crashes.LogTag, "Failed to serialize exception for client side inspection.", ex);
                }
            }
            catch (System.Exception ex)
            {
                AppCenterLog.Error(Crashes.LogTag, "Failed to save error log.", ex);
            }
        }
        public async Task ShutdownAsync()
        {
            ThrowIfDisposed();
            var tasks = new List <Task>();

            lock (_channelGroupLock)
            {
                if (_isShutdown)
                {
                    AppCenterLog.Warn(AppCenterLog.LogTag, "Attempted to shutdown channel multiple times.");
                    return;
                }
                _isShutdown = true;
                _ingestion.Close();
                foreach (var channel in _channels)
                {
                    tasks.Add(channel.ShutdownAsync());
                }
            }
            await Task.WhenAll(tasks).ConfigureAwait(false);

            AppCenterLog.Debug(AppCenterLog.LogTag, "Waiting for storage to finish operations.");
            if (!await _storage.ShutdownAsync(WaitStorageTimeout).ConfigureAwait(false))
            {
                AppCenterLog.Warn(AppCenterLog.LogTag, "Storage taking too long to finish operations; shutting down channel without waiting any longer.");
            }
        }
Пример #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");
     }
 }
Пример #4
0
        public static IEnumerable <ErrorAttachmentLog> GetErrorAttachments()
        {
            var attachments = new List <ErrorAttachmentLog>();

            if (Current.Properties.TryGetValue(CrashesContentPage.TextAttachmentKey, out var textAttachment) &&
                textAttachment is string text)
            {
                var attachment = ErrorAttachmentLog.AttachmentWithText(text, "hello.txt");
                attachments.Add(attachment);
            }
            if (Current.Properties.TryGetValue(CrashesContentPage.FileAttachmentKey, out var fileAttachment) &&
                fileAttachment is string file)
            {
                var filePicker = DependencyService.Get <IFilePicker>();
                if (filePicker != null)
                {
                    try
                    {
                        var result = filePicker.ReadFile(file);
                        if (result != null)
                        {
                            var attachment = ErrorAttachmentLog.AttachmentWithBinary(result.Item1, result.Item2, result.Item3);
                            attachments.Add(attachment);
                        }
                    }
                    catch (Exception e)
                    {
                        AppCenterLog.Warn(LogTag, "Couldn't read file attachment", e);
                        Current.Properties.Remove(CrashesContentPage.FileAttachmentKey);
                    }
                }
            }
            return(attachments);
        }
Пример #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.");
            }
        }
        ///<exception cref="IngestionException"/>
        private async Task ExecuteAsyncHelper()
        {
            while (true)
            {
                try
                {
                    await Ingestion.ExecuteCallAsync(this).ConfigureAwait(false);

                    return;
                }
                catch (IngestionException e)
                {
                    if (!e.IsRecoverable || _retryCount >= _retryIntervals.Length)
                    {
                        throw;
                    }
                    AppCenterLog.Warn(AppCenterLog.LogTag, "Failed to execute service call", e);
                }
                await _retryIntervals[_retryCount++]().ConfigureAwait(false);
                if (_tokenSource.Token.IsCancellationRequested)
                {
                    throw new IngestionException("The operation has been cancelled");
                }
            }
        }
Пример #7
0
 private void HandleSendingSuccess(State state, string batchId)
 {
     if (!_mutex.IsCurrent(state))
     {
         return;
     }
     try
     {
         _storage.DeleteLogs(Name, batchId);
     }
     catch (StorageException e)
     {
         AppCenterLog.Warn(AppCenterLog.LogTag, $"Could not delete logs for batch {batchId}", e);
         throw;
     }
     finally
     {
         List <Log> removedLogs;
         using (_mutex.GetLock(state))
         {
             removedLogs = _sendingBatches[batchId];
             _sendingBatches.Remove(batchId);
         }
         if (SentLog != null)
         {
             foreach (var log in removedLogs)
             {
                 SentLog?.Invoke(this, new SentLogEventArgs(log));
             }
         }
     }
 }
Пример #8
0
 private void SaveExceptionFile(Directory directory, string fileName, Exception exception)
 {
     try
     {
         using (var fileStream = NewFileStream(Path.Combine(directory.FullName, fileName), FileMode.Create))
         {
             var formatter = new BinaryFormatter();
             formatter.Serialize(fileStream, exception);
         }
         AppCenterLog.Debug(Crashes.LogTag, $"Saved exception in directory {ErrorStorageDirectoryName} with name {fileName}.");
     }
     catch (Exception e)
     {
         if (!exception.GetType().IsSerializable)
         {
             // Note that this still saves an empty file which acts as a marker for error report life cycle. Same as Android SDK.
             AppCenterLog.Warn(Crashes.LogTag, $"Cannot serialize {exception.GetType().FullName} exception for client side inspection. " +
                               "If you want to have access to the exception in the callbacks, please add a Serializable attribute " +
                               "and a deserialization constructor to the exception class.");
         }
         else
         {
             AppCenterLog.Warn(Crashes.LogTag, "Failed to serialize exception for client side inspection.", e);
         }
     }
 }
Пример #9
0
            public override NSArray AttachmentsWithCrashes(iOSCrashes crashes, MSACErrorReport msReport)
            {
                if (GetErrorAttachments == null)
                {
                    return(null);
                }
                var report      = new ErrorReport(msReport);
                var attachments = GetErrorAttachments(report);

                if (attachments != null)
                {
                    var nsArray = new NSMutableArray();
                    foreach (var attachment in attachments)
                    {
                        if (attachment != null)
                        {
                            nsArray.Add(attachment.internalAttachment);
                        }
                        else
                        {
                            AppCenterLog.Warn(LogTag, "Skipping null ErrorAttachmentLog in Crashes.GetErrorAttachments.");
                        }
                    }
                    return(nsArray);
                }
                return(null);
            }
Пример #10
0
 private void TriggerDeleteLogsOnSuspending(IList <string> sendingBatches)
 {
     try
     {
         if (SendingLog == null && FailedToSendLog == null)
         {
             _storage.DeleteLogs(Name);
             return;
         }
         SignalDeletingLogs(sendingBatches).ContinueWith(completedTask =>
         {
             try
             {
                 _storage.DeleteLogs(Name);
             }
             catch (StorageException e)
             {
                 AppCenterLog.Warn(AppCenterLog.LogTag, "Could not delete logs with error: ", e);
             }
         });
     }
     catch (StorageException e)
     {
         AppCenterLog.Warn(AppCenterLog.LogTag, "Could not delete logs with error: ", e);
     }
 }
Пример #11
0
        private Timer IntervalCall(int retry, Action action)
        {
            var interval = (int)_retryIntervals[retry - 1].TotalMilliseconds;

            AppCenterLog.Warn(AppCenterLog.LogTag, $"Try #{retry} failed and will be retried in {interval} ms");
            return(new Timer(state => action(), null, interval, Timeout.Infinite));
        }
Пример #12
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);
            }
        }
Пример #13
0
 private async Task PersistLogAsync(Log log, State state)
 {
     try
     {
         await _storage.PutLog(Name, log).ConfigureAwait(false);
     }
     catch (StorageException e)
     {
         AppCenterLog.Error(AppCenterLog.LogTag, "Error persisting log", e);
         return;
     }
     try
     {
         bool enabled;
         using (await _mutex.GetLockAsync(state).ConfigureAwait(false))
         {
             _pendingLogCount++;
             enabled = _enabled;
         }
         if (enabled)
         {
             CheckPendingLogs(state);
             return;
         }
         AppCenterLog.Warn(AppCenterLog.LogTag, "Channel is temporarily disabled; log was saved to disk");
     }
     catch (StatefulMutexException)
     {
         AppCenterLog.Warn(AppCenterLog.LogTag, "The PersistLog operation has been cancelled");
     }
 }
Пример #14
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");
                }
            }
        }
Пример #15
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
                AppCenterLog.Debug(LogTag, "Getting push token...");
                var state = _mutex.State;
                CreatePushNotificationChannel(channel =>
                {
                    try
                    {
                        using (_mutex.GetLock(state))
                        {
                            LatestPushToken = channel?.Uri;
                            if (!string.IsNullOrEmpty(LatestPushToken))
                            {
                                // Save channel member
                                _channel = channel;

                                // Subscribe to UserId Change.
                                UserIdContext.UserIdUpdated -= OnUserIdUpdated;
                                UserIdContext.UserIdUpdated += OnUserIdUpdated;

                                // Subscribe to push.
                                channel.PushNotificationReceived += OnPushNotificationReceivedHandler;

                                // Send channel URI to backend
                                AppCenterLog.Debug(LogTag, $"Push token '{LatestPushToken}'");
                                var pushInstallationLog = new PushInstallationLog(null, LatestPushToken, null, Guid.NewGuid(), UserIdContext.Instance.UserId);

                                // 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
                            {
                                AppCenterLog.Error(LogTag, "Push service registering with App Center backend has failed.");
                            }
                        }
                    }
                    catch (StatefulMutexException)
                    {
                        AppCenterLog.Warn(LogTag, "Push Enabled state changed after creating channel.");
                    }
                });
            }
            else if (_channel != null)
            {
                LatestPushToken                    = null;
                UserIdContext.UserIdUpdated       -= OnUserIdUpdated;
                _channel.PushNotificationReceived -= OnPushNotificationReceivedHandler;
            }
        }
Пример #16
0
 private void SaveConfiguration()
 {
     try
     {
         configuration.Save();
     }
     catch (ConfigurationErrorsException e)
     {
         AppCenterLog.Warn(AppCenterLog.LogTag, $"Configuration file can't be saved. Failure reason: {e.Message}");
     }
 }
Пример #17
0
 internal static string DeserializeException(byte[] exceptionBytes)
 {
     try
     {
         return(Encoding.UTF8.GetString(exceptionBytes));
     }
     catch (Exception e)
     {
         AppCenterLog.Warn(Crashes.LogTag, "Failed to deserialize exception for client side inspection.", e);
     }
     return(null);
 }
Пример #18
0
        private void CheckPendingLogs(State state)
        {
            if (!_enabled)
            {
                AppCenterLog.Info(AppCenterLog.LogTag, "The service has been disabled. Stop processing logs.");
                return;
            }
            if (!_ingestion.IsEnabled)
            {
                AppCenterLog.Info(AppCenterLog.LogTag, "App Center is in offline mode.");
                return;
            }
            AppCenterLog.Debug(AppCenterLog.LogTag, $"CheckPendingLogs({Name}) pending log count: {_pendingLogCount}");
            using (_mutex.GetLock())
            {
                if (_pendingLogCount >= _maxLogsPerBatch)
                {
                    _batchScheduled = true;
                    Task.Run(async() =>
                    {
                        try
                        {
                            await TriggerIngestionAsync(state).ConfigureAwait(false);
                        }
                        catch (StatefulMutexException)
                        {
                            AppCenterLog.Warn(AppCenterLog.LogTag, "Sending logs operation has been canceled.");
                        }
                    });
                }
                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)
                        {
                            try
                            {
                                await TriggerIngestionAsync(_mutex.State).ConfigureAwait(false);
                            }
                            catch (StatefulMutexException)
                            {
                                AppCenterLog.Warn(AppCenterLog.LogTag, "Sending logs operation has been canceled.");
                            }
                        }
                    });
                }
            }
        }
Пример #19
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");
     }
 }
        private static Func <Task> GetDelayFunc(TimeSpan[] intervals, int retry)
        {
            return(async() =>
            {
                var delayMilliseconds = (int)(intervals[retry].TotalMilliseconds / 2.0);
                delayMilliseconds += await GetRandomIntAsync(delayMilliseconds).ConfigureAwait(false);

                var message = $"Try #{retry} failed and will be retried in {delayMilliseconds} ms";
                AppCenterLog.Warn(AppCenterLog.LogTag, message);
                await Task.Delay(delayMilliseconds).ConfigureAwait(false);
            });
        }
Пример #21
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 Task <string> GetLogsAsync(string channelName, int limit, List <Log> logs)
        {
            return(AddTaskToQueue(() =>
            {
                logs?.Clear();
                var retrievedLogs = new List <Log>();
                AppCenterLog.Debug(AppCenterLog.LogTag,
                                   $"Trying to get up to {limit} logs from storage for {channelName}");
                var idPairs = new List <Tuple <Guid?, long> >();
                var failedToDeserializeALog = false;
                var objectEntries = _storageAdapter.Select(TableName, ColumnChannelName, channelName, ColumnIdName, _pendingDbIdentifiers.Cast <object>().ToArray(), limit);
                var retrievedEntries = objectEntries.Select(entries =>
                                                            new LogEntry()
                {
                    Id = (long)entries[0],
                    Channel = (string)entries[1],
                    Log = (string)entries[2]
                }
                                                            ).ToList();
                foreach (var entry in retrievedEntries)
                {
                    try
                    {
                        var log = LogSerializer.DeserializeLog(entry.Log);
                        retrievedLogs.Add(log);
                        idPairs.Add(Tuple.Create(log.Sid, Convert.ToInt64(entry.Id)));
                    }
                    catch (JsonException e)
                    {
                        AppCenterLog.Error(AppCenterLog.LogTag, "Cannot deserialize a log in storage", e);
                        failedToDeserializeALog = true;
                        _storageAdapter.Delete(TableName, ColumnIdName, entry.Id);
                    }
                }
                if (failedToDeserializeALog)
                {
                    AppCenterLog.Warn(AppCenterLog.LogTag, "Deleted logs that could not be deserialized");
                }
                if (idPairs.Count == 0)
                {
                    AppCenterLog.Debug(AppCenterLog.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;
            }));
        }
Пример #22
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 Task <string> GetLogsAsync(string channelName, int limit, List <Log> logs)
        {
            return(AddTaskToQueue(() =>
            {
                logs?.Clear();
                var retrievedLogs = new List <Log>();
                AppCenterLog.Debug(AppCenterLog.LogTag,
                                   $"Trying to get up to {limit} logs from storage for {channelName}");
                var idPairs = new List <Tuple <Guid?, long> >();
                var failedToDeserializeALog = false;
                var retrievedEntries =
                    _storageAdapter.GetAsync <LogEntry>(entry => entry.Channel == channelName, limit)
                    .GetAwaiter().GetResult();
                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)
                    {
                        AppCenterLog.Error(AppCenterLog.LogTag, "Cannot deserialize a log in storage", e);
                        failedToDeserializeALog = true;
                        _storageAdapter.DeleteAsync <LogEntry>(row => row.Id == entry.Id)
                        .GetAwaiter().GetResult();
                    }
                }
                if (failedToDeserializeALog)
                {
                    AppCenterLog.Warn(AppCenterLog.LogTag, "Deleted logs that could not be deserialized");
                }
                if (idPairs.Count == 0)
                {
                    AppCenterLog.Debug(AppCenterLog.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)
         {
             AppCenterLog.Warn(Analytics.Instance.LogTag, "Trying to pause already inactive session.");
             return;
         }
         AppCenterLog.Debug(Analytics.Instance.LogTag, "SessionTracker.Pause");
         _lastPausedTime      = TimeHelper.CurrentTimeInMilliseconds();
         _currentSessionState = SessionState.Inactive;
     }
 }
Пример #24
0
 static WpfHelper()
 {
     try
     {
         var assemblies = AppDomain.CurrentDomain.GetAssemblies();
         PresentationFramework =
             assemblies.FirstOrDefault(assembly => assembly.GetName().Name == "PresentationFramework");
         IsRunningOnWpf = PresentationFramework != null;
     }
     catch (AppDomainUnloadedException)
     {
         AppCenterLog.Warn(AppCenterLog.LogTag, "Unabled to determine whether this application is WPF or Windows Forms; proceeding as though it is Windows Forms.");
     }
 }
Пример #25
0
        public DefaultScreenSizeProvider()
        {
            if (!ApiInformation.IsPropertyPresent(typeof(DisplayInformation).FullName, "ScreenHeightInRawPixels") ||
                !ApiInformation.IsPropertyPresent(typeof(DisplayInformation).FullName, "ScreenWidthInRawPixels"))
            {
                AppCenterLog.Warn(AppCenterLog.LogTag, FailureMessage);
                _displayInformationEventSemaphore.Release();
                return;
            }

            // Only try to get screen size once resuming event is invoked, because there's no point
            // in trying beforehand.
            ApplicationLifecycleHelper.Instance.ApplicationResuming += SetUpDisplayInformation;
        }
        /// <summary>
        /// Validates properties.
        /// </summary>
        /// <param name="properties">Properties collection to validate.</param>
        /// <param name="logName">Log name.</param>
        /// <param name="logType">Log type.</param>
        /// <returns>Valid properties collection with maximum size of 5</returns>
        private IDictionary <string, string> ValidateProperties(IDictionary <string, string> properties, string logName, string logType)
        {
            if (properties == null)
            {
                return(null);
            }
            var result = new Dictionary <string, string>();

            foreach (var property in properties)
            {
                if (result.Count >= MaxEventProperties)
                {
                    AppCenterLog.Warn(LogTag,
                                      $"{logType} '{logName}' : properties cannot contain more than {MaxEventProperties} items. Skipping other properties.");
                    break;
                }

                // Skip empty property.
                var key   = property.Key;
                var value = property.Value;
                if (string.IsNullOrEmpty(key))
                {
                    AppCenterLog.Warn(LogTag,
                                      $"{logType} '{logName}' : a property key cannot be null or empty. Property will be skipped.");
                    break;
                }
                if (value == null)
                {
                    AppCenterLog.Warn(LogTag,
                                      $"{logType} '{logName}' : property '{key}' : property value cannot be null. Property will be skipped.");
                    break;
                }

                // Truncate exceeded property.
                if (key.Length > MaxEventPropertyKeyLength)
                {
                    AppCenterLog.Warn(LogTag,
                                      $"{logType} '{logName}' : property '{key}' : property key length cannot be longer than {MaxEventPropertyKeyLength} characters. Property key will be truncated.");
                    key = key.Substring(0, MaxEventPropertyKeyLength);
                }
                if (value.Length > MaxEventPropertyValueLength)
                {
                    AppCenterLog.Warn(LogTag,
                                      $"{logType} '{logName}' : property '{key}' : property value length cannot be longer than {MaxEventPropertyValueLength} characters. Property value will be truncated.");
                    value = value.Substring(0, MaxEventPropertyValueLength);
                }
                result.Add(key, value);
            }
            return(result);
        }
Пример #27
0
        public bool SetMaxStorageSize(long sizeInBytes)
        {
            var db = _db ?? throw new StorageException("The database wasn't initialized.");

            // Check the current number of pages in the database to determine whether the requested size will shrink the database.
            var currentPageCount = GetPageCount();
            var pageSize         = GetPageSize();

            AppCenterLog.Info(AppCenterLog.LogTag, $"Found {currentPageCount} pages in the database.");
            var requestedMaxPageCount = Convert.ToBoolean(sizeInBytes % pageSize) ? sizeInBytes / pageSize + 1 : sizeInBytes / pageSize;

            if (currentPageCount > requestedMaxPageCount)
            {
                AppCenterLog.Warn(AppCenterLog.LogTag, $"Cannot change database size to {sizeInBytes} bytes as it would cause a loss of data. " +
                                  "Maximum database size will not be changed.");
                return(false);
            }
            else
            {
                // Attempt to set the limit and check the page count to make sure the given limit works.
                var result = raw.sqlite3_exec(db, $"PRAGMA max_page_count = {requestedMaxPageCount};");
                if (result != raw.SQLITE_OK)
                {
                    AppCenterLog.Error(AppCenterLog.LogTag, $"Could not change maximum database size to {sizeInBytes} bytes. SQLite error code: {result}.");
                    return(false);
                }
                else
                {
                    var currentMaxPageCount = GetMaxPageCount();
                    var actualMaxSize       = currentMaxPageCount * pageSize;
                    if (requestedMaxPageCount != currentMaxPageCount)
                    {
                        AppCenterLog.Error(AppCenterLog.LogTag, $"Could not change maximum database size to {sizeInBytes} bytes, current maximum size is {actualMaxSize} bytes.");
                        return(false);
                    }
                    else
                    {
                        if (sizeInBytes == actualMaxSize)
                        {
                            AppCenterLog.Info(AppCenterLog.LogTag, $"Changed maximum database size to {actualMaxSize} bytes.");
                        }
                        else
                        {
                            AppCenterLog.Info(AppCenterLog.LogTag, $"Changed maximum database size to {actualMaxSize} bytes (next multiple of 4KiB).");
                        }
                        return(true);
                    }
                }
            }
        }
 public void Remove(string key)
 {
     lock (configLock)
     {
         if (configuration != null)
         {
             configuration.AppSettings.Settings.Remove(key);
             SaveConfiguration();
         }
         else
         {
             AppCenterLog.Warn(AppCenterLog.LogTag, $"{CorruptedConfigurationWarning} Method 'Remove', key:{key}");
         }
     }
 }
 public bool ContainsKey(string key)
 {
     lock (configLock)
     {
         if (configuration != null)
         {
             return(configuration.AppSettings.Settings[key] != null);
         }
         else
         {
             AppCenterLog.Warn(AppCenterLog.LogTag, $"{CorruptedConfigurationWarning} Method 'ContainsKey', key:{key}");
         }
     }
     return(false);
 }
 public void Resume()
 {
     lock (_lockObject)
     {
         if (_currentSessionState == SessionState.Active)
         {
             AppCenterLog.Warn(Analytics.Instance.LogTag, "Trying to resume already active session.");
             return;
         }
         AppCenterLog.Debug(Analytics.Instance.LogTag, "SessionTracker.Resume");
         _lastResumedTime     = TimeHelper.CurrentTimeInMilliseconds();
         _currentSessionState = SessionState.Active;
         SendStartSessionIfNeeded();
     }
 }