diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 4558d44b..c36856df 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -92,3 +92,31 @@ jobs:
with:
name: test-results-linux
path: build/output/junit-*.xml
+
+ aot-validate:
+ runs-on: ${{ matrix.os.runner }}
+ strategy:
+ fail-fast: false
+ matrix:
+ os:
+ - runner: ubuntu-latest
+ folder: linux-x64
+ binary: ecs-aot-smoketest
+ - runner: macos-latest
+ folder: osx-arm64
+ binary: ecs-aot-smoketest
+ - runner: windows-latest
+ folder: win-x64
+ binary: ecs-aot-smoketest.exe
+ steps:
+ - uses: actions/checkout@v4
+
+ - uses: actions/setup-dotnet@v4
+ with:
+ global-json-file: ./global.json
+
+ - name: Publish AOT
+ run: dotnet publish examples/ecs-aot-smoketest
+
+ - name: Invoke AOT
+ run: ./examples/ecs-aot-smoketest/bin/Release/net9.0/${{ matrix.os.folder }}/publish/${{ matrix.os.binary }}
diff --git a/dotnet-tools.json b/dotnet-tools.json
index 9c1a3501..c20584c7 100644
--- a/dotnet-tools.json
+++ b/dotnet-tools.json
@@ -24,7 +24,7 @@
"rollForward": false
},
"nupkg-validator": {
- "version": "0.6.0",
+ "version": "0.7.0",
"commands": [
"nupkg-validator"
],
diff --git a/ecs-dotnet.sln b/ecs-dotnet.sln
index 5e132dfc..56f1d65f 100644
--- a/ecs-dotnet.sln
+++ b/ecs-dotnet.sln
@@ -141,6 +141,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elastic.Serilog.Sinks.Tests
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elastic.Serilog.Enrichers.Web", "src\Elastic.Serilog.Enrichers.Web\Elastic.Serilog.Enrichers.Web.csproj", "{B6DCC4C4-1287-41BE-A19D-8F311C6E39F7}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ecs-aot-smoketest", "examples\ecs-aot-smoketest\ecs-aot-smoketest.csproj", "{46706BAE-BBCD-4DD9-ADBD-AC099C770854}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -311,6 +313,10 @@ Global
{B6DCC4C4-1287-41BE-A19D-8F311C6E39F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B6DCC4C4-1287-41BE-A19D-8F311C6E39F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B6DCC4C4-1287-41BE-A19D-8F311C6E39F7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {46706BAE-BBCD-4DD9-ADBD-AC099C770854}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {46706BAE-BBCD-4DD9-ADBD-AC099C770854}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {46706BAE-BBCD-4DD9-ADBD-AC099C770854}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {46706BAE-BBCD-4DD9-ADBD-AC099C770854}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -358,6 +364,7 @@ Global
{5EDF109F-9DFF-4957-8864-BA2702FB78F6} = {7610B796-BB3E-4CB2-8296-79BBFF6D23FC}
{933FD923-A2DC-49E3-B21E-8BA888DB5924} = {3582B07D-C2B0-49CC-B676-EAF806EB010E}
{B6DCC4C4-1287-41BE-A19D-8F311C6E39F7} = {7610B796-BB3E-4CB2-8296-79BBFF6D23FC}
+ {46706BAE-BBCD-4DD9-ADBD-AC099C770854} = {05075402-8669-45BD-913A-BD40A29BBEAB}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7F60C4BB-6216-4E50-B1E4-9C38EB484843}
diff --git a/examples/Elastic.Extensions.Logging.Console.Example/Program.cs b/examples/Elastic.Extensions.Logging.Console.Example/Program.cs
index 33f4c6eb..a973afcb 100644
--- a/examples/Elastic.Extensions.Logging.Console.Example/Program.cs
+++ b/examples/Elastic.Extensions.Logging.Console.Example/Program.cs
@@ -6,6 +6,7 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
using Host = Microsoft.Extensions.Hosting.Host;
await Host.CreateDefaultBuilder(args)
@@ -24,4 +25,3 @@ await Host.CreateDefaultBuilder(args)
})
.Build()
.RunAsync();
-
diff --git a/examples/Elastic.Serilog.Sinks.Example/Elastic.Serilog.Sinks.Example.csproj b/examples/Elastic.Serilog.Sinks.Example/Elastic.Serilog.Sinks.Example.csproj
index 60cb07d0..1e7b673f 100644
--- a/examples/Elastic.Serilog.Sinks.Example/Elastic.Serilog.Sinks.Example.csproj
+++ b/examples/Elastic.Serilog.Sinks.Example/Elastic.Serilog.Sinks.Example.csproj
@@ -9,7 +9,7 @@
-
+
diff --git a/examples/aspnetcore-with-serilog/AspnetCoreExample.csproj b/examples/aspnetcore-with-serilog/AspnetCoreExample.csproj
index d4baf31d..9a89478b 100644
--- a/examples/aspnetcore-with-serilog/AspnetCoreExample.csproj
+++ b/examples/aspnetcore-with-serilog/AspnetCoreExample.csproj
@@ -7,7 +7,7 @@
-
+
diff --git a/examples/ecs-aot-smoketest/ExtensionsLogger.cs b/examples/ecs-aot-smoketest/ExtensionsLogger.cs
new file mode 100644
index 00000000..936bab11
--- /dev/null
+++ b/examples/ecs-aot-smoketest/ExtensionsLogger.cs
@@ -0,0 +1,50 @@
+using Elastic.Channels.Diagnostics;
+using Elastic.Extensions.Logging;
+using Elastic.Extensions.Logging.Options;
+using Elastic.Transport;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+
+public class ExtensionsLogger(ITransport transport)
+{
+ public IDisposable CreateExtensionsLogger(
+ out ILogger logger,
+ out ElasticsearchLoggerProvider provider,
+ out string @namespace,
+ out WaitHandle waitHandle,
+ out IChannelDiagnosticsListener listener
+ )
+ {
+ @namespace = Guid.NewGuid().ToString("N").ToLowerInvariant().Substring(0, 6);
+ var slim = new CountdownEvent(1);
+ waitHandle = slim.WaitHandle;
+ var s = @namespace;
+ var options = new ConfigureOptions(o =>
+ {
+ o.Transport = transport;
+ o.DataStream = new DataStreamNameOptions { Type = "x", Namespace = s, DataSet = "dotnet" };
+ var nodes = transport.Configuration.NodePool.Nodes.Select(n => n.Uri).ToArray();
+ o.ShipTo = new ShipToOptions { NodeUris = nodes, NodePoolType = NodePoolType.Static };
+ });
+
+ var channelSetup = new IChannelSetup[]
+ {
+ new ChannelSetup(c =>
+ {
+ c.BufferOptions.WaitHandle = slim;
+ c.BufferOptions.OutboundBufferMaxSize = 1;
+ c.BufferOptions.OutboundBufferMaxLifetime = TimeSpan.FromSeconds(1);
+ c.BufferOptions.ExportMaxRetries = 0;
+ c.BufferOptions.ExportMaxConcurrency = 1;
+ })
+ };
+
+ var optionsFactory = new OptionsFactory([options], []);
+ var optionsMonitor = new OptionsMonitor(optionsFactory, [], new OptionsCache());
+ provider = new ElasticsearchLoggerProvider(optionsMonitor, channelSetup);
+ var loggerFactory = new LoggerFactory( [provider], new LoggerFilterOptions { MinLevel = LogLevel.Information });
+ logger = loggerFactory.CreateLogger();
+ listener = provider.DiagnosticsListener!;
+ return loggerFactory;
+ }
+}
diff --git a/examples/ecs-aot-smoketest/NLogExporter.cs b/examples/ecs-aot-smoketest/NLogExporter.cs
new file mode 100644
index 00000000..4bb9da1e
--- /dev/null
+++ b/examples/ecs-aot-smoketest/NLogExporter.cs
@@ -0,0 +1,41 @@
+using Elastic.Channels.Diagnostics;
+using Elastic.Transport;
+using NLog.Targets;
+
+public class NLogExporter(ITransport transport)
+{
+ public IDisposable CreateNLogLogger(
+ out NLog.Logger logger,
+ out NLog.LogFactory logFactory,
+ out string @namespace,
+ out WaitHandle waitHandle,
+ out IChannelDiagnosticsListener listener
+ )
+ {
+ var slim = new CountdownEvent(1);
+ waitHandle = slim.WaitHandle;
+ @namespace = Guid.NewGuid().ToString("N").ToLowerInvariant().Substring(0, 6);
+
+ logFactory = new NLog.LogFactory();
+ var logConfig = new NLog.Config.LoggingConfiguration(logFactory);
+ var logTarget = new ElasticsearchTarget { Name = "elastic" };
+ logTarget.RequestInvoker = transport.Configuration.RequestInvoker;
+ logTarget.DataStreamNamespace = @namespace;
+ logTarget.OutboundBufferMaxSize = 1;
+ logTarget.OutboundBufferMaxLifetimeSeconds = 1;
+ logTarget.ExportMaxRetries = 0;
+ logTarget.ExportMaxConcurrency = 1;
+ logTarget.ConfigureChannel = (cfg) => cfg.BufferOptions.WaitHandle = slim;
+
+ logTarget.DataStreamType = "x";
+ logTarget.DataStreamSet = "dotnet";
+ var nodesUris = string.Join(",", transport.Configuration.NodePool.Nodes.Select(n => n.Uri.ToString()).ToArray());
+ logTarget.NodeUris = nodesUris;
+ logTarget.NodePoolType = ElasticPoolType.Static;
+ logConfig.AddRuleForAllLevels(logTarget);
+ logFactory.Configuration = logConfig;
+ listener = logTarget.DiagnosticsListener!;
+ logger = logFactory.GetLogger("TestLogger");
+ return logFactory;
+ }
+}
diff --git a/examples/ecs-aot-smoketest/Program.cs b/examples/ecs-aot-smoketest/Program.cs
new file mode 100644
index 00000000..9fe24806
--- /dev/null
+++ b/examples/ecs-aot-smoketest/Program.cs
@@ -0,0 +1,85 @@
+// See https://aka.ms/new-console-template for more information
+
+using Elastic.CommonSchema;
+using Elastic.Transport;
+using Microsoft.Extensions.Logging;
+using Log = Elastic.CommonSchema.Log;
+using LogLevel = NLog.LogLevel;
+
+Console.WriteLine("Hello, World!");
+
+var serialized = @$"{{}}";
+var deserialized = EcsDocument.Deserialize(serialized);
+if (deserialized == null) throw new Exception("deserialized is null");
+
+serialized = @$"{{ ""agent"": {{ ""unknown"": ""value"" }} }}";
+deserialized = EcsDocument.Deserialize(serialized);
+if (deserialized == null) throw new Exception("deserialized is null");
+if (deserialized.Agent == null) throw new Exception("deserialized agent is null");
+
+var d = new EcsDocument { Agent = new Agent { Name = "some-agent" }, Log = new Log { Level = "debug" } };
+
+serialized = d.Serialize();
+if (string.IsNullOrEmpty(serialized)) throw new Exception("serialized is null");
+Console.WriteLine(serialized);
+
+var invoker = new InMemoryRequestInvoker();
+var pool = new StaticNodePool([new Node(new Uri("http://localhost:9200"))]);
+var configuration = new TransportConfiguration(pool, invoker);
+var transport = new DistributedTransport(configuration);
+
+var extension = new ExtensionsLogger(transport);
+LogInMemoryExtensionsLogger(extension);
+
+var nlog = new NLogExporter(transport);
+LogInMemoryNLog(nlog);
+
+/*
+var serilog = new SerilogExporter(transport);
+LogInMemorySerilog(serilog);
+
+void LogInMemorySerilog(SerilogExporter serilogExporter)
+{
+ using var logger = serilogExporter.CreateSerilogLogger(out var waitHandle, out var listener);
+ logger.Information("an error occurred {Status}", "failure");
+
+ if (!waitHandle.WaitOne(TimeSpan.FromSeconds(10)))
+ throw new Exception($"No flush occurred in 10 seconds: {listener}", listener.ObservedException);
+
+ if (!listener.PublishSuccess)
+ throw new Exception("Serilog Logger did not export correctly");
+ if (listener.ObservedException != null)
+ throw new Exception("Serilog Logger received exception", listener.ObservedException);
+ Console.WriteLine("Serilog Logger export success");
+}
+*/
+
+void LogInMemoryExtensionsLogger(ExtensionsLogger extensionsLogger)
+{
+ using var _ = extensionsLogger.CreateExtensionsLogger(out var logger, out var provider, out var @namespace, out var waitHandle, out var listener);
+ logger.LogError("an error occurred {Status}", "failure");
+
+ if (!waitHandle.WaitOne(TimeSpan.FromSeconds(10)))
+ throw new Exception($"No flush occurred in 10 seconds: {listener}", listener.ObservedException);
+
+ if (!listener.PublishSuccess)
+ throw new Exception("Extensions Logger did not export correctly");
+ if (listener.ObservedException != null)
+ throw new Exception("Extensions Logger received exception", listener.ObservedException);
+ Console.WriteLine("Extensions Logger export success");
+}
+
+void LogInMemoryNLog(NLogExporter serilogExporter)
+{
+ using var _ = serilogExporter.CreateNLogLogger(out var logger, out var _, out var _, out var waitHandle, out var listener);
+ logger.Log(LogLevel.Error, "an error occurred {Status}", "failure");
+
+ if (!waitHandle.WaitOne(TimeSpan.FromSeconds(10)))
+ throw new Exception($"No flush occurred in 10 seconds: {listener}", listener.ObservedException);
+
+ if (!listener.PublishSuccess)
+ throw new Exception("NLog did not export correctly");
+ if (listener.ObservedException != null)
+ throw new Exception("NLog export received exception", listener.ObservedException);
+ Console.WriteLine("NLog export success");
+}
diff --git a/examples/ecs-aot-smoketest/SerilogExporter.cs b/examples/ecs-aot-smoketest/SerilogExporter.cs
new file mode 100644
index 00000000..6731b8a1
--- /dev/null
+++ b/examples/ecs-aot-smoketest/SerilogExporter.cs
@@ -0,0 +1,39 @@
+using Elastic.Channels;
+using Elastic.Channels.Diagnostics;
+using Elastic.Ingest.Elasticsearch.DataStreams;
+using Elastic.Serilog.Sinks;
+using Elastic.Transport;
+using Serilog;
+using Serilog.Core;
+
+public class SerilogExporter(ITransport transport)
+{
+ public Logger CreateSerilogLogger(out WaitHandle waitHandle, out IChannelDiagnosticsListener listener)
+ {
+ var countdown = new CountdownEvent(1);
+ waitHandle = countdown.WaitHandle;
+
+ IChannelDiagnosticsListener? listen = null;
+ var options = new ElasticsearchSinkOptions(transport)
+ {
+ DataStream = new DataStreamName("logs", "serilog", "tests"),
+ ConfigureChannel = c =>
+ {
+ c.BufferOptions = new BufferOptions
+ {
+ WaitHandle = countdown,
+ OutboundBufferMaxSize = 1
+ };
+ },
+ ChannelDiagnosticsCallback = l => listen = l
+ };
+ listener = listen ?? throw new Exception("No listener");
+
+ var loggerConfig = new LoggerConfiguration()
+ .MinimumLevel.Information()
+ .WriteTo.Elasticsearch(options);
+
+ var logger = loggerConfig.CreateLogger();
+ return logger;
+ }
+}
diff --git a/examples/ecs-aot-smoketest/ecs-aot-smoketest.csproj b/examples/ecs-aot-smoketest/ecs-aot-smoketest.csproj
new file mode 100644
index 00000000..07106cb8
--- /dev/null
+++ b/examples/ecs-aot-smoketest/ecs-aot-smoketest.csproj
@@ -0,0 +1,25 @@
+
+
+
+ Exe
+ net9.0
+ ecs_aot_smoketest
+ enable
+ enable
+ true
+ false
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index 7f8b648d..56b95fa7 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -15,7 +15,21 @@
true
-
+
+
+ true
+ false
+
+
+
+ true
+
+
+
+
+
+
diff --git a/src/Elastic.Apm.NLog/ApmServiceNameLayoutRenderer.cs b/src/Elastic.Apm.NLog/ApmServiceNameLayoutRenderer.cs
index fe562842..ef8c0107 100644
--- a/src/Elastic.Apm.NLog/ApmServiceNameLayoutRenderer.cs
+++ b/src/Elastic.Apm.NLog/ApmServiceNameLayoutRenderer.cs
@@ -13,7 +13,7 @@ namespace Elastic.Apm.NLog;
/// Provides ElasticApmServiceName as special logging variable to render the current Elastic APM Service Name
///
[LayoutRenderer(Name)]
-[ThreadSafe, ThreadAgnostic]
+[ThreadAgnostic]
public class ApmServiceNameLayoutRenderer : LayoutRenderer
{
///
diff --git a/src/Elastic.Apm.NLog/ApmServiceNodeNameLayoutRenderer.cs b/src/Elastic.Apm.NLog/ApmServiceNodeNameLayoutRenderer.cs
index 95ca0669..de2c9a0a 100644
--- a/src/Elastic.Apm.NLog/ApmServiceNodeNameLayoutRenderer.cs
+++ b/src/Elastic.Apm.NLog/ApmServiceNodeNameLayoutRenderer.cs
@@ -9,7 +9,7 @@ namespace Elastic.Apm.NLog;
/// Provides ElasticApmServiceNodeName as special logging variable to render the current Elastic APM Service Node Name
///
[LayoutRenderer(Name)]
-[ThreadSafe, ThreadAgnostic]
+[ThreadAgnostic]
public class ApmServiceNodeNameLayoutRenderer : LayoutRenderer
{
///
diff --git a/src/Elastic.Apm.NLog/ApmServiceVersionLayoutRenderer.cs b/src/Elastic.Apm.NLog/ApmServiceVersionLayoutRenderer.cs
index a2184b74..5f32ab69 100644
--- a/src/Elastic.Apm.NLog/ApmServiceVersionLayoutRenderer.cs
+++ b/src/Elastic.Apm.NLog/ApmServiceVersionLayoutRenderer.cs
@@ -9,7 +9,7 @@ namespace Elastic.Apm.NLog;
/// Provides ElasticApmServiceVersion as special logging variable to render the current Elastic APM Service Version
///
[LayoutRenderer(Name)]
-[ThreadSafe, ThreadAgnostic]
+[ThreadAgnostic]
public class ApmServiceVersionLayoutRenderer : LayoutRenderer
{
///
diff --git a/src/Elastic.Apm.NLog/ApmSpanIdLayoutRenderer.cs b/src/Elastic.Apm.NLog/ApmSpanIdLayoutRenderer.cs
index 9126d2d0..e2277332 100644
--- a/src/Elastic.Apm.NLog/ApmSpanIdLayoutRenderer.cs
+++ b/src/Elastic.Apm.NLog/ApmSpanIdLayoutRenderer.cs
@@ -9,7 +9,6 @@ namespace Elastic.Apm.NLog;
/// Provides ElasticApmSpanId as special logging variable to render the current Elastic APM Span Id
///
[LayoutRenderer(Name)]
-[ThreadSafe]
public class ApmSpanIdLayoutRenderer : LayoutRenderer
{
///
diff --git a/src/Elastic.Apm.NLog/ApmTraceIdLayoutRenderer.cs b/src/Elastic.Apm.NLog/ApmTraceIdLayoutRenderer.cs
index db4e608d..ed70fffd 100644
--- a/src/Elastic.Apm.NLog/ApmTraceIdLayoutRenderer.cs
+++ b/src/Elastic.Apm.NLog/ApmTraceIdLayoutRenderer.cs
@@ -13,7 +13,6 @@ namespace Elastic.Apm.NLog;
/// Provides ElasticApmTraceId as special logging variable to render the current Elastic APM Trace Id
///
[LayoutRenderer(Name)]
-[ThreadSafe]
public class ApmTraceIdLayoutRenderer : LayoutRenderer
{
///
diff --git a/src/Elastic.Apm.NLog/ApmTransactionIdLayoutRenderer.cs b/src/Elastic.Apm.NLog/ApmTransactionIdLayoutRenderer.cs
index 35a3ffeb..80074a23 100644
--- a/src/Elastic.Apm.NLog/ApmTransactionIdLayoutRenderer.cs
+++ b/src/Elastic.Apm.NLog/ApmTransactionIdLayoutRenderer.cs
@@ -13,7 +13,6 @@ namespace Elastic.Apm.NLog;
/// Provides ElasticApmTransactionId as special logging variable to render the current Elastic APM Transaction Id
///
[LayoutRenderer(Name)]
-[ThreadSafe]
public class ApmTransactionIdLayoutRenderer : LayoutRenderer
{
///
diff --git a/src/Elastic.Apm.NLog/Elastic.Apm.NLog.csproj b/src/Elastic.Apm.NLog/Elastic.Apm.NLog.csproj
index 4d581868..2a82c23a 100644
--- a/src/Elastic.Apm.NLog/Elastic.Apm.NLog.csproj
+++ b/src/Elastic.Apm.NLog/Elastic.Apm.NLog.csproj
@@ -13,7 +13,7 @@
Feel free to open an issue on our repos to discuss if you feel you need to target
a lower NLog version
-->
-
+
diff --git a/src/Elastic.Apm.SerilogEnricher/Elastic.Apm.SerilogEnricher.csproj b/src/Elastic.Apm.SerilogEnricher/Elastic.Apm.SerilogEnricher.csproj
index 7f45db7c..2f8b2074 100644
--- a/src/Elastic.Apm.SerilogEnricher/Elastic.Apm.SerilogEnricher.csproj
+++ b/src/Elastic.Apm.SerilogEnricher/Elastic.Apm.SerilogEnricher.csproj
@@ -6,7 +6,7 @@
True
-
+
diff --git a/src/Elastic.CommonSchema.NLog/EcsLayout.cs b/src/Elastic.CommonSchema.NLog/EcsLayout.cs
index 586f17d6..4713368f 100644
--- a/src/Elastic.CommonSchema.NLog/EcsLayout.cs
+++ b/src/Elastic.CommonSchema.NLog/EcsLayout.cs
@@ -18,7 +18,6 @@ namespace Elastic.CommonSchema.NLog
{
/// An NLOG layout implementation that renders logs as ECS json
[Layout(Name)]
- [ThreadSafe]
[ThreadAgnostic]
public partial class EcsLayout : Layout
{
@@ -50,7 +49,6 @@ public EcsLayout()
ProcessThreadId = "${threadid}";
HostName = "${hostname}"; // NLog 4.6
- HostIp = "${local-ip:cachedSeconds=60}"; // NLog 4.6.8
ServerUser = "${environment-user}"; // NLog 4.6.4
@@ -94,9 +92,6 @@ protected override void InitializeLayout()
UrlPort = "${aspnet-request-url:IncludeScheme=false:IncludeHost=false:IncludePath=false:IncludePort=true}";
UrlQuery = "${aspnet-request-url:IncludeScheme=false:IncludeHost=false:IncludePath=false:IncludeQueryString=true}";
UrlUserName = "${aspnet-user-identity}";
-
- if (!NLogApmLoaded.Value)
- ApmTraceId = "${scopeproperty:item=RequestId:whenEmpty=${aspnet-TraceIdentifier}}";
}
base.InitializeLayout();
@@ -383,15 +378,14 @@ private MetadataDictionary GetMetadata(LogEventInfo e)
if (IncludeScopeProperties)
{
- foreach (var key in MappedDiagnosticsLogicalContext.GetNames())
+ foreach (var scopeProperty in ScopeContext.GetAllProperties())
{
- if (string.IsNullOrEmpty(key) || ExcludeProperties.Contains(key))
+ if (string.IsNullOrEmpty(scopeProperty.Key) || ExcludeProperties.Contains(scopeProperty.Key))
continue;
- var propertyValue = MappedDiagnosticsLogicalContext.GetObject(key);
- if (!TryPopulateWhenSafe(metadata, key, propertyValue))
+ if (!TryPopulateWhenSafe(metadata, scopeProperty.Key, scopeProperty.Value))
{
- Populate(metadata, key, propertyValue.ToString());
+ Populate(metadata, scopeProperty.Key, scopeProperty.Value.ToString());
}
}
}
diff --git a/src/Elastic.CommonSchema.NLog/Elastic.CommonSchema.NLog.csproj b/src/Elastic.CommonSchema.NLog/Elastic.CommonSchema.NLog.csproj
index 05249fe6..70af4aae 100644
--- a/src/Elastic.CommonSchema.NLog/Elastic.CommonSchema.NLog.csproj
+++ b/src/Elastic.CommonSchema.NLog/Elastic.CommonSchema.NLog.csproj
@@ -11,6 +11,6 @@
-
+
diff --git a/src/Elastic.CommonSchema.Serilog/Elastic.CommonSchema.Serilog.csproj b/src/Elastic.CommonSchema.Serilog/Elastic.CommonSchema.Serilog.csproj
index 121f1edd..bf594823 100644
--- a/src/Elastic.CommonSchema.Serilog/Elastic.CommonSchema.Serilog.csproj
+++ b/src/Elastic.CommonSchema.Serilog/Elastic.CommonSchema.Serilog.csproj
@@ -13,9 +13,6 @@
-
-
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
-
\ No newline at end of file
+
diff --git a/src/Elastic.CommonSchema/EcsDocument.DefaultService.cs b/src/Elastic.CommonSchema/EcsDocument.DefaultService.cs
index 36dfaa2a..7a64d35c 100644
--- a/src/Elastic.CommonSchema/EcsDocument.DefaultService.cs
+++ b/src/Elastic.CommonSchema/EcsDocument.DefaultService.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
@@ -67,6 +68,8 @@ private static void UpdateServiceWithEnvironmentConfig(Service service, IDiction
? entryAssembly.GetCustomAttribute()?.InformationalVersion
: null;
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "We always provide a static JsonTypeInfoResolver")]
+ [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "We always provide a static JsonTypeInfoResolver")]
private static Assembly? GetEntryAssembly()
{
var entryAssembly = Assembly.GetEntryAssembly();
diff --git a/src/Elastic.CommonSchema/EcsDocument.Serialization.cs b/src/Elastic.CommonSchema/EcsDocument.Serialization.cs
index a61e4683..52b2bcb0 100644
--- a/src/Elastic.CommonSchema/EcsDocument.Serialization.cs
+++ b/src/Elastic.CommonSchema/EcsDocument.Serialization.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information
using System;
+using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Text;
using System.Text.Encodings.Web;
@@ -68,10 +69,14 @@ protected internal virtual void WriteAdditionalProperties(Action
EcsSerializerFactory.DeserializeAsync(stream, ctx);
/// Serialize this instance to string
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "We always provide a static JsonTypeInfoResolver")]
+ [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "We always provide a static JsonTypeInfoResolver")]
public string Serialize() => JsonSerializer.Serialize(this, GetType(), SerializerOptions);
// ReSharper disable once UnusedMember.Global
/// Serialize this instance to utf8 bytes
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "We always provide a static JsonTypeInfoResolver")]
+ [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "We always provide a static JsonTypeInfoResolver")]
public byte[] SerializeToUtf8Bytes() => JsonSerializer.SerializeToUtf8Bytes(this, GetType(), SerializerOptions);
private static readonly ReusableUtf8JsonWriter ReusableJsonWriter = new();
@@ -87,6 +92,8 @@ public StringBuilder Serialize(StringBuilder stringBuilder)
// ReSharper disable once UnusedMember.Global
/// Serialize this instance to a Stream
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "We always provide a static JsonTypeInfoResolver")]
+ [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "We always provide a static JsonTypeInfoResolver")]
public void Serialize(Stream stream)
{
using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions
@@ -97,9 +104,13 @@ public void Serialize(Stream stream)
JsonSerializer.Serialize(writer, this, SerializerOptions);
}
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "We always provide a static JsonTypeInfoResolver")]
+ [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "We always provide a static JsonTypeInfoResolver")]
internal void Serialize(Utf8JsonWriter writer) => JsonSerializer.Serialize(writer, this, SerializerOptions);
/// Serialize this instance to a Stream asynchronously
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "We always provide a static JsonTypeInfoResolver")]
+ [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "We always provide a static JsonTypeInfoResolver")]
public Task SerializeAsync(Stream stream, CancellationToken ctx = default) =>
JsonSerializer.SerializeAsync(stream, this, GetType(), SerializerOptions, ctx);
}
diff --git a/src/Elastic.CommonSchema/EcsDocument.cs b/src/Elastic.CommonSchema/EcsDocument.cs
index 74f2a2fe..a5c92774 100644
--- a/src/Elastic.CommonSchema/EcsDocument.cs
+++ b/src/Elastic.CommonSchema/EcsDocument.cs
@@ -226,7 +226,7 @@ Process ReturnFromCache()
// see: https://github.com/elastic/apm-agent-dotnet/pull/847
// see: https://github.com/elastic/apm-agent-dotnet/issues/6
// Mentions observed exceptions however this extension method itself is wrapped in try/catch
- var exString = exception.ToStringDemystified();
+ var exString = exception.ToString();
return new Error { Message = exception.Message, Type = exception.GetType().FullName, StackTrace = exString };
}
diff --git a/src/Elastic.CommonSchema/Elastic.CommonSchema.csproj b/src/Elastic.CommonSchema/Elastic.CommonSchema.csproj
index ad476637..2baaf315 100644
--- a/src/Elastic.CommonSchema/Elastic.CommonSchema.csproj
+++ b/src/Elastic.CommonSchema/Elastic.CommonSchema.csproj
@@ -1,20 +1,19 @@
- netstandard2.0;netstandard2.1;net462;net8.0
+ netstandard2.0;netstandard2.1;net462;net8.0;net9.0
Elastic Common Schema (ECS) Types
Maps Elastic Common Schema (ECS) to .NET types including (de)serialization using System.Text.Json
latest
True
enable
-
-
-
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
+
+ true
+ false
+
+
+
diff --git a/src/Elastic.CommonSchema/Serialization/EcsDocumentJsonConverterFactory.cs b/src/Elastic.CommonSchema/Serialization/EcsDocumentJsonConverterFactory.cs
index 167c9271..ee1e24c3 100644
--- a/src/Elastic.CommonSchema/Serialization/EcsDocumentJsonConverterFactory.cs
+++ b/src/Elastic.CommonSchema/Serialization/EcsDocumentJsonConverterFactory.cs
@@ -1,4 +1,6 @@
using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
using System.Text.Json;
using System.Text.Json.Serialization;
@@ -14,7 +16,10 @@ public class EcsDocumentJsonConverterFactory : JsonConverterFactory
public override bool CanConvert(Type typeToConvert) => typeof(EcsDocument).IsAssignableFrom(typeToConvert);
///
- public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "We always provide a static JsonTypeInfoResolver")]
+ [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "We always provide a static JsonTypeInfoResolver")]
+ [UnconditionalSuppressMessage("AotAnalysis", "IL2092:DynamicallyAccessedMemberTypes", Justification = "More concrete then override")]
+ public override JsonConverter CreateConverter([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]Type typeToConvert, JsonSerializerOptions options)
{
if (typeToConvert == typeof(EcsDocument))
return EcsJsonConfiguration.DefaultEcsDocumentJsonConverter;
diff --git a/src/Elastic.CommonSchema/Serialization/EcsJsonConverterBase.cs b/src/Elastic.CommonSchema/Serialization/EcsJsonConverterBase.cs
index 68070d19..e9851e69 100644
--- a/src/Elastic.CommonSchema/Serialization/EcsJsonConverterBase.cs
+++ b/src/Elastic.CommonSchema/Serialization/EcsJsonConverterBase.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
@@ -13,6 +14,8 @@ namespace Elastic.CommonSchema.Serialization
public abstract class EcsJsonConverterBase : JsonConverter
{
///
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "We always provide a static JsonTypeInfoResolver")]
+ [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "We always provide a static JsonTypeInfoResolver")]
protected static JsonConverter GetDateTimeOffsetConverter(JsonSerializerOptions options) =>
options == EcsJsonConfiguration.SerializerOptions
? EcsJsonConfiguration.DateTimeOffsetConverter
@@ -59,6 +62,8 @@ protected static void WritePropString(Utf8JsonWriter writer, string key, string?
}
///
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "We always provide a static JsonTypeInfoResolver")]
+ [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "We always provide a static JsonTypeInfoResolver")]
protected static void WriteProp(Utf8JsonWriter writer, string key, TValue value, JsonSerializerOptions options)
{
if (value == null) return;
@@ -70,6 +75,8 @@ protected static void WriteProp(Utf8JsonWriter writer, string key, TValu
}
///
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "We always provide a static JsonTypeInfoResolver")]
+ [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "We always provide a static JsonTypeInfoResolver")]
protected static void WriteProp(Utf8JsonWriter writer, string key, TValue value, JsonTypeInfo typeInfo,
JsonSerializerOptions options)
{
@@ -84,6 +91,8 @@ protected static void WriteProp(Utf8JsonWriter writer, string key, TValu
else JsonSerializer.Serialize(writer, value, typeInfo);
}
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "We always provide a static JsonTypeInfoResolver")]
+ [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "We always provide a static JsonTypeInfoResolver")]
internal static object? ReadPropDeserialize(ref Utf8JsonReader reader, Type type, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.Null) return null;
@@ -122,6 +131,8 @@ protected static bool ReadPropString(ref Utf8JsonReader reader, string key, T b,
///
// ReSharper disable once UnusedParameter.Local (key is used for readability)
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "We always provide a static JsonTypeInfoResolver")]
+ [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "We always provide a static JsonTypeInfoResolver")]
private static TValue? ReadProp(ref Utf8JsonReader reader, string key, JsonSerializerOptions options) where TValue : class
{
if (reader.TokenType == JsonTokenType.Null) return null;
diff --git a/src/Elastic.CommonSchema/Serialization/EcsSerializerFactory.cs b/src/Elastic.CommonSchema/Serialization/EcsSerializerFactory.cs
index 27ae68cb..46c15073 100644
--- a/src/Elastic.CommonSchema/Serialization/EcsSerializerFactory.cs
+++ b/src/Elastic.CommonSchema/Serialization/EcsSerializerFactory.cs
@@ -1,5 +1,6 @@
using System;
using System.Buffers;
+using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Text.Json;
using System.Threading;
@@ -21,18 +22,24 @@ namespace Elastic.CommonSchema.Serialization;
///
/// Deserialize a instance from a Stream asynchronously.
///
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "We always provide a static JsonTypeInfoResolver")]
+ [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "We always provide a static JsonTypeInfoResolver")]
public static ValueTask DeserializeAsync(Stream stream, CancellationToken ctx = default) =>
JsonSerializer.DeserializeAsync(stream, EcsJsonConfiguration.SerializerOptions, ctx);
///
/// Deserialize a instance from a json string.
///
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "We always provide a static JsonTypeInfoResolver")]
+ [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "We always provide a static JsonTypeInfoResolver")]
public static TEcsDocument? Deserialize(string json) =>
JsonSerializer.Deserialize(json, EcsJsonConfiguration.SerializerOptions);
///
/// Deserialize a instance from a readonly span of bytes.
///
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "We always provide a static JsonTypeInfoResolver")]
+ [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "We always provide a static JsonTypeInfoResolver")]
public static TEcsDocument? Deserialize(ReadOnlySpan json) =>
JsonSerializer.Deserialize(json, EcsJsonConfiguration.SerializerOptions);
diff --git a/src/Elastic.CommonSchema/Serialization/JsonConfiguration.cs b/src/Elastic.CommonSchema/Serialization/JsonConfiguration.cs
index 549758aa..9c6f5db1 100644
--- a/src/Elastic.CommonSchema/Serialization/JsonConfiguration.cs
+++ b/src/Elastic.CommonSchema/Serialization/JsonConfiguration.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
@@ -13,7 +14,16 @@ namespace Elastic.CommonSchema.Serialization
/// Static class holding
public static class EcsJsonConfiguration
{
+ /// ahas
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "We always provide a static JsonTypeInfoResolver")]
+ [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "We always provide a static JsonTypeInfoResolver")]
+ static EcsJsonConfiguration()
+ {
+ }
+
/// Default used by ECS integrations
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "We always provide a static JsonTypeInfoResolver")]
+ [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "We always provide a static JsonTypeInfoResolver")]
public static JsonSerializerOptions SerializerOptions { get; } = new()
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,
@@ -38,10 +48,14 @@ public static class EcsJsonConfiguration
}
};
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "We always provide a static JsonTypeInfoResolver")]
+ [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "We always provide a static JsonTypeInfoResolver")]
internal static readonly JsonConverter DateTimeOffsetConverter =
(JsonConverter)SerializerOptions.GetConverter(typeof(DateTimeOffset));
/// Default for
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "We always provide a static JsonTypeInfoResolver")]
+ [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "We always provide a static JsonTypeInfoResolver")]
public static readonly EcsDocumentJsonConverter DefaultEcsDocumentJsonConverter = new();
private sealed class EcsJsonStringConverter : JsonConverter
diff --git a/src/Elastic.CommonSchema/Serialization/MetadataDictionaryConverter.cs b/src/Elastic.CommonSchema/Serialization/MetadataDictionaryConverter.cs
index 7ec8ffa5..1ea88021 100644
--- a/src/Elastic.CommonSchema/Serialization/MetadataDictionaryConverter.cs
+++ b/src/Elastic.CommonSchema/Serialization/MetadataDictionaryConverter.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Runtime.Serialization;
using System.Text.Json;
using System.Text.Json.Serialization;
@@ -53,6 +54,8 @@ internal class MetaDataSerializationFailure
return dictionary.Count > 0 ? dictionary : null;
}
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "We always provide a static JsonTypeInfoResolver")]
+ [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "We always provide a static JsonTypeInfoResolver")]
public override void Write(Utf8JsonWriter writer, MetadataDictionary value, JsonSerializerOptions options)
{
writer.WriteStartObject();
diff --git a/src/Elastic.Extensions.Logging.Common/LogEventJsonContext.cs b/src/Elastic.Extensions.Logging.Common/LogEventJsonContext.cs
index 639ca79d..e947280c 100644
--- a/src/Elastic.Extensions.Logging.Common/LogEventJsonContext.cs
+++ b/src/Elastic.Extensions.Logging.Common/LogEventJsonContext.cs
@@ -7,4 +7,4 @@ namespace Elastic.Extensions.Logging.Common;
///
[JsonSerializable(typeof(LogEvent))]
[JsonSourceGenerationOptions(DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)]
-public partial class LogEventJsonContext : JsonSerializerContext { }
+public partial class LogEventJsonContext : JsonSerializerContext;
diff --git a/src/Elastic.Extensions.Logging.Console/LoggingBuilderExtensions.cs b/src/Elastic.Extensions.Logging.Console/LoggingBuilderExtensions.cs
index d354b684..db7b5653 100644
--- a/src/Elastic.Extensions.Logging.Console/LoggingBuilderExtensions.cs
+++ b/src/Elastic.Extensions.Logging.Console/LoggingBuilderExtensions.cs
@@ -1,3 +1,4 @@
+using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.Logging;
namespace Elastic.Extensions.Logging.Console;
@@ -6,7 +7,14 @@ namespace Elastic.Extensions.Logging.Console;
public static class LoggingBuilderExtensions
{
/// Adds ECS output to console output
- public static ILoggingBuilder AddEcsConsole(this ILoggingBuilder builder, LogLevel stdErrorThreshold = LogLevel.Warning, Action? configure = null)
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "Action is not bound")]
+ [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "Action is not bound")]
+ [UnconditionalSuppressMessage("AotAnalysis", "IL2092:DynamicallyAccessedMemberTypes", Justification = "More concrete then override")]
+ public static ILoggingBuilder AddEcsConsole(
+ this ILoggingBuilder builder,
+ LogLevel stdErrorThreshold = LogLevel.Warning,
+ Action? configure = null
+ )
{
builder.AddConsole(c=>
{
diff --git a/src/Elastic.Extensions.Logging/Elastic.Extensions.Logging.csproj b/src/Elastic.Extensions.Logging/Elastic.Extensions.Logging.csproj
index 7384c00d..f8c13c30 100644
--- a/src/Elastic.Extensions.Logging/Elastic.Extensions.Logging.csproj
+++ b/src/Elastic.Extensions.Logging/Elastic.Extensions.Logging.csproj
@@ -14,9 +14,6 @@
-
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
diff --git a/src/Elastic.Ingest.Elasticsearch.CommonSchema/Elastic.Ingest.Elasticsearch.CommonSchema.csproj b/src/Elastic.Ingest.Elasticsearch.CommonSchema/Elastic.Ingest.Elasticsearch.CommonSchema.csproj
index 77714fe7..ac3e4276 100644
--- a/src/Elastic.Ingest.Elasticsearch.CommonSchema/Elastic.Ingest.Elasticsearch.CommonSchema.csproj
+++ b/src/Elastic.Ingest.Elasticsearch.CommonSchema/Elastic.Ingest.Elasticsearch.CommonSchema.csproj
@@ -10,7 +10,7 @@
-
+
diff --git a/src/Elastic.NLog.Targets/ElasticsearchTarget.cs b/src/Elastic.NLog.Targets/ElasticsearchTarget.cs
index 2585f249..01ac6a3e 100644
--- a/src/Elastic.NLog.Targets/ElasticsearchTarget.cs
+++ b/src/Elastic.NLog.Targets/ElasticsearchTarget.cs
@@ -26,8 +26,8 @@ namespace NLog.Targets
public class ElasticsearchTarget : TargetWithLayout
{
///
- public override Layout Layout { get => _layout; set => _layout = value as Elastic.CommonSchema.NLog.EcsLayout ?? _layout; }
- private Elastic.CommonSchema.NLog.EcsLayout _layout = new Elastic.CommonSchema.NLog.EcsLayout();
+ public override Layout Layout { get => _layout; set => _layout = value as EcsLayout ?? _layout; }
+ private EcsLayout _layout = new EcsLayout();
private IBufferedChannel? _channel;
///
@@ -189,6 +189,9 @@ public Layout? CloudId
///
public Action>? ConfigureChannel { get; set; }
+ /// Provide a to the this target uses
+ public IRequestInvoker? RequestInvoker { get; set; }
+
///
public IChannelDiagnosticsListener? DiagnosticsListener => _channel?.DiagnosticsListener;
@@ -200,7 +203,11 @@ protected override void InitializeTarget()
var indexOffset = string.IsNullOrEmpty(indexOffsetHours) ? default(TimeSpan?) : TimeSpan.FromHours(int.Parse(indexOffsetHours));
var connectionPool = CreateNodePool();
- var config = new TransportConfigurationDescriptor(connectionPool, productRegistration: ElasticsearchProductRegistration.Default);
+ var config = new TransportConfigurationDescriptor(
+ connectionPool,
+ productRegistration: ElasticsearchProductRegistration.Default,
+ invoker: RequestInvoker
+ );
// Cloud sets authentication as required parameter in the constructor
if (NodePoolType != ElasticPoolType.Cloud)
config = SetAuthenticationOnTransport(config);
@@ -254,7 +261,7 @@ private EcsDataStreamChannel CreateDataStreamChannel(Distribute
var channelOptions = new DataStreamChannelOptions(transport)
{
DataStream = new DataStreamName(dataStreamType, dataStreamSet, dataStreamNamespace),
- SerializerContexts = [EcsJsonContext.Default, Elastic.CommonSchema.NLog.NLogEcsJsonContext.Default]
+ SerializerContexts = [EcsJsonContext.Default, NLogEcsJsonContext.Default]
};
SetupChannelOptions(channelOptions);
var channel = new EcsDataStreamChannel(channelOptions, new[] { new InternalLoggerCallbackListener() });
@@ -270,7 +277,7 @@ private EcsIndexChannel CreateIndexChannel(DistributedTransport
IndexOffset = indexOffset,
TimestampLookup = l => l.Timestamp,
OperationMode = indexOperation,
- SerializerContexts = [EcsJsonContext.Default, Elastic.CommonSchema.NLog.NLogEcsJsonContext.Default]
+ SerializerContexts = [EcsJsonContext.Default, NLogEcsJsonContext.Default]
};
if (_hasIndexEventId) indexChannelOptions.BulkOperationIdLookup = (logEvent) => (logEvent.Event?.Id)!;
@@ -287,7 +294,7 @@ protected override void CloseTarget()
}
///
- protected override void Write(NLog.Common.AsyncLogEventInfo logEvent)
+ protected override void Write(Common.AsyncLogEventInfo logEvent)
{
try
{
@@ -296,7 +303,7 @@ protected override void Write(NLog.Common.AsyncLogEventInfo logEvent)
logEvent.Continuation(null);
else
{
- NLog.Common.InternalLogger.Error("ElasticSearch - Failed writing to Elastic channel (Buffer full)");
+ Common.InternalLogger.Error("ElasticSearch - Failed writing to Elastic channel (Buffer full)");
logEvent.Continuation(new System.Threading.Tasks.TaskCanceledException("Failed writing to Elastic channel (Buffer full)"));
}
}
@@ -389,15 +396,15 @@ public InternalLoggerCallbackListener()
{
ExportExceptionCallback = ex =>
{
- NLog.Common.InternalLogger.Error(ex, "ElasticSearch - Export Exception");
+ Common.InternalLogger.Error(ex, "ElasticSearch - Export Exception");
};
PublishToInboundChannelFailureCallback = () =>
{
- NLog.Common.InternalLogger.Error("ElasticSearch - Inbound Channel Failure (Buffer full)");
+ Common.InternalLogger.Error("ElasticSearch - Inbound Channel Failure (Buffer full)");
};
PublishToOutboundChannelFailureCallback = () =>
{
- NLog.Common.InternalLogger.Error("ElasticSearch - Outbound Channel Failure (Flush failed)");
+ Common.InternalLogger.Error("ElasticSearch - Outbound Channel Failure (Flush failed)");
};
ExportResponseCallback = (response, _) =>
{
@@ -405,13 +412,13 @@ public InternalLoggerCallbackListener()
return;
if (response.TryGetElasticsearchServerError(out var error))
- NLog.Common.InternalLogger.Error("ElasticSearch - Export Response Server Error - {0}", error);
+ Common.InternalLogger.Error("ElasticSearch - Export Response Server Error - {0}", error);
if (response.Items?.Count > 0)
{
foreach (var itemResult in response.Items)
if (itemResult?.Status >= 300)
- NLog.Common.InternalLogger.Error("ElasticSearch - Export Item failed to {0} document status {1} - {2}", itemResult.Action, itemResult.Status, itemResult.Error);
+ Common.InternalLogger.Error("ElasticSearch - Export Item failed to {0} document status {1} - {2}", itemResult.Action, itemResult.Status, itemResult.Error);
}
};
}
diff --git a/src/Elastic.Serilog.Enrichers.Web/Elastic.Serilog.Enrichers.Web.csproj b/src/Elastic.Serilog.Enrichers.Web/Elastic.Serilog.Enrichers.Web.csproj
index ff3f245b..f429997c 100644
--- a/src/Elastic.Serilog.Enrichers.Web/Elastic.Serilog.Enrichers.Web.csproj
+++ b/src/Elastic.Serilog.Enrichers.Web/Elastic.Serilog.Enrichers.Web.csproj
@@ -20,7 +20,7 @@
-
+
diff --git a/tests-integration/Elasticsearch.IntegrationDefaults/Elasticsearch.IntegrationDefaults.csproj b/tests-integration/Elasticsearch.IntegrationDefaults/Elasticsearch.IntegrationDefaults.csproj
index 6647e3f4..05540e27 100644
--- a/tests-integration/Elasticsearch.IntegrationDefaults/Elasticsearch.IntegrationDefaults.csproj
+++ b/tests-integration/Elasticsearch.IntegrationDefaults/Elasticsearch.IntegrationDefaults.csproj
@@ -11,7 +11,7 @@
-
+
diff --git a/tests/Elastic.Apm.NLog.Tests/Elastic.Apm.NLog.Tests.csproj b/tests/Elastic.Apm.NLog.Tests/Elastic.Apm.NLog.Tests.csproj
index e6d11190..28509887 100644
--- a/tests/Elastic.Apm.NLog.Tests/Elastic.Apm.NLog.Tests.csproj
+++ b/tests/Elastic.Apm.NLog.Tests/Elastic.Apm.NLog.Tests.csproj
@@ -7,8 +7,8 @@
-
-
+
+
diff --git a/tests/Elastic.Apm.NLog.Tests/NLogTests.cs b/tests/Elastic.Apm.NLog.Tests/NLogTests.cs
index 479f64c4..15b18add 100644
--- a/tests/Elastic.Apm.NLog.Tests/NLogTests.cs
+++ b/tests/Elastic.Apm.NLog.Tests/NLogTests.cs
@@ -14,8 +14,15 @@ public class NLogTests
{
public NLogTests()
{
- var assembly = typeof(ApmTraceIdLayoutRenderer).Assembly;
- global::NLog.Config.ConfigurationItemFactory.Default.RegisterItemsFromAssembly(assembly);
+ global::NLog.LogManager.Setup().SetupExtensions(ext =>
+ {
+ ext.RegisterLayoutRenderer(ApmTraceIdLayoutRenderer.Name);
+ ext.RegisterLayoutRenderer(ApmTransactionIdLayoutRenderer.Name);
+ ext.RegisterLayoutRenderer(ApmSpanIdLayoutRenderer.Name);
+ ext.RegisterLayoutRenderer(ApmServiceNameLayoutRenderer.Name);
+ ext.RegisterLayoutRenderer(ApmServiceVersionLayoutRenderer.Name);
+ ext.RegisterLayoutRenderer(ApmServiceNodeNameLayoutRenderer.Name);
+ });
var configuration = new MockConfiguration("my-service", "my-service-node-name", "0.2.1");
if (!Agent.IsConfigured)
@@ -33,9 +40,9 @@ public void NLogWithTransaction()
var target = new MemoryTarget();
target.Layout = "${ElasticApmTraceId}|${ElasticApmTransactionId}|${ElasticApmSpanId}|${message}";
- global::NLog.Config.SimpleConfigurator.ConfigureForTargetLogging(target, LogLevel.Debug);
+ var logFactory = new global::NLog.LogFactory().Setup().LoadConfiguration(cfg => cfg.ForLogger().WriteTo(target)).LogFactory;
- var logger = LogManager.GetLogger("Example");
+ var logger = logFactory.GetLogger("Example");
logger.Debug("PreTransaction");
@@ -72,9 +79,9 @@ public void NLogWithServiceName()
var target = new MemoryTarget();
target.Layout = "${ElasticApmServiceName}|${ElasticApmServiceNodeName}|${ElasticApmServiceVersion}|${message}";
- global::NLog.Config.SimpleConfigurator.ConfigureForTargetLogging(target, LogLevel.Debug);
+ var logFactory = new global::NLog.LogFactory().Setup().LoadConfiguration(cfg => cfg.ForLogger().WriteTo(target)).LogFactory;
- var logger = LogManager.GetLogger("Example");
+ var logger = logFactory.GetLogger("Example");
logger.Debug("Some log");
diff --git a/tests/Elastic.CommonSchema.Log4net.Tests/MessageTests.cs b/tests/Elastic.CommonSchema.Log4net.Tests/MessageTests.cs
index 703cec5a..5152d95e 100644
--- a/tests/Elastic.CommonSchema.Log4net.Tests/MessageTests.cs
+++ b/tests/Elastic.CommonSchema.Log4net.Tests/MessageTests.cs
@@ -127,10 +127,9 @@ public void ToEcs_EventWithException_PopulatesErrorField() => TestLogger((log, g
info.Error.Type.Should().Be(e.GetType().FullName);
info.Error.StackTrace.Should().Contain(e.Message);
- info.Error.StackTrace.Should().Contain("at void");
+ info.Error.StackTrace.Should().Contain("at Elastic.CommonSchema.Log4net.Tests.MessageTests");
info.Error.StackTrace.Should().Contain(innerException.Message);
- info.Error.StackTrace.Should().Contain("at void");
}
});
diff --git a/tests/Elastic.CommonSchema.NLog.Tests/EcsFieldsInTemplateTests.cs b/tests/Elastic.CommonSchema.NLog.Tests/EcsFieldsInTemplateTests.cs
index 4726cf6d..a3d1c81a 100644
--- a/tests/Elastic.CommonSchema.NLog.Tests/EcsFieldsInTemplateTests.cs
+++ b/tests/Elastic.CommonSchema.NLog.Tests/EcsFieldsInTemplateTests.cs
@@ -24,7 +24,7 @@ public void CanUseEcsFieldNamesAsTemplateProperty() => TestLogger((logger, getLo
var ecsEvents = ToEcsEvents(logEvents);
var (_, info) = ecsEvents.First();
- info.Message.Should().Be("Info \"my-trace-id\": true");
+ info.Message.Should().Be("Info my-trace-id: true");
info.Labels.Should().BeNull();
info.Metadata.Should().BeNull();
diff --git a/tests/Elastic.CommonSchema.NLog.Tests/Elastic.CommonSchema.NLog.Tests.csproj b/tests/Elastic.CommonSchema.NLog.Tests/Elastic.CommonSchema.NLog.Tests.csproj
index ead4355f..5abe6c21 100644
--- a/tests/Elastic.CommonSchema.NLog.Tests/Elastic.CommonSchema.NLog.Tests.csproj
+++ b/tests/Elastic.CommonSchema.NLog.Tests/Elastic.CommonSchema.NLog.Tests.csproj
@@ -8,8 +8,8 @@
-
-
+
+
diff --git a/tests/Elastic.CommonSchema.NLog.Tests/LogTestsBase.cs b/tests/Elastic.CommonSchema.NLog.Tests/LogTestsBase.cs
index f13255ed..9de8e34c 100644
--- a/tests/Elastic.CommonSchema.NLog.Tests/LogTestsBase.cs
+++ b/tests/Elastic.CommonSchema.NLog.Tests/LogTestsBase.cs
@@ -8,7 +8,6 @@
using Elastic.Apm.NLog;
using Elastic.CommonSchema.Tests.Specs;
using NLog;
-using NLog.LayoutRenderers;
using Config=NLog.Config;
using NLog.Targets;
using Xunit.Abstractions;
@@ -31,19 +30,23 @@ protected void TestLogger(Action>> act) =>
protected void TestLoggerAndLayout(Action setup, Action>> act)
{
// These layout renderers need to registered statically as ultimately ConfigurationItemFactory.Default is called in the call stack.
- LayoutRenderer.Register(ApmTraceIdLayoutRenderer.Name); //generic
- LayoutRenderer.Register(ApmTransactionIdLayoutRenderer.Name); //generic
- LayoutRenderer.Register(ApmSpanIdLayoutRenderer.Name); //generic
- LayoutRenderer.Register(ApmServiceNameLayoutRenderer.Name); //generic
- LayoutRenderer.Register(ApmServiceVersionLayoutRenderer.Name); //generic
- LayoutRenderer.Register(ApmServiceNodeNameLayoutRenderer.Name); //generic
+ LogManager.Setup().SetupExtensions(ext =>
+ {
+ ext.RegisterLayout();
+ ext.RegisterLayoutRenderer(ApmTraceIdLayoutRenderer.Name);
+ ext.RegisterLayoutRenderer(ApmTransactionIdLayoutRenderer.Name);
+ ext.RegisterLayoutRenderer(ApmSpanIdLayoutRenderer.Name);
+ ext.RegisterLayoutRenderer(ApmServiceNameLayoutRenderer.Name);
+ ext.RegisterLayoutRenderer(ApmServiceVersionLayoutRenderer.Name);
+ ext.RegisterLayoutRenderer(ApmServiceNodeNameLayoutRenderer.Name);
+ });
var logFactory = new LogFactory();
var logConfig = new Config.LoggingConfiguration(logFactory);
var ecsLayout = new EcsLayout { IncludeScopeProperties = true };
ecsLayout.ExcludeProperties.Add("NotX");
setup?.Invoke(ecsLayout);
- var memoryTarget = new MemoryTarget { Layout = ecsLayout, OptimizeBufferReuse = true };
+ var memoryTarget = new MemoryTarget { Layout = ecsLayout };
logConfig.AddRule(LogLevel.Trace, LogLevel.Fatal, memoryTarget);
logConfig.DefaultCultureInfo = System.Globalization.CultureInfo.InvariantCulture;
logFactory.Configuration = logConfig;
@@ -54,7 +57,6 @@ List GetAndValidateLogEvents()
{
TestOut.WriteLine(log);
Spec.Validate(log);
-
}
return memoryTarget.Logs.ToList();
diff --git a/tests/Elastic.CommonSchema.NLog.Tests/MessageTests.cs b/tests/Elastic.CommonSchema.NLog.Tests/MessageTests.cs
index 1e5f4bfe..e51a5bf8 100644
--- a/tests/Elastic.CommonSchema.NLog.Tests/MessageTests.cs
+++ b/tests/Elastic.CommonSchema.NLog.Tests/MessageTests.cs
@@ -41,7 +41,7 @@ public void SeesMessageWithProp() => TestLogger((logger, getLogEvents) =>
var ecsEvents = ToEcsEvents(logEvents);
var (_, info) = ecsEvents.First();
- info.Message.Should().Be("Info \"X\" 2.2 42");
+ info.Message.Should().Be("Info X 2.2 42");
info.Labels.Should().ContainKey("ValueX");
info.Metadata.Should().ContainKey("SomeY");
info.Metadata.Should().NotContainKey("NotX");
@@ -228,7 +228,7 @@ public void SeesMessageWithException() => TestLogger((logger, getLogEvents) =>
[Fact]
public void MetadataWithSameKeys() => TestLogger((logger, getLogEvents) =>
{
- using (MappedDiagnosticsLogicalContext.SetScoped("DupKey", "Mdlc"))
+ using (ScopeContext.PushProperty("DupKey", "Mdlc"))
{
logger.Info("Info {DupKey}", "LoggerArg");
@@ -239,7 +239,7 @@ public void MetadataWithSameKeys() => TestLogger((logger, getLogEvents) =>
var (json, info) = ecsEvents.First();
- info.Message.Should().Be("Info \"LoggerArg\"");
+ info.Message.Should().Be("Info LoggerArg");
info.Labels.Should().Contain("DupKey", "LoggerArg");
info.Labels.Should().Contain("DupKey_1", "Mdlc");
diff --git a/tests/Elastic.CommonSchema.NLog.Tests/WebTests.cs b/tests/Elastic.CommonSchema.NLog.Tests/WebTests.cs
index 4998bdca..ab910a40 100644
--- a/tests/Elastic.CommonSchema.NLog.Tests/WebTests.cs
+++ b/tests/Elastic.CommonSchema.NLog.Tests/WebTests.cs
@@ -5,6 +5,7 @@
using System;
using System.Reflection;
using FluentAssertions;
+using NLog;
using NLog.Config;
using Xunit;
using Xunit.Abstractions;
@@ -17,25 +18,16 @@ public WebTests(ITestOutputHelper output) : base(output) { }
private void TestLayout(bool withNLogWeb, Action setup, Action act)
{
- // Setup basic factory without automatic loading of NLog extensions.
- ConfigurationItemFactory.Default = new(typeof(ConfigurationItemFactory).Assembly);
-
- try
- {
- if (withNLogWeb)
- {
- var nlogWebAssemblyName = new AssemblyName("NLog.Web.AspNetCore");
- var nlogWebAssembly = Assembly.Load(nlogWebAssemblyName);
- ConfigurationItemFactory.Default.RegisterItemsFromAssembly(nlogWebAssembly);
- }
-
- TestLoggerAndLayout(setup, (layout, logger, events) => act(layout));
- }
- finally
+ if (withNLogWeb)
{
- // Cleanup for the sake of other tests.
- ConfigurationItemFactory.Default = null;
+ var nlogWebAssemblyName = new AssemblyName("NLog.Web.AspNetCore");
+ var nlogWebAssembly = Assembly.Load(nlogWebAssemblyName);
+#pragma warning disable CS0618 // Type or member is obsolete
+ ConfigurationItemFactory.Default.RegisterItemsFromAssembly(nlogWebAssembly);
+#pragma warning restore CS0618 // Type or member is obsolete
}
+
+ TestLoggerAndLayout(setup, (layout, logger, events) => act(layout));
}
[Theory]
diff --git a/tests/Elastic.Serilog.Sinks.Tests/SerilogFailureOutputTests.cs b/tests/Elastic.Serilog.Sinks.Tests/SerilogFailureOutputTests.cs
index a239ab35..36e4e982 100644
--- a/tests/Elastic.Serilog.Sinks.Tests/SerilogFailureOutputTests.cs
+++ b/tests/Elastic.Serilog.Sinks.Tests/SerilogFailureOutputTests.cs
@@ -1,9 +1,7 @@
using Elastic.Channels;
using Elastic.Channels.Diagnostics;
using Elastic.Transport;
-using FluentAssertions;
using Serilog;
-using Serilog.Sinks.TestCorrelator;
using Xunit;
using DataStreamName = Elastic.Ingest.Elasticsearch.DataStreams.DataStreamName;