mirror of https://github.com/abpframework/abp.git
committed by
GitHub
2 changed files with 227 additions and 1 deletions
@ -0,0 +1,200 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Globalization; |
||||
|
using Shouldly; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Microsoft.Extensions.Logging; |
||||
|
|
||||
|
public class AbpLoggerExtensions_Tests |
||||
|
{ |
||||
|
[Fact] |
||||
|
public void LogException_Should_Format_String_Data() |
||||
|
{ |
||||
|
var logger = new FakeLogger(); |
||||
|
var exception = new Exception("test"); |
||||
|
exception.Data["Name"] = "John"; |
||||
|
|
||||
|
logger.LogException(exception); |
||||
|
|
||||
|
logger.LastLoggedMessage.ShouldContain("Name = John"); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void LogException_Should_Format_Primitive_Data() |
||||
|
{ |
||||
|
var logger = new FakeLogger(); |
||||
|
var exception = new Exception("test"); |
||||
|
exception.Data["Count"] = 42; |
||||
|
exception.Data["IsActive"] = true; |
||||
|
|
||||
|
logger.LogException(exception); |
||||
|
|
||||
|
logger.LastLoggedMessage.ShouldContain("Count = 42"); |
||||
|
logger.LastLoggedMessage.ShouldContain("IsActive = True"); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void LogException_Should_Format_Complex_Object_As_Json() |
||||
|
{ |
||||
|
var logger = new FakeLogger(); |
||||
|
var exception = new Exception("test"); |
||||
|
exception.Data["Details"] = new Dictionary<string, object> |
||||
|
{ |
||||
|
{ "RuleName", "FixedWindow" }, |
||||
|
{ "Limit", 10 } |
||||
|
}; |
||||
|
|
||||
|
logger.LogException(exception); |
||||
|
|
||||
|
logger.LastLoggedMessage.ShouldContain("\"RuleName\":\"FixedWindow\""); |
||||
|
logger.LastLoggedMessage.ShouldContain("\"Limit\":10"); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void LogException_Should_Format_List_Of_Complex_Objects_As_Json() |
||||
|
{ |
||||
|
var logger = new FakeLogger(); |
||||
|
var exception = new Exception("test"); |
||||
|
exception.Data["RuleDetails"] = new List<Dictionary<string, object>> |
||||
|
{ |
||||
|
new() { { "RuleName", "FixedWindow" }, { "Limit", 10 } }, |
||||
|
new() { { "RuleName", "SlidingWindow" }, { "Limit", 20 } } |
||||
|
}; |
||||
|
|
||||
|
logger.LogException(exception); |
||||
|
|
||||
|
var message = logger.LastLoggedMessage; |
||||
|
message.ShouldNotContain("System.Collections.Generic.List"); |
||||
|
message.ShouldContain("FixedWindow"); |
||||
|
message.ShouldContain("SlidingWindow"); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void LogException_Should_Format_Null_Data_As_Empty() |
||||
|
{ |
||||
|
var logger = new FakeLogger(); |
||||
|
var exception = new Exception("test"); |
||||
|
exception.Data["NullKey"] = null; |
||||
|
|
||||
|
logger.LogException(exception); |
||||
|
|
||||
|
logger.LastLoggedMessage.ShouldContain("NullKey = "); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void LogException_Should_Format_Enum_Data() |
||||
|
{ |
||||
|
var logger = new FakeLogger(); |
||||
|
var exception = new Exception("test"); |
||||
|
exception.Data["Level"] = LogLevel.Warning; |
||||
|
|
||||
|
logger.LogException(exception); |
||||
|
|
||||
|
logger.LastLoggedMessage.ShouldContain("Level = Warning"); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void LogException_Should_Format_DateTime_Data() |
||||
|
{ |
||||
|
var logger = new FakeLogger(); |
||||
|
var exception = new Exception("test"); |
||||
|
var now = new DateTime(2025, 1, 15, 10, 30, 0); |
||||
|
exception.Data["Timestamp"] = now; |
||||
|
|
||||
|
logger.LogException(exception); |
||||
|
|
||||
|
logger.LastLoggedMessage.ShouldContain($"Timestamp = {now.ToString(CultureInfo.CurrentCulture)}"); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void LogException_Should_Format_Guid_Data() |
||||
|
{ |
||||
|
var logger = new FakeLogger(); |
||||
|
var exception = new Exception("test"); |
||||
|
var id = Guid.NewGuid(); |
||||
|
exception.Data["Id"] = id; |
||||
|
|
||||
|
logger.LogException(exception); |
||||
|
|
||||
|
logger.LastLoggedMessage.ShouldContain($"Id = {id}"); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void LogException_Should_Format_Anonymous_Object_As_Json() |
||||
|
{ |
||||
|
var logger = new FakeLogger(); |
||||
|
var exception = new Exception("test"); |
||||
|
exception.Data["Info"] = new { Name = "Test", Value = 123 }; |
||||
|
|
||||
|
logger.LogException(exception); |
||||
|
|
||||
|
var message = logger.LastLoggedMessage; |
||||
|
message.ShouldContain("\"Name\":\"Test\""); |
||||
|
message.ShouldContain("\"Value\":123"); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void LogException_Should_Fallback_To_ToString_For_Non_Serializable_Object() |
||||
|
{ |
||||
|
var logger = new FakeLogger(); |
||||
|
var exception = new Exception("test"); |
||||
|
var selfRef = new SelfReferencingObject { Name = "Loop" }; |
||||
|
selfRef.Self = selfRef; |
||||
|
exception.Data["BadObject"] = selfRef; |
||||
|
|
||||
|
logger.LogException(exception); |
||||
|
|
||||
|
logger.LastLoggedMessage.ShouldNotBeNull(); |
||||
|
logger.LastLoggedMessage.ShouldContain("BadObject = SelfRef:Loop"); |
||||
|
logger.LastLoggedMessage.ShouldNotContain("\"Name\""); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void LogException_Should_Truncate_Large_Json_Output() |
||||
|
{ |
||||
|
var logger = new FakeLogger(); |
||||
|
var exception = new Exception("test"); |
||||
|
var largeList = new List<Dictionary<string, string>>(); |
||||
|
for (var i = 0; i < 500; i++) |
||||
|
{ |
||||
|
largeList.Add(new Dictionary<string, string> |
||||
|
{ |
||||
|
{ "Key", new string('x', 100) } |
||||
|
}); |
||||
|
} |
||||
|
exception.Data["LargeData"] = largeList; |
||||
|
|
||||
|
logger.LogException(exception); |
||||
|
|
||||
|
logger.LastLoggedMessage.ShouldNotBeNull(); |
||||
|
logger.LastLoggedMessage.ShouldContain("...(truncated)"); |
||||
|
} |
||||
|
|
||||
|
private class SelfReferencingObject |
||||
|
{ |
||||
|
public string Name { get; set; } = default!; |
||||
|
public override string ToString() => $"SelfRef:{Name}"; |
||||
|
public SelfReferencingObject? Self { get; set; } |
||||
|
} |
||||
|
|
||||
|
private class FakeLogger : ILogger |
||||
|
{ |
||||
|
public string? LastLoggedMessage { get; private set; } |
||||
|
|
||||
|
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter) |
||||
|
{ |
||||
|
LastLoggedMessage = formatter(state, exception); |
||||
|
} |
||||
|
|
||||
|
public bool IsEnabled(LogLevel logLevel) => true; |
||||
|
|
||||
|
public IDisposable BeginScope<TState>(TState state) where TState : notnull => NullDisposable.Instance; |
||||
|
|
||||
|
private class NullDisposable : IDisposable |
||||
|
{ |
||||
|
public static readonly NullDisposable Instance = new(); |
||||
|
public void Dispose() { } |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue