.NET Core Logging in Console App - Detail level - c#

I'm creating a console application in .NET Core 5.0 (VS 2019). I'm having trouble implementing my appsettings.json with various logging configuration. It simply does not work.
I have this at the start of the Main() method to configure appsettings.json:
var dir = Directory.GetCurrentDirectory();
var configurationRoot = new ConfigurationBuilder()
.SetBasePath(dir) // Microsoft.Extensions.Configuration.Json
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false)
.AddJsonFile($"appsettings.{environmentName}.json", optional: true, reloadOnChange: false)
.AddEnvironmentVariables()
.AddCommandLine(args)
.Build();
I have also made ServiceCollection extension to configure logging in ServiceCollection:
public static IServiceCollection ConfigureApplicationLogging(this IServiceCollection #this, string appName, IConfigurationRoot configurationRoot)
{
#this.AddLogging(loggingBuilder =>
{
loggingBuilder.ClearProviders();
loggingBuilder.AddConfiguration(configurationRoot);
loggingBuilder.AddConsole();
loggingBuilder.AddEventLog(settings =>
{
settings.LogName = "Application";
settings.SourceName = appName;
});
});
return #this;
}
This is how I create ServiceCollection and build services:
var serviceCollection = new ServiceCollection();
serviceCollection.ConfigureApplicationLogging("MyApp", configurationRoot)
// ... add other services
var services = serviceCollection.BuildServiceProvider();
Following is my appsettings.json:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
},
"Console": {
"IncludeScopes": true,
"LogLevel": {
"Default": "Error",
"Microsoft": "Error"
}
},
"EventLog": {
"LogLevel": {
"Default": "Error",
"Microsoft": "Error"
}
}
}
}
As you can see, Console's default level is set to error. I obtain logger through ServiceCollection:
_logger = services.GetService<ILogger<MyService>>();
Now, if I execute this code:
_logger.LogInformation("info");
_logger.LogError("error");
Both messages get printed to the console and it seems like it doesn't take settings from appsettings.json.
I've searched a lot on the internet, but couldn't find a solution.

By calling AddConsole() you are overriding the settings from the AddConfiguration() call (with defaults, since you're not providing any settings in the AddConsole call).

Related

How to create a class library using serilog as a referenced package?

I have a solution containing multiple .NET Core API and windows service projects. How can I integrate Serilog in such a way that I will not be required to make changes at several different places for adding a column or changing some property?
I'm thinking of adding Serilog in a common library and use that custom library in all other projects so the overhead of installing serilog and other enrichers in each application will be removed and each application doesn't need to take care of logging logs it will be done by custom library.
Below are the points that I need to cover.
How to invoke starting point of the serilog when it is in the library.
Once the instance is created from the application through library, the instance should be accessible throughout the application like in windows service.
How to pass application configuration(serilog) details(appSettings.json) at run time(1st time) to the custom library using dependency injection.
Below is the code, but it's not working and it's not written correctly, I need to have a dependency injection that can pass configuration to the library once the application starts.
Custom library code
public class MySerilog
{
private ILogger logger;
public MySerilog(IConfiguration config)
{
logger = new LoggerConfiguration()
.ReadFrom.Configuration(config).CreateLogger();
}
public void Information(string message)
{
logger.Information(message);
}
}
In Controller.
public class LogServiceController : Controller
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private ILogManager logManager;
// private readonly ILogger<LogServiceController> _logger;
public IActionResult Index()
{
return View();
}
public LogServiceController()
{
// _logger = logger;
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.Build();
logManager = new LogManager(null);
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
var rng = new Random();
// logManager.Information("WeatherForecastControllerTesting");
// _logger.LogInformation("WeatherForecast");
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
}
appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Default": "Information",
"Microsoft": "Error",
"System": "Error"
}
},
"WriteTo": [
{
"Name": "RollingFile",
"Args": {
"pathFormat": "C:\\Users\\logs.txt",
//"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.ffff}|{TenantName}|{RequestId}|{SourceContext}|{Level:u3}|{Message:lj}{NewLine}{Exception}",
"restrictedToMinimumLevel": "Information"
}
}
]
}
}

ILogger is not injected when using new DI functionality - Azure Functions

ILogger is not injected when using new DI functionality and not showing the log information in the console.
public class SampleGreeter : IGreeter
{
private readonly ILogger<SampleGreeter> logger;
public SampleGreeter(ILogger<SampleGreeter> logger)
{
this.logger = logger;
}
public string CreateGreeting(string name)
{
logger.LogInformation("Logging from greeter");
return $"Hello, {name}. I'm a sample greeter.";
}
}
Nothing is logged from greeter, while logging from function runtime works and is showing in the console.
host.json file:
{
"version": "2.0",
"logging": {
"applicationInsights": {
"fileLoggingMode": "debugOnly",
"logLevel": {
"default": "Information",
"<namespace>": "Information"
},
"samplingExcludedTypes": "Request",
"samplingSettings": {
"isEnabled": true
}
}
}
}
Microsoft documentation says:
"The host injects ILogger and ILoggerFactory services into constructors. However, by default these new logging filters are filtered out of the function logs. You need to modify the host.json file to opt-in to additional filters and categories."
Microsoft documentation and example
You've put
"logLevel": {
"default": "Information",
"<namespace>": "Information"
},
(and fileLoggingMode) within the applicationInsights level, but that's not the right one: it should be one level higher, as in the sample configuration file:
"logging": {
"fileLoggingMode": "debugOnly",
"logLevel": {
"default": "Information",
"<namespace>": "Information"
},
"applicationInsights": {
"samplingExcludedTypes": "Request",
"samplingSettings": {
"isEnabled": true
}
}
}

Error when get connection string: ArgumentNullException: Value cannot be null. Parameter name: connectionString

I am using ASP.NET Core 2.0. Below is my code.
Startup:
namespace foo
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services
.AddMvc()
.AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver());
services.AddDbContext<fooContext>(options => options.UseSqlServer(Configuration.GetConnectionString("UserDatabase")));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
appsettings.json:
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
},
"ConnectionStrings": {
"UserDatabase": "Server=DESKTOP-FSES7UK;Database=xxx;User Id=sa; Password=xxxxxxx;Trusted_Connection=True;"
}
}
}
How to fix it?
As mentioned in the comment, try to move your connection string to the top (suggestion) fix is to take the key *"ConnectionStrings" *outside of logging key
appsettings.json
{
"ConnectionStrings": {
"UserDatabase": "Server=DESKTOP-FSES7UK;Database=xxx;User Id=sa; Password=xxxxxxx;Trusted_Connection=True;"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
Problem is your ConnectionStrings object has been a property of Logging object. Write your appsettings.json as follows:
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
},
},
"ConnectionStrings": {
"UserDatabase": "Server=DESKTOP-FSES7UK;Database=xxx;User Id=sa; Password=xxxxxxx;Trusted_Connection=True;"
}
}

Can't get console logging to work in .net core 2.0

I have the following code:
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
Configuration = builder.Build();
var serviceProvider = new ServiceCollection()
.AddLogging(loggingBuilder => loggingBuilder.AddConfiguration(Configuration.GetSection("Logging"))
.AddConsole()
.AddDebug())
.AddSingleton<IEngine, Engine>()
.BuildServiceProvider();
var engine = serviceProvider.GetService<IEngine>();
await engine.RunAsync();
And
public class Engine : IEngine
{
private readonly ILogger<Engine> logger;
public Engine(ILoggerFactory loggerFactory)
{
logger = loggerFactory.CreateLogger<Engine>();
}
public async Task RunAsync()
{
logger.LogError("Test");
logger.LogTrace("Starting engine!");
}
}
Then i have the following configuration
{
"Logging": {
"IncludeScopes": false,
"Console": {
"LogLevel": {
"Default": "Trace",
"System": "Information",
"Microsoft": "Information"
}
}
}
}
But nothing is logged to the console, but i do get output in the debug log, so what am i missing?
I have verified that it finds the config file so that is not the issue!
Well it seems .net core 2.0 has a delay before printing to the console.
So it was working i just wasn't waiting for it to flush!
Rather than calling a Thread.Sleep and waiting for the logger to finish, if you retain an instance of the logger, you can execute:
logger.Dispose()
to force the logger to flush (output) its cache before the application closes.
If the logger is tied to an IContainer or ServiceProvider, you should be able to Dispose() on those to achieve the same effect.
https://github.com/serilog/serilog-extensions-logging-file/issues/16

ASP.Net Core LogLevel not working

I'm having trouble getting the logger to work like i want it to. I've set the loglevel to warning, but the console window is still bloated with info logs.
I've provided some examples below, nothing extra is configured in Startup.cs or Program.cs.
I'm happy to provide more information if needed.
appsettings.json
{
"ConnectionStrings": {
"DefaultConnection": "ConnectionString"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning",
"Microsoft": "Warning"
}
}
}
Logging example:
public class DishRepository : IDishRepository
{
private readonly ApplicationDbContext _context;
private readonly ILogger<DishRepository> _logger;
public DishRepository(ApplicationDbContext context, ILogger<DishRepository> logger)
{
_context = context;
_logger = logger;
}
public IEnumerable<Dish> GetAll()
{
try
{
_logger.LogInformation("GetAll was called");
return _context.Dishes
.Include(d => d.Category)
.Include(d => d.DishIngredients)
.ThenInclude(di => di.Ingredient)
.Include(d => d.PizzaType).ToList();
}
catch (Exception e)
{
_logger.LogError($"Failed to get all dishes: {e}");
return Enumerable.Empty<Dish>();
}
}
}
When i run my program via VisualStudio i get this:
--------This Works--------
I found the example below at https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging/?tabs=aspnetcore2x it works, but I don't understand why this works and not the appsettings.json example above.
appsettings.json
"Logging": {
"IncludeScopes": false,
"Debug": {
"LogLevel": {
"Default": "Warning"
}
},
"Console": {
"LogLevel": {
"PizzeriaAngular": "Warning",
"Microsoft": "Warning",
"Microsoft.AspNetCore": "Warning",
"Microsoft.EntityFrameworkCore": "Information"
}
},
"LogLevel": {
"Default": "Debug"
}
}
Program.cs still looks like this:
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
There are two config files appsettings.json and appsettings.Development.json. And system use it in development mode.
This code work for me (NetCore 2.x)
in class Startup.cs in method ConfigureServices(IServiceCollection services)
services.AddLogging(builder =>
{
builder.SetMinimumLevel(LogLevel.Trace);
builder.AddFilter("Microsoft", LogLevel.Warning);
builder.AddFilter("System", LogLevel.Error);
builder.AddFilter("Engine", LogLevel.Warning);
});
If you are using another logging provider, like NLog, then the "Logging" appsettings for Microsoft will not work.
For NLog, you have to set the minimum logging level in the nlog.config:
<logger name="*" minlevel="Info" writeTo="default" />

Categories