public IEnumerator <KeyValuePair <string, object> > GetEnumerator() { if (MessagePropertyCount == 0) { if (ExtraPropertyCount > 0) { return(_extraProperties.GetEnumerator()); } else { return(System.Linq.Enumerable.Empty <KeyValuePair <string, object> >().GetEnumerator()); } } else { if (ExtraPropertyCount > 0) { return(System.Linq.Enumerable.Concat(_extraProperties, LogValues).GetEnumerator()); } else { return(LogValues.GetEnumerator()); } } }
/// <summary> /// Logs an exception using the standard pattern for the LaunchDarkly SDKs. /// </summary> /// <remarks> /// The exception summary is logged at Error level. Then the stacktrace is logged at /// Debug level, using lazy evaluation to avoid computing it if Debug loggins is disabled. /// </remarks> /// <param name="logger">the logger instance</param> /// <param name="message">a descriptive prefix ("Unexpected error" if null or empty)</param> /// <param name="e">the exception</param> public static void LogException(Logger logger, string message, Exception e) { logger.Error("{0}: {1}", string.IsNullOrEmpty(message) ? "Unexpected error" : message, LogValues.ExceptionSummary(e)); logger.Debug(LogValues.ExceptionTrace(e)); }
private void OnMessage(object sender, EventSource.MessageReceivedEventArgs e) { try { HandleMessage(e.EventName, e.Message.Data); } catch (JsonReadException ex) { _log.Error("LaunchDarkly service request failed or received invalid data: {0}", LogValues.ExceptionSummary(ex)); var errorInfo = new DataSourceStatus.ErrorInfo { Kind = DataSourceStatus.ErrorKind.InvalidData, Message = ex.Message, Time = DateTime.Now }; _updateSink.UpdateStatus(DataSourceState.Interrupted, errorInfo); _eventSource.Restart(false); } catch (Exception ex) { LogHelpers.LogException(_log, "Unexpected error in stream processing", ex); } }
/// <summary> /// Creates a delegate which can be invoked to create a log scope. /// </summary> /// <param name="formatString">The named format string</param> /// <returns>A delegate which when invoked creates a log scope.</returns> public static Func <ILogger, IDisposable> DefineScope(string formatString) { var formatter = CreateLogValuesFormatter(formatString, expectedNamedParameterCount: 0); var logValues = new LogValues(formatter); return(logger => logger.BeginScope(logValues)); }
private async Task UpdateTaskAsync() { try { var response = await _featureFlagRequestor.FeatureFlagsAsync(); if (response.statusCode == 200) { var flagsAsJsonString = response.jsonResponse; var allData = DataModelSerialization.DeserializeV1Schema(flagsAsJsonString); _updateSink.Init(_user, allData); if (_initialized.GetAndSet(true) == false) { _startTask.SetResult(true); _log.Info("Initialized LaunchDarkly Polling Processor."); } } } catch (UnsuccessfulResponseException ex) { var errorInfo = DataSourceStatus.ErrorInfo.FromHttpError(ex.StatusCode); if (HttpErrors.IsRecoverable(ex.StatusCode)) { _log.Warn(HttpErrors.ErrorMessage(ex.StatusCode, "polling request", "will retry")); _updateSink.UpdateStatus(DataSourceState.Interrupted, errorInfo); } else { _log.Error(HttpErrors.ErrorMessage(ex.StatusCode, "polling request", "")); _updateSink.UpdateStatus(DataSourceState.Shutdown, errorInfo); // if client is initializing, make it stop waiting _startTask.TrySetResult(false); ((IDisposable)this).Dispose(); } } catch (JsonReadException ex) { _log.Error("Polling request received malformed data: {0}", LogValues.ExceptionSummary(ex)); _updateSink.UpdateStatus(DataSourceState.Interrupted, new DataSourceStatus.ErrorInfo { Kind = DataSourceStatus.ErrorKind.InvalidData, Time = DateTime.Now }); } catch (Exception ex) { Exception realEx = (ex is AggregateException ae) ? ae.Flatten() : ex; _log.Warn("Polling for feature flag updates failed: {0}", LogValues.ExceptionSummary(realEx)); _log.Debug(LogValues.ExceptionTrace(realEx)); _updateSink.UpdateStatus(DataSourceState.Interrupted, DataSourceStatus.ErrorInfo.FromException(realEx)); } }
public void ExceptionTrace() { try { throw new Exception(); } catch (Exception e) { var s = LogValues.ExceptionTrace(e).ToString(); Assert.Contains("LogValuesTest.ExceptionTrace", s); } }
public void ExceptionSummary() { var e2 = new ArgumentException("bad"); Assert.Equal("System.ArgumentException: bad", LogValues.ExceptionSummary(e2).ToString()); var e3 = new ArgumentException("bad", new NotSupportedException("worse")); Assert.Equal("System.ArgumentException: bad (caused by: System.NotSupportedException: worse)", LogValues.ExceptionSummary(e3).ToString()); }
internal void DoInit(FullDataSet <ItemDescriptor> data) { _log.Debug("using initial test data:\n{0}", LogValues.Defer(() => string.Join("\n", data.Data.Select(coll => coll.Key.Name + ":\n" + string.Join("\n", coll.Value.Items.Select(kv => coll.Key.Serialize(kv.Value) )) )) )); _updates.Init(data); }
private void ProcessError(Exception e) { if (e == null) { // If we're waiting to recover after a failure, we'll let the polling routine take care // of signaling success. Even if we could signal success a little earlier based on the // success of whatever operation we just did, we'd rather avoid the overhead of acquiring // w.statusLock every time we do anything. So we'll just do nothing here. return; } _log.Error("Error from persistent data store: {0}", LogValues.ExceptionSummary(e)); _statusManager.UpdateAvailability(false); }
private void ReportStoreFailure(Exception e) { if (!_lastStoreUpdateFailed) { _log.Warn("Unexpected data store error when trying to store an update received from the data source: {0}", LogValues.ExceptionSummary(e)); _lastStoreUpdateFailed = true; } _log.Debug(LogValues.ExceptionTrace(e)); UpdateStatus(DataSourceState.Interrupted, new DataSourceStatus.ErrorInfo { Kind = DataSourceStatus.ErrorKind.StoreError, Message = e.Message, Time = DateTime.Now }); }
private void OnMessage(object sender, EventSource.MessageReceivedEventArgs e) { try { HandleMessage(e.EventName, e.Message.DataUtf8Bytes.Data); // The way the PreferDataAsUtf8Bytes option works in EventSource is that if the // stream really is using UTF-8 encoding, the event data is passed to us directly // in Message.DataUtf8Bytes as a byte array and does not need to be converted to // a string. If the stream is for some reason using a different encoding, then // EventSource reads the data as a string (automatically converted by .NET from // whatever the encoding was), and then calling Message.DataUtf8Bytes converts // that to UTF-8 bytes. } catch (JsonReadException ex) { _log.Error("LaunchDarkly service request failed or received invalid data: {0}", LogValues.ExceptionSummary(ex)); var errorInfo = new DataSourceStatus.ErrorInfo { Kind = DataSourceStatus.ErrorKind.InvalidData, Message = ex.Message, Time = DateTime.Now }; _dataSourceUpdates.UpdateStatus(DataSourceState.Interrupted, errorInfo); _es.Restart(false); } catch (StreamStoreException) { if (!_storeStatusMonitoringEnabled) { if (!_lastStoreUpdateFailed) { _log.Warn("Restarting stream to ensure that we have the latest data"); } _es.Restart(false); } _lastStoreUpdateFailed = true; } catch (Exception ex) { LogHelpers.LogException(_log, "Unexpected error in stream processing", ex); _es.Restart(false); } }
public void DeferCallsFunctionOnlyWhenStringified() { var calls = 0; var thing = LogValues.Defer(() => { calls++; return(String.Format("calls={0}", calls)); }); Assert.Equal(0, calls); var s1 = thing.ToString(); Assert.Equal("calls=1", s1); Assert.Equal(1, calls); var s2 = thing.ToString(); Assert.Equal("calls=2", s2); }
private void OnError(object sender, EventSource.ExceptionEventArgs e) { var ex = e.Exception; var recoverable = true; DataSourceStatus.ErrorInfo errorInfo; RecordStreamInit(true); if (ex is EventSourceServiceUnsuccessfulResponseException respEx) { int status = respEx.StatusCode; errorInfo = DataSourceStatus.ErrorInfo.FromHttpError(status); if (!HttpErrors.IsRecoverable(status)) { recoverable = false; _log.Error(HttpErrors.ErrorMessage(status, "streaming connection", "")); } else { _log.Warn(HttpErrors.ErrorMessage(status, "streaming connection", "will retry")); } } else { errorInfo = DataSourceStatus.ErrorInfo.FromException(ex); _log.Warn("Encountered EventSource error: {0}", LogValues.ExceptionSummary(ex)); _log.Debug(LogValues.ExceptionTrace(ex)); } _updateSink.UpdateStatus(recoverable ? DataSourceState.Interrupted : DataSourceState.Shutdown, errorInfo); if (!recoverable) { // Make _initTask complete to tell the client to stop waiting for initialization. We use // TrySetResult rather than SetResult here because it might have already been completed // (if for instance the stream started successfully, then restarted and got a 401). _initTask.TrySetResult(false); ((IDisposable)this).Dispose(); } }
private async Task UpdateTaskAsync() { _log.Info("Polling LaunchDarkly for feature flag updates"); try { var allData = await _featureRequestor.GetAllDataAsync(); if (allData is null) { // This means it was cached, and alreadyInited was true _dataSourceUpdates.UpdateStatus(DataSourceState.Valid, null); } else { if (_dataSourceUpdates.Init(allData.Value)) { _dataSourceUpdates.UpdateStatus(DataSourceState.Valid, null); if (!_initialized.GetAndSet(true)) { _initTask.SetResult(true); _log.Info("First polling request successful"); } } } } catch (UnsuccessfulResponseException ex) { _log.Error(HttpErrors.ErrorMessage(ex.StatusCode, "polling request", "will retry")); var errorInfo = DataSourceStatus.ErrorInfo.FromHttpError(ex.StatusCode); if (HttpErrors.IsRecoverable(ex.StatusCode)) { _dataSourceUpdates.UpdateStatus(DataSourceState.Interrupted, errorInfo); } else { _dataSourceUpdates.UpdateStatus(DataSourceState.Off, errorInfo); try { // if client is initializing, make it stop waiting _initTask.SetResult(true); } catch (InvalidOperationException) { // the task was already set - nothing more to do } ((IDisposable)this).Dispose(); } } catch (JsonReadException ex) { _log.Error("Polling request received malformed data: {0}", LogValues.ExceptionSummary(ex)); _dataSourceUpdates.UpdateStatus(DataSourceState.Interrupted, new DataSourceStatus.ErrorInfo { Kind = DataSourceStatus.ErrorKind.InvalidData, Time = DateTime.Now }); } catch (Exception ex) { Exception realEx = (ex is AggregateException ae) ? ae.Flatten() : ex; LogHelpers.LogException(_log, "Polling for feature flag updates failed", realEx); _dataSourceUpdates.UpdateStatus(DataSourceState.Interrupted, DataSourceStatus.ErrorInfo.FromException(realEx)); } }
private static string FormatLogValues(LogValues values, Exception ex) { return(string.Format(values.Format, values.Args)); }
public override string ToString() => LogValues.ToString();
public async Task <EventSenderResult> SendEventDataAsync(EventDataKind kind, string data, int eventCount) { Uri uri; string description; string payloadId; if (kind == EventDataKind.DiagnosticEvent) { uri = _diagnosticUri; description = "diagnostic event"; payloadId = null; } else { uri = _eventsUri; description = string.Format("{0} event(s)", eventCount); payloadId = Guid.NewGuid().ToString(); } _logger.Debug("Submitting {0} to {1} with json: {2}", description, uri.AbsoluteUri, data); for (var attempt = 0; attempt < MaxAttempts; attempt++) { if (attempt > 0) { await Task.Delay(_retryInterval); } using (var cts = new CancellationTokenSource(_timeout)) { string errorMessage = null; bool canRetry = false; bool mustShutDown = false; try { using (var request = PrepareRequest(uri, payloadId)) using (var stringContent = new StringContent(data, Encoding.UTF8, "application/json")) { request.Content = stringContent; Stopwatch timer = new Stopwatch(); using (var response = await _httpClient.SendAsync(request, cts.Token)) { timer.Stop(); _logger.Debug("Event delivery took {0} ms, response status {1}", timer.ElapsedMilliseconds, (int)response.StatusCode); if (response.IsSuccessStatusCode) { DateTimeOffset?respDate = response.Headers.Date; return(new EventSenderResult(DeliveryStatus.Succeeded, respDate.HasValue ? (DateTime?)respDate.Value.DateTime : null)); } else { errorMessage = HttpErrors.ErrorMessageBase((int)response.StatusCode); canRetry = HttpErrors.IsRecoverable((int)response.StatusCode); mustShutDown = !canRetry; } } } } catch (TaskCanceledException e) { if (e.CancellationToken == cts.Token) { // Indicates the task was cancelled deliberately somehow; in this case don't retry _logger.Warn("Event sending task was cancelled"); return(new EventSenderResult(DeliveryStatus.Failed, null)); } else { // Otherwise this was a request timeout. errorMessage = "Timed out"; canRetry = true; } } catch (Exception e) { errorMessage = string.Format("Error ({0})", LogValues.ExceptionSummary(e)); canRetry = true; } string nextStepDesc = canRetry ? (attempt == MaxAttempts - 1 ? "will not retry" : "will retry after one second") : "giving up permanently"; _logger.Warn(errorMessage + " sending {0}; {1}", description, nextStepDesc); if (mustShutDown) { return(new EventSenderResult(DeliveryStatus.FailedAndMustShutDown, null)); } if (!canRetry) { break; } } } return(new EventSenderResult(DeliveryStatus.Failed, null)); }
internal void DoUpdate(DataKind kind, string key, ItemDescriptor item) { _log.Debug("updating \"{0}\" in {1} to {2}", key, kind.Name, LogValues.Defer(() => kind.Serialize(item))); _updates.Upsert(kind, key, item); }