Artavazd
Artavazd

Reputation: 175

Serilog not logging to SQL Server

In my .NET Core 3.1 project, I have installed Serilog and tried to follow all of the implementing details but for some reason it is not logging into a SQL Server table.

Here is the code - Web API program:

public class Program
{
    public static void Main(string[] args)
    {
        try
        {
            var iWebHost = CreateHostBuilder(args).Build();
            var path = Directory.GetCurrentDirectory();
            var environmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production";
            var configuration = new ConfigurationBuilder()
                .SetBasePath(path)
                .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                .AddJsonFile($"appsettings.{environmentName}.json", optional: true)
            .Build();

            var logger = new LoggerConfiguration()
                .Enrich.FromLogContext()
                .ReadFrom.Configuration(configuration)
                .CreateLogger();

            Log.Logger = logger;
            iWebHost.Run();
        }
        catch (Exception exception)
        {
            Log.Fatal(exception, "Error starting");
        }
        finally
        {
            Log.CloseAndFlush();
        }
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            })
            .UseSerilog();
}

appsetting.json and appsettings.development.json

{
"Serilog": {
    "Using": [ "Serilog.Sinks.MSSqlServer" ],
    "MinimumLevel": {
      "Default": "Information",
      "Override": {
        "System": "Warning",
        "Microsoft": "Warning"
      },
      "WriteTo": [
        {
          "Name": "MSSqlServer",
          "Args": {
            "connectionString": "Server=localhost; Initial Catalog=GP; User ID=lc; Password=lc",
            "tableName": "Log"
          }
        }
      ]
    }
  }
}

Here is my main controller

public class MainController : ControllerBase
{
    private readonly ILogger<MainController> _logger;

    public MainController(ILogger<MainController> logger)
    {
        _logger = logger;
    }
}

And here is the controller that I want to write logs from:

public async Task<ResponseBase> GetAsync(RequestBase request)
{
    _logger.LogInformation("in controller");
    // other code
    // return;
}

Here is my log entity

public class Log
{
    public int Id { get; set; }
    public string Message { get; set; }
    public string MessageTemplate { get; set; }
    public string Level { get; set; }
    public DateTimeOffset TimeStamp { get; set; }
    public string Exception { get; set; }
    public string Properties { get; set; }
    public string LogEvent { get; set; }
}

Upvotes: 2

Views: 6015

Answers (1)

Panagiotis Kanavos
Panagiotis Kanavos

Reputation: 131374

Your code calls UseSerilog() before Serilog's configuration. This means the application ends up with a default, unconfigured logger. You can avoid this by configuring Serilog using inline initialization with the UseSerilog overload that provides access to the HostingContext. From the linked docs:

.UseSerilog((hostingContext, services, loggerConfiguration) => loggerConfiguration
    .ReadFrom.Configuration(hostingContext.Configuration)
    .Enrich.FromLogContext()
    .WriteTo.Console())

This reads Serilog's settings from configuration and adds a Console logger, ensuring you'll get log messages even if the configuration is incorrect.

There's no reason to create the configuration separately. CreateDefaultBuilder() sets the current directory as the root and adds the appsettings files. To extend this, use ConfigureHostConfiguration or ConfigureAppConfiguration after CreateDefaultBuilder().

CreateHostBuilder should change to :

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        })
        .UseSerilog((hostingContext, services, loggerConfiguration) => loggerConfiguration
            .ReadFrom.Configuration(hostingContext.Configuration)
            .Enrich.FromLogContext()
            .WriteTo.Console());

and Main to just :

public static void Main(string[] args)
{
    CreateHostBuilder(args).Run();
}

If you want to use the logger before building the host, you should create it before calling UseSerilog() :

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

    try
    {
        CreateHostBuilder(args).Run();
    }
    catch (Exception exception)
    {
        Log.Fatal(exception, "Error starting");
    }
    finally
    {
        Log.CloseAndFlush();
    }
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        })
        .UseSerilog()

Upvotes: 2

Related Questions