Open Closed

Logging configuration hard coded in code, should be in appsettings.json #10377


User avatar
0
improwise created

How come the logger settings is hardcoded into Program.cs and not in appsettings.json?

AFAIK, this goes against recommendations and best practices, an I fail to see a valid reason for this compared to just putting it in appsettings. This basically requires you to make code changes to modify the logging configuration, and also makes it impossible to have different configuration in different environments?

There have been a few requests about this in the past, none with an answer/resolution as it seems

https://abp.io/support/questions/1496/ABPIO-WASM---Log-level-configuration

https://github.com/abpframework/abp/issues/17333

etc.


7 Answer(s)
  • User Avatar
    0
    improwise created
    static async Task Main(string[] args)
    {
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Information()
            .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
            .MinimumLevel.Override("Volo.Abp", LogEventLevel.Warning)
    

    #if DEBUG .MinimumLevel.Override("Malerifakta.CustomerPortal", LogEventLevel.Debug) #else .MinimumLevel.Override("Malerifakta.CustomerPortal", LogEventLevel.Information) #endif .Enrich.FromLogContext() .WriteTo.Async(c => c.File("Logs/logs.txt")) .WriteTo.Async(c => c.Console()) .CreateLogger();

        await CreateHostBuilder(args).RunConsoleAsync();
    }
    
  • User Avatar
    0
    AI-Bot created
    Support Team ABP Agent
    • In ABP startup templates, logging is typically configured in Program.cs on purpose because the host needs a logger before the DI container and modules are built, so startup/bootstrapping errors are captured reliably (including failures that happen while reading configuration, building the app, running migrations, initializing modules, etc.). ABP also ships templates with Serilog pre-wired and a few “baseline” enrichers/sinks so you immediately get useful logs during development without extra setup.
    • That said, ABP does not prevent configuring logging from appsettings*.json. You can (and in production usually should) move almost all Serilog configuration into configuration files and let different environments override it using appsettings.Development.json, appsettings.Production.json, environment variables, etc.

    Concrete approach (template-friendly):

    1. Put Serilog settings into appsettings.json (and overrides into appsettings.{Environment}.json).
    2. In Program.cs, keep only the minimal bootstrap code and load Serilog from configuration:
    using Serilog;
    
       var builder = WebApplication.CreateBuilder(args);
    
       builder.Host.UseSerilog((context, services, loggerConfiguration) =>
       {
           loggerConfiguration
               .ReadFrom.Configuration(context.Configuration)   // <-- appsettings.json
               .ReadFrom.Services(services);                   // <-- DI-based enrichers if any
       });
    
       await builder.AddApplicationAsync<MyHttpApiHostModule>();
       var app = builder.Build();
       await app.InitializeApplicationAsync();
       await app.RunAsync();
    
    1. Use environment-specific configuration normally:
      • appsettings.Development.json -> verbose logs
      • appsettings.Production.json -> warning/error + production sinks (Elastic/AppInsights/etc.)

    What about “hardcoded minimum level” / WASM scenarios?

    • In Blazor WebAssembly, configuration and logging are constrained by the client-side hosting model; the template may set a default minimum level in code to ensure sane defaults and avoid shipping overly-verbose client logs unintentionally. You can still drive this via configuration, but you must ensure your WASM config files are actually loaded/selected per environment (WASM uses wwwroot/appsettings*.json).

    Links you referenced

    • ABP support thread (reachable): https://abp.io/support/questions/1496/ABPIO-WASM---Log-level-configuration
    • GitHub issue link you provided is not reachable from my URL check right now, so I’m not including it as a verified source.

    (If you want the “official ABP template” exact file/method name where Serilog is configured—e.g., a shared helper in *.Shared.Hosting—tell me your ABP version/template type and I can point to the exact implementation.)


    This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

  • User Avatar
    0
    improwise created

    real answer please

  • User Avatar
    1
    maliming created
    Support Team Fullstack Developer

    hi

    I agree with you, I will share a solution and update the code in our template projects.

    Thanks.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Here is an example to use the log configuration with appsettings.json

    {
      "Serilog": {
        "MinimumLevel": {
          "Default": "Debug",
          "Override": {
            "Microsoft": "Information",
            "Microsoft.EntityFrameworkCore": "Warning"
          }
        },
        "WriteTo": [
          {
            "Name": "Async",
            "Args": {
              "configure": [
                {
                  "Name": "File",
                  "Args": { "path": "Logs/logs.txt" }
                }
              ]
            }
          },
          {
            "Name": "Async",
            "Args": {
              "configure": [
                {
                  "Name": "Console"
                }
              ]
            }
          }
        ],
        "Enrich": [ "FromLogContext" ]
      }
    }
    
    
    
    using System;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Builder;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    using Serilog;
    
    namespace AbpSolution1.Web;
    
    public class Program
    {
        public async static Task<int> Main(string[] args)
        {
            Log.Logger = new LoggerConfiguration()
                .WriteTo.Async(c => c.File("Logs/logs.txt"))
                .WriteTo.Async(c => c.Console())
                .CreateBootstrapLogger();
    
            try
            {
                Log.Information("Starting web host.");
                var builder = WebApplication.CreateBuilder(args);
                builder.Host
                    .AddAppSettingsSecretsJson()
                    .UseAutofac()
                    .UseSerilog((context, services, loggerConfiguration) =>
                    {
                        loggerConfiguration
                            .ReadFrom.Configuration(context.Configuration)
                            .ReadFrom.Services(services)
                            .WriteTo.Async(c => c.AbpStudio(services));
                    });
                await builder.AddApplicationAsync<AbpSolution1WebModule>();
                var app = builder.Build();
                await app.InitializeApplicationAsync();
                await app.RunAsync();
                return 0;
            }
            catch (Exception ex)
            {
                Log.Fatal(ex, "Host terminated unexpectedly!");
                return 1;
            }
            finally
            {
                Log.CloseAndFlush();
            }
        }
    }
    
    

    Thanks.

  • User Avatar
    0
    improwise created

    [maliming] said: hi

    Here is an example to use the log configuration with appsettings.json

    { 
      "Serilog": { 
        "MinimumLevel": { 
          "Default": "Debug", 
          "Override": { 
            "Microsoft": "Information", 
            "Microsoft.EntityFrameworkCore": "Warning" 
          } 
        }, 
        "WriteTo": [ 
          { 
            "Name": "Async", 
            "Args": { 
              "configure": [ 
                { 
                  "Name": "File", 
                  "Args": { "path": "Logs/logs.txt" } 
                } 
              ] 
            } 
          }, 
          { 
            "Name": "Async", 
            "Args": { 
              "configure": [ 
                { 
                  "Name": "Console" 
                } 
              ] 
            } 
          } 
        ], 
        "Enrich": [ "FromLogContext" ] 
      } 
    } 
     
    
     
    using System; 
    using System.Threading.Tasks; 
    using Microsoft.AspNetCore.Builder; 
    using Microsoft.Extensions.DependencyInjection; 
    using Microsoft.Extensions.Hosting; 
    using Serilog; 
     
    namespace AbpSolution1.Web; 
     
    public class Program 
    { 
        public async static Task<int> Main(string[] args) 
        { 
            Log.Logger = new LoggerConfiguration() 
                .WriteTo.Async(c => c.File("Logs/logs.txt")) 
                .WriteTo.Async(c => c.Console()) 
                .CreateBootstrapLogger(); 
     
            try 
            { 
                Log.Information("Starting web host."); 
                var builder = WebApplication.CreateBuilder(args); 
                builder.Host 
                    .AddAppSettingsSecretsJson() 
                    .UseAutofac() 
                    .UseSerilog((context, services, loggerConfiguration) => 
                    { 
                        loggerConfiguration 
                            .ReadFrom.Configuration(context.Configuration) 
                            .ReadFrom.Services(services) 
                            .WriteTo.Async(c => c.AbpStudio(services)); 
                    }); 
                await builder.AddApplicationAsync<AbpSolution1WebModule>(); 
                var app = builder.Build(); 
                await app.InitializeApplicationAsync(); 
                await app.RunAsync(); 
                return 0; 
            } 
            catch (Exception ex) 
            { 
                Log.Fatal(ex, "Host terminated unexpectedly!"); 
                return 1; 
            } 
            finally 
            { 
                Log.CloseAndFlush(); 
            } 
        } 
    } 
     
    

    Thanks.

    This is actually quite similar to the one we implemented now except for that we added rollover for log files and we named the "startup log" as startup.txt to keep it separate from the Serilog logging (which probably won't work for the earliest logging so still need that in ABP code probably, just as you did).. This seem to work fine even though we are still in early testing.

  • User Avatar
    1
    maliming created
    Support Team Fullstack Developer

    Thanks. I will add this feature in the next version.

Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.2.0-preview. Updated on February 17, 2026, 09:10
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.