/// <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."); } }
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"); } }
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); }
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"); } } }
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)); } } } }
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); } } }
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); }
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); } }
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)); }
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); } }
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"); } }
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"); } } }
/// <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; } }
private void SaveConfiguration() { try { configuration.Save(); } catch (ConfigurationErrorsException e) { AppCenterLog.Warn(AppCenterLog.LogTag, $"Configuration file can't be saved. Failure reason: {e.Message}"); } }
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); }
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."); } } }); } } }
/// <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); }); }
/// <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; })); }
/// <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; } }
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."); } }
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); }
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(); } }