Serilog not writing to File (.net core 2.2)

Turns out I had copied some of the JSON from documentation incorrectly. It's hard to tell but in the original question I actually had Enrich, WriteTo, and Properties sections embedded within the MinimumLevel section.

Obviously this prevented Serilog from correctly knowing which Sinks to write to.

Here's my corrected settings JSON:

"Serilog": {
    "Using": ["Serilog.Sinks.Console", "Serilog.Sinks.File"],
    "MinimumLevel": {
      "Default": "Debug",
      "Override": {
        "Microsoft": "Warning",
        "System": "Warning"
      }
    },
    "Enrich": ["FromLogContext"],
    "WriteTo": [
      { "Name": "Console" },
      { "Name": "Debug" },
      {
        "Name": "File",
        "Args": {
          "path": "%LogDir%\\sampleapp\\log-.txt",
          "rollingInterval": "Day",
          "shared": true
        }
      }
    ],
    "Properties": {
      "Application":  "sampleapp" 
    } 
  },

Note that I also removed the {Date} from the filename. Apparently it'll tack that on if you set the rolling interval to day....


appsettings.Development.json overwrite settings in appsettings.json

I repeat again, configuration in appsettings.Development.json will take precedence over appsettings.json. I know that sounds obvious but I bet someone could overlook this in the future just like I did.

I spent nearly an hour scratching my head why no log was being written to the file, only to notice later I had only Console sink in my appsettings.Development.json (effectively removing my File sink in appsettings.json duh!).

Here is a sample of a proper configuration (modify according to your needs):

ASP.NET Core 3.1

Program.cs

using Microsoft.AspNetCore.Hosting;
using Serilog;
using System;
using System.IO;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog.Core;

namespace My.App
{
    public class Program
    {
        private static bool IsDevelopment =>
            Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development";

        public static IConfiguration Configuration { get; } = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", false, true)
            .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", true)
            .AddEnvironmentVariables()
            .Build();

        public static Logger Logger { get; } = new LoggerConfiguration()
            .ReadFrom.Configuration(Configuration)
            .Enrich.FromLogContext()
            .CreateLogger();

        public static int Main(string[] args)
        {
            Log.Logger = Logger;

            try
            {
                Log.Information("Starting...");
                var host = CreateHostBuilder(args).Build();                      
                host.Run();                        
                return 0;
            }
            catch (Exception ex)
            {
                Log.Fatal(ex, "Host terminated unexpectedly");
                return 1;
            }
            finally
            {
                Log.CloseAndFlush();
            }
        }

        public static IHostBuilder CreateHostBuilder(string[] args)
        {
            var host = Host.CreateDefaultBuilder(args)
                .UseSerilog()
                .UseServiceProviderFactory(
                    new AutofacMultitenantServiceProviderFactory(Startup.ConfigureMultitenantContainer))
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder
                        .UseContentRoot(Directory.GetCurrentDirectory())
                        .UseIISIntegration()
                        .UseStartup<Startup>();
                });

            return host;
        }
    }
}

ASP.NET Core 2.2

Program.cs

public class Program
{
    public static IConfiguration Configuration { get; } = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
        .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
        .AddEnvironmentVariables()
        .Build();

    public static void Main(string[] args)
    {
        Log.Logger = new LoggerConfiguration()
            .ReadFrom.Configuration(Configuration)
            .Enrich.FromLogContext()
            .CreateLogger();

        try
        {
            Log.Information("Starting...");
            CreateWebHostBuilder(args).Run();
        }
        catch (Exception ex)
        {
            Log.Fatal(ex, "Host terminated unexpectedly");
        }
        finally
        {
            Log.CloseAndFlush();
        }
    }

    public static IWebHost CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            .UseSerilog()
            .Build();
}

appsettings.json

{  
  "Serilog": {
    "MinimumLevel": {
      "Default": "Debug",
      "Override": {
        "Microsoft": "Warning",
        "System": "Warning"
      }
    },
    "Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ]
  }
}

appsettings.Development.json

{
  "Serilog": {
    "WriteTo": [
      {
        "Name": "Async",
        "Args": {
          "configure": [
            {
              "Name": "Console"
            },
            {
              "Name": "Debug"
            },
            {
              "Name": "DiagnosticTrace"
            },
            {
              "Name": "File",
              "Args": {
                "path": "/home/log/api-log-.txt",
                "rollingInterval": "Day",
                "retainedFileCountLimit": 7,
                "buffered": true
              }
            }
          ]
        }
      }
    ]
  }
}

appsettings.Production.json

{
  "Serilog": {
    "MinimumLevel": {
      "Default": "Information"
    },
    "WriteTo": [
      {
        "Name": "Async",
        "Args": {
          "configure": [
            {
              "Name": "ApplicationInsights",
              "Args": {
                "restrictedToMinimumLevel": "Information",
                "telemetryConverter": "Serilog.Sinks.ApplicationInsights.Sinks.ApplicationInsights.TelemetryConverters.TraceTelemetryConverter, Serilog.Sinks.ApplicationInsights"
              }
            },
            {
              "Name": "Email",
              "Args": {
                "EmailConnectionInfo": {
                  "EmailSubject": "PRODUCTION error logs",
                  "FromEmail": "xxxxxxx",
                  "ToEmail": "xxxxxxx",
                  "MailServer": "xxxx",
                  "NetworkCredentials": {
                    "username": "xxxxxx",
                    "password": "xxxxxx",
                    "domain": "xxxxx"
                  },
                  "Port": 25
                },
                "restrictedToMinimumLevel": "Error"
              }
            },
            {
              "Name": "File",
              "Args": {
                "path": "/home/log/api-log-.txt",
                "rollingInterval": "Day",
                "retainedFileCountLimit": 15,
                "buffered": true
              }
            }
          ]
        }
      }
    ]
  }
}

Here's my corrected settings JSON:

In Startup class:

Log.Logger = new LoggerConfiguration()
                         .ReadFrom.Configuration(config)
                         .Enrich.With<EventTypeEnricher>()
                         .CreateLogger();

In appsettings.json

{
  "Serilog": {
    "Using": [
      "Serilog.Sinks.Console",
      "Serilog.Sinks.Seq",
      "Serilog.Sinks.Async",
      "Serilog.Sinks.File",
      "Serilog.Sinks.Debug"
    ],
    "MinimumLevel": {
      "Default": "Information",
      "Override": {
        "Microsoft": "Warning",
        "System": "Warning"
      }
    },
    "Enrich": [
      "FromLogContext",
      "WithMachineName"
    ],
    "Properties": {
      "ApplicationName": "AppSim Crawler"
    },
    "WriteTo": [
      {
        "Name": "Seq",
        "Args": {
          "serverUrl": "http://localhost:5341",
          "apiKey": "none"
        }
      },
      {
        "Name": "Debug",
        "Args": {
          "outputTemplate": "{Timestamp:dd-MM-yyyy HH:mm:ss.fff} [{EventType:x8} {Level:u3}] <s:[{SourceContext}]> <method:[{FileName} > {MemberName}]>{NewLine}at {FilePath}:{LineNumber}{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}"
        }
      },
      {
        "Name": "Async",
        "Args": {
          "configure": [
            {
              "Name": "Console",
              "Args": {
                "theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console",
                "outputTemplate": "{Timestamp:dd-MM-yyyy HH:mm:ss.fff} [{EventType:x8} {Level:u3}] <c:[%COMPUTERNAME%]> <s:[{SourceContext}]> <method:[{FileName} > {MemberName}]>{NewLine}at {FilePath}:{LineNumber}{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}"
              }
            }
          ]
        }
      },
      {
        "Name": "Async",
        "Args": {
          "configure": [
            {
              "Name": "File",
              "Args": {
                "path": "C:/appsim/logs/appSimCrawler.log",
                "outputTemplate": "{Timestamp:dd-MM-yyyy HH:mm:ss.fff} [{EventType:x8} {Level:u3}] <s:[{SourceContext}]>  <method:[{FileName} > {MemberName}]>{NewLine}at {FilePath}:{LineNumber}{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}",
                "rollingInterval": "Day",
                "retainedFileCountLimit": 30,
                "shared": true,
                "rollOnFileSizeLimit": true
              }
            }
          ]
        }
      }
    ]
  }
}