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));
 }
Пример #3
0
        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);
            }
        }
Пример #4
0
        /// <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));
        }
Пример #5
0
        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));
            }
        }
Пример #6
0
 public void ExceptionTrace()
 {
     try
     {
         throw new Exception();
     }
     catch (Exception e)
     {
         var s = LogValues.ExceptionTrace(e).ToString();
         Assert.Contains("LogValuesTest.ExceptionTrace", s);
     }
 }
Пример #7
0
        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());
        }
Пример #8
0
 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);
            }
        }
Пример #12
0
        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);
        }
Пример #13
0
        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();
            }
        }
Пример #14
0
        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));
            }
        }
Пример #15
0
 private static string FormatLogValues(LogValues values, Exception ex)
 {
     return(string.Format(values.Format, values.Args));
 }
Пример #16
0
 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));
        }
Пример #18
0
 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);
 }