ECS project: Elastic.CommonSchema.Serilog
ECS schema version: latest
ECS .NET assembly version: latest
.NET framework / OS: net9.0 / Windows
Description of the problem, including expected versus actual behavior:
If in our message template we use named parameter which EcsDocument already has the same property name during the conversion of LogEvent to EcsDocment the main property value of EcsDocument will be replaced by the value of the named parameter. To simply reproduce the issue we need to use message template that contains named parameters with the same name of EcsDocument fields. You can also have a look at the unit test below. You can add this test to the Elastic.CommonSchema.Serilog.Tests.MessageTests class.
[Fact]
public void SeesMessageWithMessageProp() => TestLogger((logger, getLogEvents) =>
{
logger.Information("Info {Message}", "X");
var logEvents = getLogEvents();
logEvents.Should().HaveCount(1);
var ecsEvents = ToEcsEvents(logEvents);
var (_, info) = ecsEvents.First();
info.Message.Should().Be("Info X");
info.Labels.Should().ContainKey("X");
var x = info.Labels["Message"];
x.Should().NotBeNull().And.Be("X");
});
In my sample above I used Message named parameter in the message template.
The test above will be failed with the following message.
Expected info.Message to be "Info X" with a length of 6, but "X" has a length of 1, differs near "X" (index 0).
If you have a look at the test output that contains final serialized json you can see the message field value is "X" but the expected is "Info X". Compare it with the MessageTemplate field.
Standard output
{ "@timestamp": "2026-02-12T09:48:29.4267576+01:00", "log.level": "Information", "message": "X", "ecs.version": "9.0.0", "log": { "logger": "Elastic.CommonSchema.Serilog.Tests.MessageTests" }, "labels": { "MessageTemplate": "Info {Message}", "ThreadName": ".NET TP Worker" }, "agent": { "type": "Elastic.CommonSchema.Serilog", "version": "9.0.1-canary.0.9+e5480ff35c391fcc72ec6024d448d8c36b572127" }, "event": { "created": "2026-02-12T09:48:29.4267576+01:00", "severity": 2, "timezone": "Central Europe Standard Time" }, "host": { "os": { "full": "Microsoft Windows 10.0.26200", "platform": "Win32NT", "version": "10.0.26200.0" }, "architecture": "X64", "hostname": "mhahost", "name": "PRG10564" }, "process": { "name": "testhost", "pid": 42228, "thread.id": 11, "thread.name": ".NET TP Worker", "title": "" }, "server": { "user": { "name": "AMUST\\mhosseinalizadeh" } }, "service": { "name": "Elastic.CommonSchema", "type": "dotnet", "version": "9.0.1-canary.0.9+e5480ff35c391fcc72ec6024d448d8c36b572127" }, "user": { "domain": "Test", "name": "mhosseinalizadeh" } }
As far as I checked the issue is in LogEventConverter.ConvertToEcs method. Within this method we try to fetch all the relevant ecs data and fill those ecs properties and at the end there is a call to GetMetadata method that fetches all the remaining properties that are not ECS relevant properties (including the named parameters used in the message template). Then we call ecsEvent.AssignField method to set metadata.
.
.
.
var metaData = GetMetadata(logEvent, configuration.LogEventPropertiesToFilter);
foreach (var kv in metaData)
ecsEvent.AssignField(kv.Key, kv.Value);
.
.
.
The point is that AssignField may set the value for all the fields of EcsDocument not only Metadata or Labels.
So in my example because I have Message named parameter, the path to be set in EcsDocument is "message" and because the EcsDocument has the Message field then the value will be replaced by the value of Message named parameter which is wrong.
Before calling AssignField method the value of the EcsDocument.Message property is correct because it is filled by ecsEvent.Message = logEvent.RenderMessage(configuration.MessageFormatProvider); and there is no problem. The issue happens after filling metadata because it replaces the Message field value.
Please note that the same issue may happen for other EcsDocument string properties like SpanId, TraceId and TransactionId.
Possible solution:
I think the solution would be using another method like AssignField that fills only Metadata or Labels not other fields in this case. Because they are already set correctly. So that we can ensure we will not replace the values that already set for EcsDocument properties by ConvertToEcs method. Unfortunately we do not have such a method currently :(
ECS project: Elastic.CommonSchema.Serilog
ECS schema version: latest
ECS .NET assembly version: latest
.NET framework / OS: net9.0 / Windows
Description of the problem, including expected versus actual behavior:
If in our message template we use named parameter which
EcsDocumentalready has the same property name during the conversion ofLogEventtoEcsDocmentthe main property value ofEcsDocumentwill be replaced by the value of the named parameter. To simply reproduce the issue we need to use message template that contains named parameters with the same name ofEcsDocumentfields. You can also have a look at the unit test below. You can add this test to theElastic.CommonSchema.Serilog.Tests.MessageTestsclass.In my sample above I used
Messagenamed parameter in the message template.The test above will be failed with the following message.
Expected info.Message to be "Info X" with a length of 6, but "X" has a length of 1, differs near "X" (index 0).
If you have a look at the test output that contains final serialized json you can see the
messagefield value is "X" but the expected is "Info X". Compare it with theMessageTemplatefield.Standard output
{ "@timestamp": "2026-02-12T09:48:29.4267576+01:00", "log.level": "Information", "message": "X", "ecs.version": "9.0.0", "log": { "logger": "Elastic.CommonSchema.Serilog.Tests.MessageTests" }, "labels": { "MessageTemplate": "Info {Message}", "ThreadName": ".NET TP Worker" }, "agent": { "type": "Elastic.CommonSchema.Serilog", "version": "9.0.1-canary.0.9+e5480ff35c391fcc72ec6024d448d8c36b572127" }, "event": { "created": "2026-02-12T09:48:29.4267576+01:00", "severity": 2, "timezone": "Central Europe Standard Time" }, "host": { "os": { "full": "Microsoft Windows 10.0.26200", "platform": "Win32NT", "version": "10.0.26200.0" }, "architecture": "X64", "hostname": "mhahost", "name": "PRG10564" }, "process": { "name": "testhost", "pid": 42228, "thread.id": 11, "thread.name": ".NET TP Worker", "title": "" }, "server": { "user": { "name": "AMUST\\mhosseinalizadeh" } }, "service": { "name": "Elastic.CommonSchema", "type": "dotnet", "version": "9.0.1-canary.0.9+e5480ff35c391fcc72ec6024d448d8c36b572127" }, "user": { "domain": "Test", "name": "mhosseinalizadeh" } }As far as I checked the issue is in
LogEventConverter.ConvertToEcsmethod. Within this method we try to fetch all the relevant ecs data and fill those ecs properties and at the end there is a call toGetMetadatamethod that fetches all the remaining properties that are not ECS relevant properties (including the named parameters used in the message template). Then we callecsEvent.AssignFieldmethod to set metadata.The point is that
AssignFieldmay set the value for all the fields ofEcsDocumentnot onlyMetadataorLabels.So in my example because I have
Messagenamed parameter, the path to be set inEcsDocumentis "message" and because theEcsDocumenthas theMessagefield then the value will be replaced by the value ofMessagenamed parameter which is wrong.Before calling
AssignFieldmethod the value of theEcsDocument.Messageproperty is correct because it is filled byecsEvent.Message = logEvent.RenderMessage(configuration.MessageFormatProvider);and there is no problem. The issue happens after filling metadata because it replaces theMessagefield value.Please note that the same issue may happen for other
EcsDocumentstring properties likeSpanId,TraceIdandTransactionId.Possible solution:
I think the solution would be using another method like
AssignFieldthat fills onlyMetadataorLabelsnot other fields in this case. Because they are already set correctly. So that we can ensure we will not replace the values that already set forEcsDocumentproperties byConvertToEcsmethod. Unfortunately we do not have such a method currently :(