Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
2 changes: 1 addition & 1 deletion dotnet-tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"rollForward": false
},
"nupkg-validator": {
"version": "0.6.0",
"version": "0.7.0",
"commands": [
"nupkg-validator"
],
Expand Down
7 changes: 7 additions & 0 deletions ecs-dotnet.sln
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -24,4 +25,3 @@ await Host.CreateDefaultBuilder(args)
})
.Build()
.RunAsync();

Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

<ItemGroup>
<PackageReference Include="Elastic.Apm" Version="1.22.0" />
<PackageReference Include="Serilog" Version="4.1.0" />
<PackageReference Include="Serilog" Version="4.3.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.1" />
<PackageReference Include="Elastic.Clients.Elasticsearch" Version="8.16.2" />
<PackageReference Include="Elastic.Elasticsearch.Ephemeral" Version="0.6.0" />
Expand Down
2 changes: 1 addition & 1 deletion examples/aspnetcore-with-serilog/AspnetCoreExample.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<ItemGroup>
<PackageReference Include="Elastic.Apm" Version="1.22.0" />
<PackageReference Include="Elastic.Apm.AspNetCore" Version="1.22.0" />
<PackageReference Include="Serilog" Version="4.1.0" />
<PackageReference Include="Serilog" Version="4.3.0" />
<PackageReference Include="Serilog.AspNetCore" Version="3.2.0" />
<PackageReference Include="Serilog.Sinks.Async" Version="1.5.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
Expand Down
50 changes: 50 additions & 0 deletions examples/ecs-aot-smoketest/ExtensionsLogger.cs
Original file line number Diff line number Diff line change
@@ -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<ITransportConfiguration> 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<ElasticsearchLoggerOptions>(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<ElasticsearchLoggerOptions>([options], []);
var optionsMonitor = new OptionsMonitor<ElasticsearchLoggerOptions>(optionsFactory, [], new OptionsCache<ElasticsearchLoggerOptions>());
provider = new ElasticsearchLoggerProvider(optionsMonitor, channelSetup);
var loggerFactory = new LoggerFactory( [provider], new LoggerFilterOptions { MinLevel = LogLevel.Information });
logger = loggerFactory.CreateLogger<ElasticsearchLogger>();
listener = provider.DiagnosticsListener!;
return loggerFactory;
}
}
41 changes: 41 additions & 0 deletions examples/ecs-aot-smoketest/NLogExporter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using Elastic.Channels.Diagnostics;
using Elastic.Transport;
using NLog.Targets;

public class NLogExporter(ITransport<ITransportConfiguration> 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;
}
}
85 changes: 85 additions & 0 deletions examples/ecs-aot-smoketest/Program.cs
Original file line number Diff line number Diff line change
@@ -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");
}
39 changes: 39 additions & 0 deletions examples/ecs-aot-smoketest/SerilogExporter.cs
Original file line number Diff line number Diff line change
@@ -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<ITransportConfiguration> 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;
}
}
25 changes: 25 additions & 0 deletions examples/ecs-aot-smoketest/ecs-aot-smoketest.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<RootNamespace>ecs_aot_smoketest</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PublishAot>true</PublishAot>
<TrimmerSingleWarn>false</TrimmerSingleWarn>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Elastic.CommonSchema\Elastic.CommonSchema.csproj"/>
<ProjectReference Include="..\..\src\Elastic.Extensions.Logging\Elastic.Extensions.Logging.csproj" />
<ProjectReference Include="..\..\src\Elastic.Ingest.Elasticsearch.CommonSchema\Elastic.Ingest.Elasticsearch.CommonSchema.csproj" />
<ProjectReference Include="..\..\src\Elastic.NLog.Targets\Elastic.NLog.Targets.csproj" />
<ProjectReference Include="..\..\src\Elastic.Serilog.Sinks\Elastic.Serilog.Sinks.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="NLog" Version="6.0.3" />
</ItemGroup>

</Project>
16 changes: 15 additions & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,21 @@
<PublishRepositoryUrl>true</PublishRepositoryUrl>

</PropertyGroup>


<PropertyGroup Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0'))">
<IsAotCompatible>true</IsAotCompatible>
<JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>
</PropertyGroup>

<PropertyGroup>
<PolySharpIncludeRuntimeSupportedAttributes>true</PolySharpIncludeRuntimeSupportedAttributes>
</PropertyGroup>

<ItemGroup Condition="!$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0'))">
<PackageReference Include="PolySharp" Version="1.15.0" PrivateAssets="all"
IncludeAssets="runtime; build; native; contentfiles; analyzers; buildtransitive"/>
</ItemGroup>

<ItemGroup>
<Content Include="README.md" Pack="true" PackagePath="README.md" CopyToOutputDirectory="PreserveNewest"/>
<Content Include="../../nuget-icon.png" CopyToOutputDirectory="PreserveNewest">
Expand Down
2 changes: 1 addition & 1 deletion src/Elastic.Apm.NLog/ApmServiceNameLayoutRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace Elastic.Apm.NLog;
/// Provides ElasticApmServiceName as special logging variable to render the current Elastic APM Service Name
/// </summary>
[LayoutRenderer(Name)]
[ThreadSafe, ThreadAgnostic]
[ThreadAgnostic]
public class ApmServiceNameLayoutRenderer : LayoutRenderer
{
/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion src/Elastic.Apm.NLog/ApmServiceNodeNameLayoutRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Elastic.Apm.NLog;
/// Provides ElasticApmServiceNodeName as special logging variable to render the current Elastic APM Service Node Name
/// </summary>
[LayoutRenderer(Name)]
[ThreadSafe, ThreadAgnostic]
[ThreadAgnostic]
public class ApmServiceNodeNameLayoutRenderer : LayoutRenderer
{
/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion src/Elastic.Apm.NLog/ApmServiceVersionLayoutRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Elastic.Apm.NLog;
/// Provides ElasticApmServiceVersion as special logging variable to render the current Elastic APM Service Version
/// </summary>
[LayoutRenderer(Name)]
[ThreadSafe, ThreadAgnostic]
[ThreadAgnostic]
public class ApmServiceVersionLayoutRenderer : LayoutRenderer
{
/// <summary>
Expand Down
Loading
Loading