private EvaluationDetail <T> Evaluate <T>(string featureKey, User user, LdValue defaultValue, LdValue.Converter <T> converter, bool checkType, EventFactory eventFactory) { T defaultValueOfType = converter.ToType(defaultValue); if (!Initialized) { if (_dataStore.Initialized()) { _evalLog.Warn("Flag evaluation before client initialized; using last known values from data store"); } else { _evalLog.Warn("Flag evaluation before client initialized; data store unavailable, returning default value"); return(new EvaluationDetail <T>(defaultValueOfType, null, EvaluationReason.ErrorReason(EvaluationErrorKind.ClientNotReady))); } } FeatureFlag featureFlag = null; try { featureFlag = GetFlag(featureKey); if (featureFlag == null) { _evalLog.Info("Unknown feature flag \"{0}\"; returning default value", featureKey); _eventProcessor.RecordEvaluationEvent(eventFactory.NewUnknownFlagEvaluationEvent( featureKey, user, defaultValue, EvaluationErrorKind.FlagNotFound)); return(new EvaluationDetail <T>(defaultValueOfType, null, EvaluationReason.ErrorReason(EvaluationErrorKind.FlagNotFound))); } if (user == null || user.Key == null) { _evalLog.Warn("Null user or null user key when evaluating flag \"{0}\"; returning default value", featureKey); _eventProcessor.RecordEvaluationEvent(eventFactory.NewDefaultValueEvaluationEvent( featureFlag, user, defaultValue, EvaluationErrorKind.UserNotSpecified)); return(new EvaluationDetail <T>(defaultValueOfType, null, EvaluationReason.ErrorReason(EvaluationErrorKind.UserNotSpecified))); } Evaluator.EvalResult evalResult = _evaluator.Evaluate(featureFlag, user, eventFactory); if (!IsOffline()) { foreach (var prereqEvent in evalResult.PrerequisiteEvents) { _eventProcessor.RecordEvaluationEvent(prereqEvent); } } var evalDetail = evalResult.Result; EvaluationDetail <T> returnDetail; if (evalDetail.VariationIndex == null) { returnDetail = new EvaluationDetail <T>(defaultValueOfType, null, evalDetail.Reason); evalDetail = new EvaluationDetail <LdValue>(defaultValue, null, evalDetail.Reason); } else { if (checkType && !defaultValue.IsNull && evalDetail.Value.Type != defaultValue.Type) { _evalLog.Error("Expected type {0} but got {1} when evaluating feature flag \"{2}\"; returning default value", defaultValue.Type, evalDetail.Value.Type, featureKey); _eventProcessor.RecordEvaluationEvent(eventFactory.NewDefaultValueEvaluationEvent( featureFlag, user, defaultValue, EvaluationErrorKind.WrongType)); return(new EvaluationDetail <T>(defaultValueOfType, null, EvaluationReason.ErrorReason(EvaluationErrorKind.WrongType))); } returnDetail = new EvaluationDetail <T>(converter.ToType(evalDetail.Value), evalDetail.VariationIndex, evalDetail.Reason); } _eventProcessor.RecordEvaluationEvent(eventFactory.NewEvaluationEvent( featureFlag, user, evalDetail, defaultValue)); return(returnDetail); } catch (Exception e) { LogHelpers.LogException(_evalLog, string.Format("Exception when evaluating feature flag \"{0}\"", featureKey), e); var reason = EvaluationReason.ErrorReason(EvaluationErrorKind.Exception); if (featureFlag == null) { _eventProcessor.RecordEvaluationEvent(eventFactory.NewUnknownFlagEvaluationEvent( featureKey, user, defaultValue, EvaluationErrorKind.Exception)); } else { _eventProcessor.RecordEvaluationEvent(eventFactory.NewEvaluationEvent( featureFlag, user, new EvaluationDetail <LdValue>(defaultValue, null, reason), defaultValue)); } return(new EvaluationDetail <T>(defaultValueOfType, null, reason)); } }
/// <inheritdoc/> public FeatureFlagsState AllFlagsState(User user, params FlagsStateOption[] options) { if (IsOffline()) { _evalLog.Warn("AllFlagsState() called when client is in offline mode; returning empty state"); return(new FeatureFlagsState(false)); } if (!Initialized) { if (_dataStore.Initialized()) { _evalLog.Warn("AllFlagsState() called before client initialized; using last known values from data store"); } else { _evalLog.Warn("AllFlagsState() called before client initialized; data store unavailable, returning empty state"); return(new FeatureFlagsState(false)); } } if (user == null || user.Key == null) { _evalLog.Warn("AllFlagsState() called with null user or null user key; returning empty state"); return(new FeatureFlagsState(false)); } var builder = new FeatureFlagsStateBuilder(options); var clientSideOnly = FlagsStateOption.HasOption(options, FlagsStateOption.ClientSideOnly); var withReasons = FlagsStateOption.HasOption(options, FlagsStateOption.WithReasons); var detailsOnlyIfTracked = FlagsStateOption.HasOption(options, FlagsStateOption.DetailsOnlyForTrackedFlags); KeyedItems <ItemDescriptor> flags; try { flags = _dataStore.GetAll(DataModel.Features); } catch (Exception e) { LogHelpers.LogException(_log, "Exception while retrieving flags for AllFlagsState", e); return(new FeatureFlagsState(false)); } foreach (var pair in flags.Items) { if (pair.Value.Item is null || !(pair.Value.Item is FeatureFlag flag)) { continue; } if (clientSideOnly && !flag.ClientSide) { continue; } try { Evaluator.EvalResult result = _evaluator.Evaluate(flag, user, EventFactory.Default); builder.AddFlag(flag.Key, result.Result.Value, result.Result.VariationIndex, result.Result.Reason, flag.Version, flag.TrackEvents, flag.DebugEventsUntilDate); } catch (Exception e) { LogHelpers.LogException(_evalLog, string.Format("Exception caught for feature flag \"{0}\" when evaluating all flags", flag.Key), e); EvaluationReason reason = EvaluationReason.ErrorReason(EvaluationErrorKind.Exception); builder.AddFlag(flag.Key, new EvaluationDetail <LdValue>(LdValue.Null, null, reason)); } } return(builder.Build()); }