-
Notifications
You must be signed in to change notification settings - Fork 67
Description
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 :(