How to control log levels in C# - c#

For a C# library we're building, we've implemented a logging facility using Microsoft.Extensions.Logging. The library is using a nullable ILogger, which is injected by the user of the library, like this:
var client = new Client(app.Logger)
The app is an AspNetCore application, which has a configured logger, and is injected into the Client. However, I'd like to control the log levels using the standard logging configuration as in appsettings.json:
"Logging": {
"LogLevel": {
"Default": "Debug",
"Microsoft.AspNetCore": "Information",
"System.Net.Http.HttpClient": "Information"
}
}
I'd like to add an entry here, to control the logging, like this:
"Logging": {
"LogLevel": {
"Default": "Debug",
"Microsoft.AspNetCore": "Information",
"System.Net.Http.HttpClient": "Information",
"MyLibrary": "Trace" // <--- like this
}
}
The challenge is that the namespace of the logger is not MyLibrary, but the name of the current logger printed is rp-dotnet-sample[0], instead of something like MyLibrary.
My question now is: how do I get to a situation in which I can develop this library and control the log levels external to the library?

Related

C# Serilog config in ASP.NET Core 6

I have the following in appsettings.json for Serilog:
"Serilog": {
"Using": [],
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft.AspNetCore": "Warning",
"System": "Warning" //Amik ezekből a névterekből jönnek is Informationok lesznek.
}
},
"Enrich": [ "FromLogContext", "WithMachineName", "WithProcessId", "WithThreadId" ],
"WriteTo": [
{ "Name": "Console" }
]
},
I tried to add Serilog for my bootstrap app, but nothing worked well :(.
It is not logging to the console.
I have the following settings in appsettings.json for Serilog. I tried to add Serilog for my bootstrap app, but nothing worked well
It is not logging into console.
Well, its not quite clear if you have followed all the steps accordingly. Based on your shared appsettings.json it appreared that your configuration is partially correct. If you don't define anything inside using block its better to ommit that. In addition to this, you haven't defined your "Args" parameter where need to log what I mean is the path. Furthermore, whether you have install the required nuget package and included the required code snippet in your program.cs file
Therefore, you can follow the steps below to implement it correctly.
Prerequisite:
Serilog Nuget Package
appsettings.json configuration
1. Serilog Nuget Package
To configure Serilog for asp.net core reagrdless of its version, you need to following package in your application reference.
serilog.aspnetcore, serilog.aspnetcore and serilog.expressions
You can add from your Nuget Package Manager as following:
Once all the required package installed accordingly it should look like below:
In addititon, you even can using nuget package manager console command which are like below:
dotnet add package serilog.aspnetcore
dotnet add package serilog.sinks.seq
dotnet add package serilog.expressions
2. appsettings.json configuration
Please replace your appsettings.json file as following for serilog.
{
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"WriteTo": [
{
"Name": "Console",
"Args": {
"path": "./logs/log-.txt",
"rollingInterval": "Day"
}
}
]
},
"AllowedHosts": "*"
}
Program.cs file
using Serilog;
Log.Logger = new LoggerConfiguration()
.WriteTo.Console().CreateBootstrapLogger();
Log.Information("Staring up logging");
try
{
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseSerilog((context, logConfig) => logConfig
.WriteTo.Console()
.ReadFrom.Configuration(context.Configuration));
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseSerilogRequestLogging();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
}
catch (Exception ex)
{
Log.Fatal(ex,"Unhandled Exception");
}
finally
{
Log.Information("Log Complete");
Log.CloseAndFlush();
}
Output:
Note: If you would like to know more details about logging in asp.net core you could check the official document here

.NET HttpLogging of request to custom storage

We work in .NET 6 and want to log all incoming requests. We plan to allow this primarily in DEV and TEST environments but potentially and temporarily also in PROD.
The new HttpLogger sounds like a perfect match. But it will output to the standard ILogger which in our case is Elastic. From GDPR reasons we want to avoid that where potentially sensitive data will be exposed in an uncontrolled way.
Does anyone have another solution:
Redirect messages from HttpLogger to other storage
Create custom middleware to be able to sniff requests and output to custom storage
I found this interesting post on reading the body twice but was not able to make it work: https://codetalk.in/posts/2022/01/04/read-request-body-multiple-times-in-asp-dot-net-core
You can do that just by configuration, for example in production app settings, disable HTTP logging for Elastic and enable it for file logger, something like this (really depends on your loggers and configurations):
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information"
},
"Elastic": {
"IncludeScopes": true,
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "None"
}
},
"File":
{
"IncludeScopes": true,
"LogLevel": {
"Default": "None",
"Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information"
}
}
}
}
To be more restrictive, configure HttpLoggingOptions for production to not log some fields for example.

How do you read from appsettings.json in the same style as it's predecessor, webforms?

In WebForms we would have a web.config file that we could do ConfigurationManager.AppSettings["SomeKey"]; to retrieve the value from the key-value pair.
I've just started a project in .NET 5.0 and there doesn't seem a simple way to do something that seems to trivial?
I've looked online and have been unsuccessful in following tutorials on how to access these keys in appsettings.json from a .cshtml file using # notation.
appsettings.json:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"MyKey": "wwwwwwwwwww"
}
Index.cshtml:
<h1>
Title - #ConfigurationManager.AppSettings["MyKey"];
</h1>
The above illustrates what I am trying to achieve, is there a simple way to do this rather than creating classes etc as I don't seem to be able to follow their examples.
To access configuration settings in a view in a .NET project, you should be able to use # annotation. This is done by injecting the configuration into the page:
#page
#model Test5Model
#using Microsoft.Extensions.Configuration
#inject IConfiguration Configuration
Configuration value for 'MyKey': #Configuration["MyKey"]
Take this appsettings.json for example:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"Test": "Hello World",
"ConnectionStrings": {
"SomeContext": "SomeConnectionStringProperties"
},
"SectionOne": {
"SectionOneTestVal": "SomeTestValue"
}
}
In order to access the Test key, it would simply be #Configuration["Test"] while to access the SectionOneTestVal "key" in the SectionOne section, you would do something like Configuration.GetSection("SectionOne")["SectionOneTestVal"]:
Thus adding this to a view:
<p>#Configuration["Test"]</p>
<p>#Configuration.GetSection("SectionOne")["SectionOneTestVal"]</p>
...would yield:
For more information and examples, also check out dependency injection into views.

Trace, Debug and Information messages not reaching App Insights from WorkerService

I've spent the entire last day trying to find something to explain why I'm not seeing any Trace, Debug or Information messages in app insights when I run my WorkerService in Azure. The WorkerService is being hosted in a Linux (Ubuntu 18.4) VM in our enterprise space and in all other ways works fine.
The Critical, Error and Warning messages are getting through so the connection is correctly established but something appears to be filtering the messages at the process end.
The relevant logging part of the appsettings.json is as follows:
"Logging": {
"LogLevel": {
"Default": "Trace",
"System": "Trace",
"Microsoft": "Trace"
}
},
"ApplicationInsights": {
"LogLevel": {
"Default": "Trace",
"System": "Trace",
"Microsoft": "Trace"
}
},
...which should allow everything through I would expect. My test code is...
log.LogTrace("WorkerService: Trace");
log.LogDebug("WorkerService: Debug");
log.LogInformation("WorkerService: Information");
log.LogWarning("WorkerService: Warning");
log.LogError("WorkerService: Error");
log.LogCritical("WorkerService: Critical");
...but I have noticed when I run the code locally that the output window shows the following...
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker: Information: Executing action method MyWorkerService.Features.HealthCheck.HealthCheckController.GetAdvancedHealthCheck (MyWorkerService) - Validation state: Valid
MyWorkerService.Features.HealthCheck.GetAdvancedHealthCheck.Handler: Trace: Trace
MyWorkerService.Features.HealthCheck.GetAdvancedHealthCheck.Handler: Debug: Debug
MyWorkerService.Features.HealthCheck.GetAdvancedHealthCheck.Handler: Information: Information
MyWorkerService.Features.HealthCheck.GetAdvancedHealthCheck.Handler: Warning: Warning
Application Insights Telemetry: {"name":"AppTraces","time":"2020-12-15T08:04:49.6657815Z","iKey":"8d4d3ae1-xxxx-xxxx-xxxx-029e472df754","tags":{"ai.application.ver":"1.0.0.0" ...<snip>... "TraceId":"520378xxxxxxxxxxxxxxxxxxxxe5a1b5"}}}}
MyWorkerService.Features.HealthCheck.GetAdvancedHealthCheck.Handler: Error: Error
Application Insights Telemetry: {"name":"AppTraces","time":"2020-12-15T08:04:49.6688389Z","iKey":"8d4d3ae1-xxxx-xxxx-xxxx-029e472df754","tags":{"ai.application.ver":"1.0.0.0" ...<snip>... "TraceId":"520378xxxxxxxxxxxxxxxxxxxxe5a1b5"}}}}
MyWorkerService.Features.HealthCheck.GetAdvancedHealthCheck.Handler: Critical: Critical
Application Insights Telemetry: {"name":"AppTraces","time":"2020-12-15T08:04:49.6854384Z","iKey":"8d4d3ae1-xxxx-xxxx-xxxx-029e472df754","tags":{"ai.application.ver":"1.0.0.0" ...<snip>... "TraceId":"520378xxxxxxxxxxxxxxxxxxxxe5a1b5"}}}}
...which also suggests that the Trace, Debug and Information messages are not being sent to Azure.
I'm using the "Microsoft.ApplicationInsights.WorkerService" Version="2.16.0" nuget package but cannot see what else I need to configure to change the filter which is limiting the transmitted data.
Any help or suggestions gratefully accepted.
For appsettings.json, please make sure you have set the property copy to output directory as copy if newer(in visual studio, right click appsettings.json -> select properties).
And then put the ApplicationInsights section into Logging section. Like below:
{
"Logging": {
"LogLevel": {
"Default": "Trace",
"Microsoft": "Trace",
"Microsoft.Hosting.Lifetime": "Trace"
},
"ApplicationInsights": {
"LogLevel": {
"Default": "Trace",
"System": "Trace",
"Microsoft": "Trace"
}
}
}
}
Here is the test result at my side:

AWS Logging not working

I created a very simple Console app which is supposed to log the messages to the AWS Logs but although the app runs I can't find any log on AWS.
I think publishing the app code does not make sense: I presume it's ok and it does not throw any exception.
I think the problem is located in the AWS settings. This is what I did in AWS:
created some role , not sure why but did it almost close to what aws poor and messy documentation says. So the role is created, not exactly as it was supposed in the "documentation" but it contains the required permissions for the logs. Why I created it? - I don't have a clue - my app does not use it!
Created the Log Group - ok, this parameter is what I put into the config of my app
Not sure I need t create the log stream, but ok, I created it, but when I click on it it says "No events found." and "It appears you have not installed a CloudWatch Logs agent .."
Why do I need some agent? what is it? how to install? - absolutely not clear and pointing to the poor aws "documentation" is useless.
I guess these are the major things done in the AWS but..still no result - nothing works, I cant see the logs.
Searched for the answer in google, youtube, etc - no result.
Found some code which is similar to mine but it's no enought - it seems there are some settings required to be done on AWS.
What's wrong?
You have two options:
Write log files to disk and use CloudWatch Agent to submit these logs to CloudWatch: https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/QuickStartWindows2016.html
With this option you don't need to configure anything related to AWS in the program, but you have to install and configure the Agent.
Use AWS.Logger NuGet package and configure it to send the logs to CloudWatch, in this case you don't need to use the Agent: https://github.com/aws/aws-logging-dotnet/tree/master/samples/AspNetCore
With this option you must create AWS API user with CloudWatch Log writing permission and put this user credentials into AWS.Logger configuration. Show the configuring code you used if you need an advice on this.
I had a similar problem, which turned out to be more config-related.
Firstly, make sure that you have AWS Toolkit for Visual Studio installed and set up with the appropriate user. I use an IAM User with the correct policy permissions to read and write Cloudwatch logs.
Here's a copy of my basic console test that works correctly:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Configuration;
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace Runner
{
class Program
{
public static async Task Main(string[] args)
{
var services = ConfigureServices(new ServiceCollection())
.BuildServiceProvider();
await services.GetService<App>().RunAsync();
}
private static IServiceCollection ConfigureServices(IServiceCollection services)
{
var configuration = ConfigurationFactory.GetConfiguration();
services
.AddSingleton(configuration)
.AddLogging(builder =>
{
var config = configuration.GetSection("Logging");
builder
.AddConfiguration(configuration.GetSection("Logging"))
.AddConsole()
.AddDebug()
.AddAWSProvider(configuration.GetAWSLoggingConfigSection().Config);
})
// add app
services.AddTransient<App>();
return services;
}
}
public class App
{
private ILogger<App> Logger;
public App(ILogger<App> logger)
{
Logger = logger;
}
public async Task RunAsync()
{
try
{
Logger.LogTrace("LogTrace", "{\"Test\":1}");
Logger.LogInformation("LogInformation", "{\"Test\":2}");
Logger.LogWarning("LogWarning", "{\"Test\":3}");
Logger.LogDebug("LogDebug", "{\"Test\":4}");
Logger.LogError("LogError", "{\"Test\":5}");
Logger.LogCritical("LogCritical", "{\"Test\":6}");
Thread.Sleep(3000);
Debugger.Break();
}
catch (Exception ex)
{
throw;
}
}
}
}
And my appsettings.json file is:
{
"Logging": {
"Region": "eu-west-1",
"LogGroup": "/dev/runner",
"IncludeLogLevel": true,
"IncludeCategory": true,
"IncludeNewline": true,
"IncludeException": true,
"IncludeEventId": false,
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
},
"Console": {
"LogLevel": {
"Default": "Error",
"System": "Information",
"Microsoft": "Information"
}
},
"Debug": {
"LogLevel": {
"Default": "Trace",
"System": "Information",
"Microsoft": "Information"
}
}
}
}
The Thread.Sleep is to allow the console logger to catch up with itself - if you just break you often don't see anything.
Similarly, if you quit the program executing at the breakpoint the AWS logger won't flush its buffers to Cloudwatch (it will just create the logstream and leave it empty), so let the program run to completion to populate the logstream itself.

Categories

Resources