diff --git a/src/libraries/Microsoft.Extensions.Logging.EventSource/src/LoggingEventSource.cs b/src/libraries/Microsoft.Extensions.Logging.EventSource/src/LoggingEventSource.cs index 56982fcc479b16..886919cd40ef51 100644 --- a/src/libraries/Microsoft.Extensions.Logging.EventSource/src/LoggingEventSource.cs +++ b/src/libraries/Microsoft.Extensions.Logging.EventSource/src/LoggingEventSource.cs @@ -198,6 +198,7 @@ internal unsafe void FormattedMessage( /// [Event(2, Keywords = Keywords.Message, Level = EventLevel.LogAlways, Version = 2)] [DynamicDependency(DynamicallyAccessedMemberTypes.PublicProperties, typeof(KeyValuePair))] + [DynamicDependency(DynamicallyAccessedMemberTypes.PublicProperties, typeof(ExceptionInfo))] [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = WriteEventDynamicDependencySuppressionJustification)] internal void Message( diff --git a/src/libraries/Microsoft.Extensions.Logging.EventSource/tests/EventSourceLoggerTest.cs b/src/libraries/Microsoft.Extensions.Logging.EventSource/tests/EventSourceLoggerTest.cs index 0991b45ea6b2bf..99230e59ade0cc 100644 --- a/src/libraries/Microsoft.Extensions.Logging.EventSource/tests/EventSourceLoggerTest.cs +++ b/src/libraries/Microsoft.Extensions.Logging.EventSource/tests/EventSourceLoggerTest.cs @@ -163,7 +163,6 @@ public void FilterSpecs_IncreaseLoggingLevelForOneCategory_DisablesExistingRules } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/73438", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] public void Logs_AsExpected_WithDefaults() { using (var testListener = new TestEventListener()) @@ -201,7 +200,6 @@ public void Logs_AsExpected_WithDefaults() [InlineData(true, true, false)] [InlineData(true, false, true)] [InlineData(false, true, true)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/73438", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] public void Logs_TracingDetailsAsExpected_WithDefaults(bool hasTrace, bool useW3CFormatId, bool sampled) { using (var testListener = new TestEventListener()) @@ -258,7 +256,6 @@ public void Logs_TracingDetailsAsExpected_WithDefaults(bool hasTrace, bool useW3 } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/73438", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] public void Logs_AsExpected_WithDefaults_EnabledEarly() { using (var testListener = new TestEventListener()) @@ -365,7 +362,6 @@ public void Logs_OnlyJson_IfKeywordSet() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/73438", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] public void Logs_OnlyMessage_IfKeywordSet() { using (var testListener = new TestEventListener()) @@ -904,7 +900,7 @@ protected override void OnEventWritten(EventWrittenEventArgs eventWrittenArgs) } else { - if (eventWrittenArgs.Payload[i] == null || IsPrimitive(eventWrittenArgs.Payload[i].GetType())) + if (eventWrittenArgs.Payload[i] is null || IsPrimitive(eventWrittenArgs.Payload[i].GetType())) { writer.WriteValue(eventWrittenArgs.Payload[i]); } @@ -913,22 +909,11 @@ protected override void OnEventWritten(EventWrittenEventArgs eventWrittenArgs) var dictProperty = (IDictionary)eventWrittenArgs.Payload[i]; // EventPayload claims to support IDictionary, but you cannot get a KeyValuePair enumerator out of it // So we need to serialize manually - writer.WriteStartObject(); - - for (int j = 0; j < dictProperty.Keys.Count; j++) - { - writer.WritePropertyName(dictProperty.Keys.ElementAt(j)); - writer.WriteValue(dictProperty.Values.ElementAt(j)); - } - - writer.WriteEndObject(); + WriteDictionary(writer, dictProperty); } else { -#pragma warning disable IL2026 // https://github.com/dotnet/runtime/issues/126862 - string serializedComplexValue = JsonConvert.SerializeObject(eventWrittenArgs.Payload[i]); -#pragma warning restore IL2026 - writer.WriteRawValue(serializedComplexValue); + WriteComplexValue(writer, eventWrittenArgs.Payload[i]); } } } @@ -937,9 +922,95 @@ protected override void OnEventWritten(EventWrittenEventArgs eventWrittenArgs) Events.Add(sw.ToString()); } - private bool IsPrimitive(Type type) + private static void WriteComplexValue(JsonTextWriter writer, object value) + { + if (value is IDictionary dictionary) + { + WriteDictionary(writer, dictionary); + } + else if (value is IEnumerable> keyValuePairs) + { + writer.WriteStartArray(); + + foreach (KeyValuePair keyValuePair in keyValuePairs) + { + writer.WriteStartObject(); + writer.WritePropertyName(nameof(KeyValuePair.Key)); + writer.WriteValue(keyValuePair.Key); + writer.WritePropertyName(nameof(KeyValuePair.Value)); + writer.WriteValue(keyValuePair.Value); + writer.WriteEndObject(); + } + + writer.WriteEndArray(); + } + else if (value is object[] values) + { + writer.WriteStartArray(); + + foreach (object element in values) + { + WriteValue(writer, element); + } + + writer.WriteEndArray(); + } + else + { + throw new InvalidOperationException($"Unexpected complex payload type: {value.GetType()}"); + } + } + + private static void WriteDictionary(JsonTextWriter writer, IDictionary dictProperty) + { + writer.WriteStartObject(); + + using IEnumerator keys = dictProperty.Keys.GetEnumerator(); + using IEnumerator values = dictProperty.Values.GetEnumerator(); + + while (keys.MoveNext()) + { + bool hasValue = values.MoveNext(); + Debug.Assert(hasValue); + + writer.WritePropertyName(keys.Current); + WriteValue(writer, values.Current); + } + + writer.WriteEndObject(); + } + + private static void WriteValue(JsonTextWriter writer, object value) + { + if (value is null) + { + writer.WriteNull(); + } + else + { + Type valueType = value.GetType(); + + if (IsPrimitive(valueType)) + { + if (valueType.IsEnum) + { + writer.WriteValue(Convert.ToInt32(value, CultureInfo.InvariantCulture)); + } + else + { + writer.WriteValue(value); + } + } + else + { + WriteComplexValue(writer, value); + } + } + } + + private static bool IsPrimitive(Type type) { - return type == typeof(string) || type == typeof(int) || type == typeof(bool) || type == typeof(double); + return type.IsPrimitive || type.IsEnum || type == typeof(string) || type == typeof(decimal) || type == typeof(DateTime) || type == typeof(Guid); } private bool IsJsonProperty(int eventId, int propertyOrdinal, string propertyName) diff --git a/src/libraries/Microsoft.Extensions.Logging.EventSource/tests/Microsoft.Extensions.Logging.EventSource.Tests.csproj b/src/libraries/Microsoft.Extensions.Logging.EventSource/tests/Microsoft.Extensions.Logging.EventSource.Tests.csproj index a7586b20c77017..1f72fd348ffbe1 100644 --- a/src/libraries/Microsoft.Extensions.Logging.EventSource/tests/Microsoft.Extensions.Logging.EventSource.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Logging.EventSource/tests/Microsoft.Extensions.Logging.EventSource.Tests.csproj @@ -5,8 +5,6 @@ true true true - - false