diff --git a/src/Serilog.Sinks.AzureLogAnalytics.csproj b/src/Serilog.Sinks.AzureLogAnalytics.csproj index 39c39eb..72e7c3c 100644 --- a/src/Serilog.Sinks.AzureLogAnalytics.csproj +++ b/src/Serilog.Sinks.AzureLogAnalytics.csproj @@ -15,10 +15,15 @@ True Serilog.snk netstandard2.0;net8.0 + latest Serilog serilog-sink-nuget.png README.md + + true + false + LICENSE diff --git a/src/Sinks/AzureLogAnalytics/AzureLogAnalyticsSink.cs b/src/Sinks/AzureLogAnalytics/AzureLogAnalyticsSink.cs index 49246f2..70dfbe6 100644 --- a/src/Sinks/AzureLogAnalytics/AzureLogAnalyticsSink.cs +++ b/src/Sinks/AzureLogAnalytics/AzureLogAnalyticsSink.cs @@ -1,23 +1,17 @@ // Copyright 2025 Zethian Inc. -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -using Azure.Core; -using Serilog.Core; -using Serilog.Debugging; -using Serilog.Events; -using Serilog.Sinks.AzureLogAnalytics; -using Serilog.Sinks.Batch; using System; using System.Collections.Generic; using System.Dynamic; @@ -26,11 +20,17 @@ using System.Net.Http.Headers; using System.Text; using System.Text.Json; +using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; -using NamingStrategy = Serilog.Sinks.AzureLogAnalytics.NamingStrategy; -using System.Text.Json.Serialization; +using Azure.Core; +using Serilog.Core; +using Serilog.Debugging; +using Serilog.Events; using Serilog.Formatting; +using Serilog.Sinks.AzureLogAnalytics; +using Serilog.Sinks.Batch; +using NamingStrategy = Serilog.Sinks.AzureLogAnalytics.NamingStrategy; namespace Serilog.Sinks { @@ -40,12 +40,12 @@ internal class AzureLogAnalyticsSink : BatchProvider, ILogEventSink private DateTimeOffset expire_on = DateTimeOffset.MinValue; private readonly string LoggerUriString; private readonly SemaphoreSlim _semaphore; - private readonly JsonSerializerOptions _jsonOptions; + private readonly LogsJsonSerializerContext _logsJsonSerializerContext; private readonly ConfigurationSettings _configurationSettings; private readonly LoggerCredential _loggerCredential; private static readonly HttpClient httpClient = new HttpClient(); - const string scope = "https://monitor.azure.com//.default"; + private const string scope = "https://monitor.azure.com//.default"; internal AzureLogAnalyticsSink(LoggerCredential loggerCredential, ConfigurationSettings settings, ITextFormatter formatter) : base(settings.BatchSize, settings.BufferSize) @@ -56,25 +56,29 @@ internal AzureLogAnalyticsSink(LoggerCredential loggerCredential, ConfigurationS _configurationSettings = settings; + JsonSerializerOptions jsonOptions; switch (settings.PropertyNamingStrategy) { case NamingStrategy.Default: - _jsonOptions = new JsonSerializerOptions(); + jsonOptions = new JsonSerializerOptions(); break; + case NamingStrategy.CamelCase: - _jsonOptions = new JsonSerializerOptions() + jsonOptions = new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, }; break; + default: throw new ArgumentOutOfRangeException(); } - _jsonOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles; - _jsonOptions.WriteIndented = false; - _jsonOptions.Converters.Add(new LoggerJsonConverter(formatter)); + jsonOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles; + jsonOptions.WriteIndented = false; + jsonOptions.Converters.Add(new LoggerJsonConverter(formatter)); + _logsJsonSerializerContext = new LogsJsonSerializerContext(jsonOptions); if (_configurationSettings.MaxDepth > 0) { _configurationSettings.MaxDepth = _configurationSettings.MaxDepth; @@ -90,15 +94,13 @@ public void Emit(LogEvent logEvent) PushEvent(logEvent); } - #endregion - + #endregion ILogEvent implementation protected override async Task WriteLogEventAsync(ICollection logEventsBatch) { if ((logEventsBatch == null) || (logEventsBatch.Count == 0)) return true; - var jsonStringCollection = new List(); var logs = logEventsBatch.Select(s => @@ -112,6 +114,7 @@ protected override async Task WriteLogEventAsync(ICollection log return await PostDataAsync(logs); } + private async Task<(string, DateTimeOffset)> GetAuthToken() { if (_loggerCredential.TokenCredential != null) @@ -177,7 +180,7 @@ private async Task PostDataAsync(IEnumerable> httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", $"{token}"); } - var jsonString = JsonSerializer.Serialize(logs, _jsonOptions); + var jsonString = JsonSerializer.Serialize(logs, typeof(IEnumerable>), _logsJsonSerializerContext); var jsonContent = new StringContent(jsonString, Encoding.UTF8, "application/json"); var response = httpClient.PostAsync(LoggerUriString, jsonContent).GetAwaiter().GetResult(); @@ -200,4 +203,4 @@ private async Task PostDataAsync(IEnumerable> } } } -} +} \ No newline at end of file diff --git a/src/Sinks/AzureLogAnalytics/LogsJsonSerializerContext.cs b/src/Sinks/AzureLogAnalytics/LogsJsonSerializerContext.cs new file mode 100644 index 0000000..d691db8 --- /dev/null +++ b/src/Sinks/AzureLogAnalytics/LogsJsonSerializerContext.cs @@ -0,0 +1,14 @@ +namespace Serilog.Sinks.AzureLogAnalytics +{ + using System; + using System.Collections.Generic; + using System.Text.Json.Serialization; + using Serilog.Events; + + [JsonSerializable(typeof(DateTime))] + [JsonSerializable(typeof(IEnumerable>))] + [JsonSerializable(typeof(LogEvent))] + internal partial class LogsJsonSerializerContext : JsonSerializerContext + { + } +} \ No newline at end of file