Serilog ElasticSearch Sink custom properties

228 views Asked by At

I'm trying to log to my Elasticsearch instance some data from .NET 6.0 Web Api with Serilog.AspNetCore and Serilog.Sinks.Elasticsearch installed, but I need to use custom properties for example:

  • bankName
  • totalValue
  • customer.name

and others similar to this, but I created custom Enricher:

    public class ApiEnricher : ILogEventEnricher
    {
        private const string bankName = "Total Bank";
        private const decimal totalValue = 21;
        private const string customerName = "Adam";

        public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
        {
            // Add default values for required fields
            logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("bankName", bankName));
            logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("total.value", totalValue));
            logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("cusotmer.name", cusomerName));
        }
    }

I tried to add this to my appsettings.json:

    "Serilog": {
        "Using": [ "Serilog.Sinks.Elasticsearch", "WebApi.Common" ],
        "MinimumLevel": "Debug",
        "Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId", "ApiEnricher" ],
        "WriteTo": [
            {
                "Name": "Console",
                "Args": {
                    "outputTemplate": "[{Timestamp:HH:mm:ss.fff} {Level:u3}] [{SourceContext}] {Message:lj}{NewLine}{Exception}"
                }
            },
            {
                "Name": "Elasticsearch",
                "Args": {
                    "nodeUris": "http://host.docker.internal:9200",
                    "indexFormat": "logs-myApp-example-{0:yyyy.MM}",
                    "autoRegisterTemplate": true,
                    "inlineFields": true,
                    "numberOfReplicas": 2,
                    "numberOfShards": 2
                }
            }
        ]
    },

But with no luck, only example output I'm getting is:

{
  "@timestamp": "2023-11-27T14:02:24.2061221+00:00",
  "level": "Information",
  "messageTemplate": "Example {bankName} {totalValue} {customerName}",
  "message": "Example \"Forbank\" 21.0 \"Bar\"",
  "bankName": "Forbank",
  "totalValue": 21.0,
  "customerName": "Bar",
  "SourceContext": "WebApi.Controllers.SolutionController",
  "ActionId": "1a52a98f-ecc6-40f2-a632-dc045d53811b",
  "ActionName": "WebApi.Controllers.SolutionController.Init",
  "RequestId": "0HMVFA5SJN8GJ:00000004",
  "RequestPath": "/api/example/init",
  "ConnectionId": "0HMVFA5SJN8GJ"
}

Logging with: logger.LogInformation("Example {bankName} {totalValue} {customerName}", bankName, 21, "Bar");

works but I want solution that does not enforce rewriting each logs, also if possible I want it to be configurable from appsettings.json and I will prefer for those props to be only available on Elasticsearch sink.

EDIT:

Let me clarify where the question came from.

I received requirements from an external company regarding what the logs sent to Elastic should look like.

Among these requirements, I have a list of parameters that must appear in elastic, such as: user.name, user.phone, class, exception, etc.

And I was wondering if it could be done in some clever way without having to redo all the logs.

1

There are 1 answers

3
Deev Andrey On BEST ANSWER

This could be done with just appsettings.json configuration, adding Properties section, see this example from official docs:

{
  "Serilog": {
    "Using": [ "Serilog.Sinks.Elasticsearch" ],
    "MinimumLevel": "Warning",
    "WriteTo": [
      {
        "Name": "Elasticsearch",
        "Args": {
          "nodeUris": "http://localhost:9200"
        }
      }
    ],
    "Enrich": [ "FromLogContext", "WithMachineName" ],
    "Properties": {
      "Application": "My app"
    }
  }
}