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)
-
0
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(); } -
0
- In ABP startup templates, logging is typically configured in
Program.cson 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 usingappsettings.Development.json,appsettings.Production.json, environment variables, etc.
Concrete approach (template-friendly):
- Put Serilog settings into
appsettings.json(and overrides intoappsettings.{Environment}.json). - 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();- Use environment-specific configuration normally:
appsettings.Development.json-> verbose logsappsettings.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.
- In ABP startup templates, logging is typically configured in
-
0
real answer please
-
1
hi
I agree with you, I will share a solution and update the code in our template projects.
Thanks.
-
0
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.
-
0
[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.
-
1
Thanks. I will add this feature in the next version.