Question

Filtering Serilog logs to different sinks depending on Property

I am attempting to integrate Serilog into my ASP.NET Core API project to log specific types of entries to different sinks based on their propertry. My goal is to configure the logger so that when the Serilog Context includes a specific property, the logs are written to a file; otherwise, they should be directed to SEQ . But this not working for me. Please find below my Code

Appsettings.json

{
  "Serilog": {
    "Using": [ "Serilog.Exceptions" ],
    "LevelSwitches": { "$controlSwitch": "Error" },
    "MinimumLevel": { "ControlledBy": "$controlSwitch" },
    "Enrich": [ "FromLogContext", "WithMachineName", "WithProcessId", "WithThreadId", "WithExceptionDetails" ],
    "WriteTo": [
      {
        "Name": "File",
        "Args": {
          "pathFormat": "C:\\Logs\\MLAPILog-{Date}.log",
          "rollingInterval": "Day",
          "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}"
        },
        "Filter": [
          {
            "Name": "ByIncluding",
            "Args": {
              "Expression": "Matching.WithProperty('LogType', 'File')"
            }
          }
        ]
      },
      {
        "Name": "Seq",
        "Args": {
          "serverUrl": "sequrl",
          "apiKey": "api key",
          "controlLevelSwitch": "$controlSwitch"
        },
        "Filter": [
          {
            "Name": "ByExcluding",
            "Args": {
              "Expression": "Matching.WithProperty('LogType', 'File')"
            }
          }
        ]
      }
    ],
    "Properties": {
      "MLEnvironment": "Local",
      "Client": "Unknown"
    }
  },

BaseController

//below method is specifically to write logs to file.

internal void LogAuthInfo(string requestUrl, string authToken, string formattedAuth)
        {
            var hostName = Dns.GetHostName();
            var ipAddress = Dns.GetHostAddresses(hostName);
            using (LogContext.PushProperty("LogType", "File"))
            {

                _logger
                    .ForContext("CallingApplication", this.CallingApplication)
                    .ForContext("CustomerCode", this.CustomerCode)
                    .ForContext("LocationId", this.LocationId.ToString())
                    .ForContext("LocationDescription", this.LocationDescription)
                    .ForContext("Version", Assembly.GetExecutingAssembly().GetName().Version)
                    .ForContext("ServerIP", string.Join(",", ipAddress.Select(x => x.ToString())))
                    .ForContext("RequestUrl", requestUrl)
                    .ForContext("AuthToken", authToken)
                    .ForContext("FormattedAuthToken", formattedAuth)
                    .Error("AuthToken Info");

            }
        }
    }

Below one is used to log details in seq. Since both logs needs to save different info, I have given different methods

protected internal void LogInfo(string message, [CallerMemberName] string memberName = null, bool detailedTracking = false)
    {
        var hostName = Dns.GetHostName();
        var ipAddress = Dns.GetHostAddresses(hostName);
        _logger
            .ForContext("CallingApplication", this.CallingApplication)
            .ForContext("CustomerCode", this.CustomerCode)
            .ForContext("LocationId", this.LocationId.ToString())
            .ForContext("LocationDescription", this.LocationDescription)
            .ForContext("Version", Assembly.GetExecutingAssembly().GetName().Version)
            .ForContext("ServerIP", string.Join(",", ipAddress.Select(x => x.ToString())))
             .ForContext("DetailedTracking", detailedTracking.ToString())
            .Information(message);

    }

Then I am calling this code in the BasicAuthorizeAttribute class

  public class BasicAuthorizeAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext actionContext)var configuration = actionContext.HttpContext.RequestServices.GetRequiredService<Microsoft.Extensions.Configuration.IConfiguration>();


            var logDebugAccess = configuration.GetValue<string>("AppSettings:LogAuthToken:DebugAccessCodeEnabled");
            string customerCodes = configuration.GetValue<string>("AppSettings:LogAuthToken:CustomerCodes");
            BaseController controller = (BaseController)actionContext.Controller;
 

    if (logDebugAccess != null && logDebugAccess == "true" && !string.IsNullOrEmpty(customerCodes)) //These are configurations to control the logging
                        {
                            var customerCodeList = customerCodes.Split(',').Select(code => code.ToUpper().Trim());
                            if (customerCodeList.Contains(siteCode.ToUpper()))
                            {
                                controller.LogAuthInfo(url, encryptetransactioncode, formattedAuth);
                            }
                        }
    }
}

In Serilog Logger Extension class, I have the below logic given

public static class SerilogLoggerExtension
    {
        public static void Initialize(ILoggerFactory loggerFactory, IConfiguration configuration)
        {
            var mlEnvironment = configuration.GetValue<string>("MLEnvironment");
            var productName = "MicrologicAPI";

            // Read Seq server URL and API key from appsettings.json
            var seqServerUrl = configuration.GetValue<string>("Serilog:WriteTo:1:Args:serverUrl");
            var seqApiKey = configuration.GetValue<string>("Serilog:WriteTo:1:Args:apiKey");

            Log.Logger = new LoggerConfiguration()
                .ReadFrom.Configuration(configuration)
                .Enrich.FromLogContext()
                .Enrich.WithEnvironmentUserName()
                .Enrich.WithExceptionDetails()

                    
                      .CreateLogger();

            loggerFactory.WithFilter(new FilterLoggerSettings
            {
                {"Trace",LogLevel.Trace },
                {"Default", LogLevel.Trace},
                {"Microsoft", LogLevel.Warning},
                {"System", LogLevel.Warning}
            })
            .AddSerilog();
        }
    }

I am using Serilog Version - 2.10.1. Can anyone please help to identify the issue with my code?

 2  33  2
1 Jan 1970

Solution

 2

Please update the appsettings file as given below

{
  
  "Serilog": {
    "Using": [
      "Serilog",
      "Serilog.Enrichers.Thread",
      "Serilog.Settings.Configuration",
      "Serilog.Sinks.Console",
      "Serilog.Sinks.File"
    ],
    "LevelSwitches": { "$controlSwitch": "Information" },
    "MinimumLevel": { "ControlledBy": "$controlSwitch" },
    "Enrich": [ "FromLogContext", "WithMachineName", "WithProcessId", "WithThreadId", "WithExceptionDetails" ],
    "WriteTo": [
      { "Name": "Console" },
      {
        "Name": "Seq",
        "MinimumLevel": "$controlSwitch",
        "Args": {
          "serverUrl": "seq url",
          "apiKey": "seq key",
          "controlLevelSwitch": "$controlSwitch"
        }
      },
      {
        "Name": "Logger",
        "Args": {
          "MinimumLevel": "Information",
          "configureLogger": {
            "Filter": [
              {
                "Name": "ByIncludingOnly",
                "Args": {
                  "expression": "LogType is not null"
                }
              }
            ],
            "WriteTo": [
              {
                "Name": "File",
                "Args": {
                  "rollingInterval": "Day",
                  "path": "Logs/DEBUGACCESSLOG_.log",
                  "outputTemplate": "{Timestamp:HH:mm:ss.fff zzz}|{Level}|{ThreadId}|{SourceContext}|{Message:lj}|{NewLine}"
                }
              }
            ]
          }
        }
      }
    ],
    "Properties": {
      "MLEnvironment": "Local",
      "Client": "Unknown"
    }
  },

Rest of the codes are looking good.

2024-07-22
Chinjoo