Moris
Moris

Reputation: 15

How do I configure Serilog in appsettings.json to create log file in UTF-8-BOM encoding?

The default file encoding that Serilog creates is utf-8 without BOM. How do I configure Serilog in appsettings.json to create log file in UTF-8-BOM encoding?

If i add "encoding": "utf-8", I get an error "InvalidOperationException: Type UTF8 was not found."

"WriteTo:Async": {
  "Name": "Async",
  "Args": {
    "configure": [
      {
        "Name": "File",
        "Args": {
          "path": "Logs/Log-.txt",
          "rollOnFileSizeLimit": true,
          "fileSizeLimitBytes": 5242880,
          "retainedFileCountLimit": 31,
          "rollingInterval": "Day",
          "outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz}] [{Level:u3}] ({ThreadID}) [{SourceContext}] {Message}{NewLine}{Exception}",
          "encoding": "utf-8",
          "formatter": {
            "type": "Serilog.Templates.ExpressionTemplate, Serilog.Expressions"
          }
        }
      }
    ]
  }
}

Upvotes: 1

Views: 725

Answers (2)

Gokulkanna Balusamy
Gokulkanna Balusamy

Reputation: 17

The below configuration worked for me as I have added the args values as "encoding":"System.Text.Encoding::UTF8".

Sample Code as below

appsetting.json

{
"Serilog": {
    "Using": [
        "Serilog.Sinks.Console",
        "Serilog.Sinks.File"
    ],
    "MinimumLevel": "Information",
    "WriteTo": [
        {
            "Name": "Console",
            "Args": {
                "encoding": "System.Text.Encoding::UTF8"
            }
        },
        {
            "Name": "File",
            "Args": {
                "path": "D:\\MyLogFile\\LogFile.log",
                "rollingInterval": "Day",
                "encoding": "System.Text.Encoding::UTF8"
            }
        }
    ],
    "Enrich": [
        "FromLogContext",
        "WithMachineName",
        "WithThreadId"
    ],
    "Destructure": [
        {
            "Name": "ToMaximumDepth",
            "Args": {
                "maximumDestructuringDepth": 4
            }
        },
        {
            "Name": "ToMaximumStringLength",
            "Args": {
                "maximumStringLength": 100
            }
        },
        {
            "Name": "ToMaximumCollectionCount",
            "Args": {
                "maximumCollectionCount": 10
            }
        }
    ]
}}

C#

IConfigurationRoot configurationRoot = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json").Build();
var _logger = new LoggerConfiguration().ReadFrom.Configuration(Configuration).CreateLogger();

Upvotes: 0

batressc
batressc

Reputation: 1588

The manner that you has used to specify the encoding is incorrect. You must provide a valid full qualified existing encoding class name or inherit from an existing or create a custom one.

In this case, you only need to create a derived class of System.Text.UTF8Encoding. Follow these steps:

  1. Create a derived class of System.Text.UTF8Encoding. Passing true on the base constructor we are setting encoderShouldEmitUTF8Identifier parameter and this change the encoding behavior to UTF-8 BOM encoding.
using System.Text;

namespace MyApplication
{
    public class UTF8WithBOMEncoding : UTF8Encoding
    {
        public UTF8WithBOMEncoding() : base(true) { }
    }
}

  1. On appsettings.json specify the full qualified class name and the assembly name of the encoding class to use. If you don't provide both elements the internal type resolution will fail.
{
    "Name": "File",
    "Args": {
        "encoding": "MyApplication.UTF8WithBOMEncoding, MyApplication",
    }
}

TL;DR This notes it's only an explanation of the type resolution behavior

The type resolution occurrs in this line of code Serilog.Settings.Configuration - StringArgumentValue.cs.

var type = FindType(argumentValue.Trim());
if (type == null)
{
    throw new InvalidOperationException($"Type {argumentValue} was not found.");
}

The FindType method uses the Type.GetType method, according the Microsoft documentation this method will try to resolve the type searching on the currently executing assembly or in mscorlib.dll or System.Private.CoreLib.dll.

internal static Type? FindType(string typeName)
{
    var type = Type.GetType(typeName);
    if (type == null)
    {
        if (!typeName.Contains(','))
        {
            type = Type.GetType($"{typeName}, Serilog");
        }
    }

    return type;
}

Because our application it's using the Serilog package to resolve the Serilog configuration, all the operations occurrs in the context of the Serilog Assembly, that is because we must provide explicitly the assembly name where the custom encoding class exists.

Upvotes: 0

Related Questions