diff --git a/src/ConfigCatClient.sln b/src/ConfigCatClient.sln index b7ddced9..6f2e6a0c 100644 --- a/src/ConfigCatClient.sln +++ b/src/ConfigCatClient.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30907.101 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32630.192 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConfigCatClient", "ConfigCatClient\ConfigCatClient.csproj", "{3046A17C-28AC-49A7-8B7B-E618FB5992F0}" EndProject diff --git a/src/ConfigCatClient/Evaluate/EvaluateLogger.cs b/src/ConfigCatClient/Evaluate/EvaluateLogger.cs index b24a7de6..236d7514 100644 --- a/src/ConfigCatClient/Evaluate/EvaluateLogger.cs +++ b/src/ConfigCatClient/Evaluate/EvaluateLogger.cs @@ -25,18 +25,12 @@ public override string ToString() { var result = new StringBuilder(); - result.AppendLine($" Evaluate '{KeyName}'"); - - result.AppendLine($" VariationId: {this.VariationId ?? "null"}"); - - result.AppendLine($" User object: {this.User.Serialize()}"); - + result.AppendLine($"Evaluating '{KeyName}'"); foreach (var o in this.Operations) { - result.AppendLine(" " + o); + result.AppendLine(" " + o); } - - result.AppendLine($" Returning: {this.ReturnValue}"); + result.Append($" Returning '{this.ReturnValue}' (VariationId: '{this.VariationId ?? "null"}')."); return result.ToString(); } @@ -61,8 +55,8 @@ public static string FormatComparator(Comparator comparator) Comparator.NumberGreaterThanEqual => ">=", Comparator.NumberEqual => "=", Comparator.NumberNotEqual => "!=", - Comparator.SensitiveOneOf => "IS ONE OF (Sensitive)", - Comparator.SensitiveNotOneOf => "IS NOT ONE OF (Sensitive)", + Comparator.SensitiveOneOf => "IS ONE OF (hashed)", + Comparator.SensitiveNotOneOf => "IS NOT ONE OF (hashed)", _ => comparator.ToString() }; } diff --git a/src/ConfigCatClient/Evaluate/RolloutEvaluator.cs b/src/ConfigCatClient/Evaluate/RolloutEvaluator.cs index 395bede1..97486d33 100644 --- a/src/ConfigCatClient/Evaluate/RolloutEvaluator.cs +++ b/src/ConfigCatClient/Evaluate/RolloutEvaluator.cs @@ -24,7 +24,7 @@ public T Evaluate(IDictionary settings, string key, T defaul { if (settings.Count == 0) { - this.log.Error($"Config JSON is not present. Returning defaultValue: [{defaultValue}]."); + this.log.Error($"Config JSON is not present. Returning the defaultValue defined in the app source code: '{defaultValue}'."); return defaultValue; } @@ -40,7 +40,7 @@ public object Evaluate(IDictionary settings, string key, object { if (settings.Count == 0) { - this.log.Error($"Config JSON is not present. Returning defaultValue: [{defaultValue}]."); + this.log.Error($"Config JSON is not present. Returning the defaultValue defined in the app source code: '{defaultValue}'."); return defaultValue; } @@ -56,7 +56,7 @@ public string EvaluateVariationId(IDictionary settings, string { if (settings.Count == 0) { - this.log.Error($"Config JSON is not present. Returning defaultVariationId: [{defaultVariationId}]."); + this.log.Error($"Config JSON is not present. Returning defaultVariationId: '{defaultVariationId}'."); return defaultVariationId; } @@ -69,7 +69,7 @@ private EvaluateResult EvaluateLogic(IDictionary settings, stri if (!settings.TryGetValue(key, out var setting)) { var keys = string.Join(",", settings.Keys.Select(s => $"'{s}'").ToArray()); - this.log.Error($"Evaluating '{key}' failed. Returning default value: '{logDefaultValue}'. Here are the available keys: {keys}."); + this.log.Error($"Evaluating '{key}' failed (key not found in ConfigCat). Returning the defaultValue that you defined in the source code: '{logDefaultValue}'. Here are the available keys: {keys}."); return null; } @@ -110,7 +110,7 @@ private EvaluateResult EvaluateLogic(IDictionary settings, stri } else if (setting.RolloutRules.Any() || setting.RolloutPercentageItems.Any()) { - this.log.Warning($"Evaluating '{key}'. UserObject missing! You should pass a UserObject to GetValue() or GetValueAsync(), in order to make targeting work properly. Read more: https://configcat.com/docs/advanced/user-object"); + this.log.Warning($"Cannot evaluate targeting rules and % options for '{key}' (UserObject missing). You should pass a UserObject to GetValue() or GetValueAsync() in order to make targeting work properly. Read more: https://configcat.com/docs/advanced/user-object"); } // regular evaluate @@ -129,7 +129,7 @@ private EvaluateResult EvaluateLogic(IDictionary settings, stri } finally { - this.log.Information(evaluateLog.ToString()); + this.log.Information($"{evaluateLog}"); } } @@ -145,6 +145,7 @@ private static bool TryEvaluateVariations(ICollection var hashValue = hashCandidate.Hash().Substring(0, 7); var hashScale = int.Parse(hashValue, NumberStyles.HexNumber) % 100; + evaluateLog.Log($"Applying the % option that matches the User's pseudo-random '{hashScale}' (this value is sticky and consistent across all SDKs):"); var bucket = 0; @@ -152,10 +153,14 @@ private static bool TryEvaluateVariations(ICollection { bucket += variation.Percentage; - if (hashScale >= bucket) continue; + if (hashScale >= bucket) + { + evaluateLog.Log($" - % option: [IF {bucket} > {hashScale} THEN '{variation.Value}'] => no match"); + continue; + } result.Value = variation.Value; result.VariationId = variation.VariationId; - evaluateLog.Log($"Evaluating % options, '{key}' evaluated to '{variation.Value}'."); + evaluateLog.Log($" - % option: [IF {bucket} > {hashScale} THEN '{variation.Value}'] => MATCH, applying % option"); return true; } } @@ -169,24 +174,26 @@ private static bool TryEvaluateRules(ICollection rules, User use if (rules is { Count: > 0 }) { + logger.Log($"Applying the first targeting rule that matches the User '{user.Serialize()}':"); foreach (var rule in rules.OrderBy(o => o.Order)) { result.Value = rule.Value; result.VariationId = rule.VariationId; + string l = $" - rule: [IF User.{rule.ComparisonAttribute} {EvaluateLogger.FormatComparator(rule.Comparator)} '{rule.ComparisonValue}' THEN {rule.Value}] => "; if (!user.AllAttributes.ContainsKey(rule.ComparisonAttribute)) { + logger.Log(l + "no match"); continue; } var comparisonAttributeValue = user.AllAttributes[rule.ComparisonAttribute]; if (string.IsNullOrEmpty(comparisonAttributeValue)) { + logger.Log(l + "no match"); continue; } - string l = $"Evaluate rule: '{comparisonAttributeValue}' {EvaluateLogger.FormatComparator(rule.Comparator)} '{rule.ComparisonValue}' => "; - switch (rule.Comparator) { case Comparator.In: @@ -196,7 +203,7 @@ private static bool TryEvaluateRules(ICollection rules, User use .Select(t => t.Trim()) .Contains(comparisonAttributeValue)) { - logger.Log(l + "match"); + logger.Log(l + "MATCH, applying rule"); return true; } @@ -212,7 +219,7 @@ private static bool TryEvaluateRules(ICollection rules, User use .Select(t => t.Trim()) .Contains(comparisonAttributeValue)) { - logger.Log(l + "match"); + logger.Log(l + "MATCH, applying rule"); return true; } @@ -224,7 +231,7 @@ private static bool TryEvaluateRules(ICollection rules, User use if (comparisonAttributeValue.Contains(rule.ComparisonValue)) { - logger.Log(l + "match"); + logger.Log(l + "MATCH, applying rule"); return true; } @@ -236,7 +243,7 @@ private static bool TryEvaluateRules(ICollection rules, User use if (!comparisonAttributeValue.Contains(rule.ComparisonValue)) { - logger.Log(l + "match"); + logger.Log(l + "MATCH, applying rule"); return true; } @@ -253,7 +260,7 @@ private static bool TryEvaluateRules(ICollection rules, User use if (EvaluateSemVer(comparisonAttributeValue, rule.ComparisonValue, rule.Comparator)) { - logger.Log(l + "match"); + logger.Log(l + "MATCH, applying rule"); return true; } @@ -271,7 +278,7 @@ private static bool TryEvaluateRules(ICollection rules, User use if (EvaluateNumber(comparisonAttributeValue, rule.ComparisonValue, rule.Comparator)) { - logger.Log(l + "match"); + logger.Log(l + "MATCH, applying rule"); return true; } @@ -285,7 +292,7 @@ private static bool TryEvaluateRules(ICollection rules, User use .Select(t => t.Trim()) .Contains(comparisonAttributeValue.Hash())) { - logger.Log(l + "match"); + logger.Log(l + "MATCH, applying rule"); return true; } @@ -299,7 +306,7 @@ private static bool TryEvaluateRules(ICollection rules, User use .Select(t => t.Trim()) .Contains(comparisonAttributeValue.Hash())) { - logger.Log(l + "match"); + logger.Log(l + "MATCH, applying rule"); return true; } diff --git a/src/ConfigCatClient/Logging/ConsoleLogger.cs b/src/ConfigCatClient/Logging/ConsoleLogger.cs index d72d0f65..7b0d03dd 100644 --- a/src/ConfigCatClient/Logging/ConsoleLogger.cs +++ b/src/ConfigCatClient/Logging/ConsoleLogger.cs @@ -27,30 +27,31 @@ public ConsoleLogger(LogLevel logLevel) /// public void Debug(string message) { - Console.WriteLine(FormatMessage(LogLevel.Debug, message)); + PrintMessage(LogLevel.Debug, message); } /// public void Error(string message) { - Console.WriteLine(FormatMessage(LogLevel.Error, message)); + PrintMessage(LogLevel.Error, message); } /// public void Information(string message) { - Console.WriteLine(FormatMessage(LogLevel.Info, message)); + PrintMessage(LogLevel.Info, message); } /// public void Warning(string message) { - Console.WriteLine(FormatMessage(LogLevel.Warning, message)); + PrintMessage(LogLevel.Warning, message); } - private string FormatMessage(LogLevel logLevel, string message) + private void PrintMessage(LogLevel logLevel, string message) { - return $"ConfigCat - {logLevel} - {message}"; + string logLevelPadded = logLevel.ToString().ToUpper().PadRight(7); + Console.WriteLine($"ConfigCat.{logLevelPadded} {message}"); } } } diff --git a/src/ConfigCatClient/Logging/LogLevel.cs b/src/ConfigCatClient/Logging/LogLevel.cs index cfcb12f5..6246a11b 100644 --- a/src/ConfigCatClient/Logging/LogLevel.cs +++ b/src/ConfigCatClient/Logging/LogLevel.cs @@ -7,23 +7,23 @@ public enum LogLevel { /// - /// No tracing and any debugging messages. + /// No messages are logged. /// Off = 0, /// - /// Error messages. + /// Error messages are logged. All other messages are discarded. /// Error = 1, /// - /// Error and warning messages. + /// Warning and Error messages should be logged. Information and Debug messages are discarded. /// Warning = 2, /// - /// Information, Error and Warning messages. + /// Information, Warning and Error are logged. Debug messages are discarded. /// Info = 3, /// - /// All messages + /// All messages should be logged. /// Debug = 4 }