Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…a-dotnet into fix(tracing)-aot-void-task-and-serialization
  • Loading branch information
hjgraca committed Oct 31, 2024
2 parents 129f14e + 81acc01 commit 5bc2000
Show file tree
Hide file tree
Showing 9 changed files with 347 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@
* permissions and limitations under the License.
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.Json.Serialization;

namespace AWS.Lambda.Powertools.Logging.Internal.Helpers;

Expand All @@ -38,18 +41,31 @@ internal static object ObjectToDictionary(object anonymousObject)
return new Dictionary<string, object>();
}

if (anonymousObject.GetType().Namespace is not null)
var type = anonymousObject.GetType();

if (type.IsEnum)
{
return anonymousObject;
}

if (type.Namespace != null && !type.IsEnum)
{
return anonymousObject;
}

return anonymousObject.GetType().GetProperties()
return type.GetProperties()
.Where(prop => prop.GetValue(anonymousObject, null) != null)
.ToDictionary(
prop => prop.Name,
prop => {
var value = prop.GetValue(anonymousObject, null);
return value != null ? ObjectToDictionary(value) : string.Empty;
if (value == null)
return string.Empty;

if (value.GetType().IsEnum)
return value;

return ObjectToDictionary(value);
}
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.Extensions.Logging;

namespace AWS.Lambda.Powertools.Logging.Serializers;

internal class LogLevelJsonConverter : JsonConverter<LogLevel>
{
public override LogLevel Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return Enum.TryParse<LogLevel>(reader.GetString(),true, out var val) ? val : default;
}

public override void Write(Utf8JsonWriter writer, LogLevel value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,9 @@ private static JsonSerializerOptions BuildJsonSerializerOptions()
_jsonOptions.Converters.Add(new TimeOnlyConverter());

#if NET8_0_OR_GREATER
_jsonOptions.Converters.Add(new JsonStringEnumConverter<LogLevel>());
_jsonOptions.Converters.Add(new LogLevelJsonConverter());
#elif NET6_0
_jsonOptions.Converters.Add(new JsonStringEnumConverter());
_jsonOptions.Converters.Add(new LogLevelJsonConverter());
#endif

_jsonOptions.Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
using System.Linq;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;
using Amazon.Lambda.Core;
using Amazon.Lambda.TestUtilities;
using AWS.Lambda.Powertools.Common;
Expand All @@ -42,7 +43,50 @@ public LogFormatterTest()
{
_testHandler = new TestHandlers();
}


[Fact]
public void Serialize_ShouldHandleEnumValues()
{
var consoleOut = Substitute.For<StringWriter>();
SystemWrapper.Instance.SetOut(consoleOut);
var lambdaContext = new TestLambdaContext
{
FunctionName = "funtionName",
FunctionVersion = "version",
InvokedFunctionArn = "function::arn",
AwsRequestId = "requestId",
MemoryLimitInMB = 128
};

var handler = new TestHandlers();
handler.TestEnums("fake", lambdaContext);

consoleOut.Received(1).WriteLine(Arg.Is<string>(i =>
i.Contains("\"message\":5")
));
consoleOut.Received(1).WriteLine(Arg.Is<string>(i =>
i.Contains("\"message\":\"Dog\"")
));

var json = JsonSerializer.Serialize(Pet.Dog, PowertoolsLoggingSerializer.GetSerializerOptions());
Assert.Contains("Dog", json);
}

[JsonConverter(typeof(JsonStringEnumConverter))]
public enum Pet
{
Cat = 1,
Dog = 3,
Lizard = 5
}

public enum Thing
{
One = 1,
Three = 3,
Five = 5
}

[Fact]
public void Log_WhenCustomFormatter_LogsCustomFormat()
{
Expand Down Expand Up @@ -204,7 +248,7 @@ public void Should_Log_CustomFormatter_When_Decorated()
consoleOut.Received(1).WriteLine(
Arg.Is<string>(i =>
i.Contains(
"\"correlation_ids\":{\"aws_request_id\":\"requestId\"},\"lambda_function\":{\"name\":\"funtionName\",\"arn\":\"function::arn\",\"memory_limit_in_mb\":128,\"version\":\"version\",\"cold_start\":true},\"level\":\"Information\""))
"\"correlation_ids\":{\"aws_request_id\":\"requestId\"},\"lambda_function\":{\"name\":\"funtionName\",\"arn\":\"function::arn\",\"memory_limit_in_mb\":128,\"version\":\"version\",\"cold_start\":true},\"level\":\"Information\""))
);
#else
consoleOut.Received(1).WriteLine(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
* permissions and limitations under the License.
*/

using System.Text.Json.Serialization;
using Amazon.Lambda.APIGatewayEvents;
using Amazon.Lambda.ApplicationLoadBalancerEvents;
using Amazon.Lambda.CloudWatchEvents;
Expand Down Expand Up @@ -158,4 +159,26 @@ public void TestLogNoDecorator()
{
Logger.LogInformation("test");
}

[Logging(Service = "test", LoggerOutputCase = LoggerOutputCase.SnakeCase)]
public void TestEnums(string input, ILambdaContext context)
{
Logger.LogInformation(Pet.Dog);
Logger.LogInformation(Thing.Five);
}

public enum Thing
{
One = 1,
Three = 3,
Five = 5
}

[JsonConverter(typeof(JsonStringEnumConverter))]
public enum Pet
{
Cat = 1,
Dog = 3,
Lizard = 5
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ public void SerializerOptions_ShouldHaveCorrectDefaultSettings()
converter => Assert.IsType<DateOnlyConverter>(converter),
converter => Assert.IsType<TimeOnlyConverter>(converter),
#if NET8_0_OR_GREATER
converter => Assert.IsType<JsonStringEnumConverter<LogLevel>>(converter));
converter => Assert.IsType<LogLevelJsonConverter>(converter));
#elif NET6_0
converter => Assert.IsType<JsonStringEnumConverter>(converter));
converter => Assert.IsType<LogLevelJsonConverter>(converter));
#endif

Assert.Equal(JavaScriptEncoder.UnsafeRelaxedJsonEscaping, options.Encoder);
Expand All @@ -90,9 +90,9 @@ public void SerializerOptions_ShouldHaveCorrectDefaultSettings_WhenDynamic()
converter => Assert.IsType<DateOnlyConverter>(converter),
converter => Assert.IsType<TimeOnlyConverter>(converter),
#if NET8_0_OR_GREATER
converter => Assert.IsType<JsonStringEnumConverter<LogLevel>>(converter));
converter => Assert.IsType<LogLevelJsonConverter>(converter));
#elif NET6_0
converter => Assert.IsType<JsonStringEnumConverter>(converter));
converter => Assert.IsType<LogLevelJsonConverter>(converter));
#endif

Assert.Equal(JavaScriptEncoder.UnsafeRelaxedJsonEscaping, options.Encoder);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
using System.Text.Json;
using AWS.Lambda.Powertools.Logging.Serializers;
using Microsoft.Extensions.Logging;
using Xunit;

namespace AWS.Lambda.Powertools.Logging.Tests.Utilities;

public class LogLevelJsonConverterTests
{
private readonly LogLevelJsonConverter _converter;
private readonly JsonSerializerOptions _options;

public LogLevelJsonConverterTests()
{
_converter = new LogLevelJsonConverter();
_options = new JsonSerializerOptions
{
Converters = { _converter }
};
}

[Theory]
[InlineData("Information", LogLevel.Information)]
[InlineData("Error", LogLevel.Error)]
[InlineData("Warning", LogLevel.Warning)]
[InlineData("Debug", LogLevel.Debug)]
[InlineData("Trace", LogLevel.Trace)]
[InlineData("Critical", LogLevel.Critical)]
[InlineData("None", LogLevel.None)]
public void Read_ValidLogLevel_ReturnsCorrectEnum(string input, LogLevel expected)
{
// Arrange
var json = $"\"{input}\"";

// Act
var result = JsonSerializer.Deserialize<LogLevel>(json, _options);

// Assert
Assert.Equal(expected, result);
}

[Theory]
[InlineData("information", LogLevel.Information)]
[InlineData("ERROR", LogLevel.Error)]
[InlineData("Warning", LogLevel.Warning)]
[InlineData("deBUG", LogLevel.Debug)]
public void Read_CaseInsensitive_ReturnsCorrectEnum(string input, LogLevel expected)
{
// Arrange
var json = $"\"{input}\"";

// Act
var result = JsonSerializer.Deserialize<LogLevel>(json, _options);

// Assert
Assert.Equal(expected, result);
}

[Theory]
[InlineData("")]
[InlineData("InvalidLevel")]
[InlineData("NotALevel")]
public void Read_InvalidLogLevel_ReturnsDefault(string input)
{
// Arrange
var json = $"\"{input}\"";

// Act
var result = JsonSerializer.Deserialize<LogLevel>(json, _options);

// Assert
Assert.Equal(default(LogLevel), result);
}

[Fact]
public void Read_NullValue_ReturnsDefault()
{
// Arrange
var json = "null";

// Act
var result = JsonSerializer.Deserialize<LogLevel>(json, _options);

// Assert
Assert.Equal(default(LogLevel), result);
}

[Theory]
[InlineData(LogLevel.Information, "Information")]
[InlineData(LogLevel.Error, "Error")]
[InlineData(LogLevel.Warning, "Warning")]
[InlineData(LogLevel.Debug, "Debug")]
[InlineData(LogLevel.Trace, "Trace")]
[InlineData(LogLevel.Critical, "Critical")]
[InlineData(LogLevel.None, "None")]
public void Write_ValidLogLevel_WritesCorrectString(LogLevel input, string expected)
{
// Act
var result = JsonSerializer.Serialize(input, _options);

// Assert
Assert.Equal($"\"{expected}\"", result);
}

[Fact]
public void Write_DefaultLogLevel_WritesCorrectString()
{
// Arrange
var input = default(LogLevel);

// Act
var result = JsonSerializer.Serialize(input, _options);

// Assert
Assert.Equal($"\"{input}\"", result);
}

[Fact]
public void Converter_CanConvert_LogLevelType()
{
// Act
var canConvert = _converter.CanConvert(typeof(LogLevel));

// Assert
Assert.True(canConvert);
}

[Fact]
public void SerializeAndDeserialize_RoundTrip_MaintainsValue()
{
// Arrange
var originalValue = LogLevel.Information;

// Act
var serialized = JsonSerializer.Serialize(originalValue, _options);
var deserialized = JsonSerializer.Deserialize<LogLevel>(serialized, _options);

// Assert
Assert.Equal(originalValue, deserialized);
}
}
Loading

0 comments on commit 5bc2000

Please sign in to comment.