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

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"
}
}
]
}
}

Related

Azure AppInsight Log Information not working

In Asp.net Core version 3.1 I have tried to log LogInformation to Application Insights, but it is not logging in App Insight.
private readonly ILogger<LogService> _logger;
public LogService(IOptions<LogConfig> logConfig, ILogger<LogService> logger)
{
_logConfig = logConfig.Value;
_logger = logger;
}
_logger.LogInformation("Parameters: {Log Info}", _logConfig.IsLogEnabled);
But Logging Error is working
_logger.LogError(e, "Parameters: {HttpMethod}, {ErrorCode}", logEntry.HttpMethod, logEntry.ErrorCode);
Using package Microsoft.ApplicationInsights.AspNetCore version 2.21.0
In Startup.cs
services.AddApplicationInsightsTelemetry();
In appSettings.Development.json
{
"Logging": {
"LogLevel": {
"Default": "Information"
}
},
"ApplicationInsights": {
"LogLevel": {
"Default": "Information"
},
"ConnectionString": "secret"
}
}
You are setting the AI loglevel at the incorrect level. It should be like this:
{
"Logging": {
"LogLevel": {
"Default": "Information"
},
"ApplicationInsights": {
"LogLevel": {
"Default": "Information"
}
}
},
"ApplicationInsights": {
"ConnectionString": "secret"
}
}

Is there a way to filter out the healthcheck logs of an ASP.NET Core 6 app in AzureAppService when using ApplicationInsights

I have setup an ASP.NET Core 6.0 web app that uses Azure ApplicationInsights.
Healthcheck is configured like this:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddHealthChecks();
...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseEndpoints(endpoints =>
{
...
endpoints.MapHealthChecks("/healthz");
});
}
}
And when I deploy my app to azure app service my live-metrics are clogged with healthchecks:
I see in a blogpost that someone has written custom filters inside the app.
Is it possible to configure this in a more easy way?
EDIT: The quickest way was to target the logging with this config. Less accurate than accepted solution but required only config changes.
"Logging": {
"LogLevel": {
"Default": "Warning",
"Microsoft": "Warning"
},
//save healthcheck output in the storage account
"AzureAppServicesBlob": {
"IncludeScopes": true,
"LogLevel": {
"Default": "Information",
"Microsoft": "Information",
}
},
//ignore it in the applicationinsights (live-metrics)
"ApplicationInsights": {
"LogLevel": {
"Default": "Information",
// healthcheck namespace
"Microsoft.AspNetCore.Hosting.Diagnostics": "Warning"
}
}
},
Yes, you can do this by using an ITelemetryInitializer
public class FilterHealthchecksTelemetryInitializer : ITelemetryInitializer
{
private readonly IHttpContextAccessor _httpContextAccessor;
public FilterHealthchecksTelemetryInitializer(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
}
public void Initialize(ITelemetry telemetry)
{
if ((_httpContextAccessor.HttpContext?.Request.Path.Value?.StartsWith("/healthz", StringComparison.OrdinalIgnoreCase)).GetValueOrDefault())
{
// We don't want to track health checks in the metrics.
if (telemetry is ISupportAdvancedSampling advancedSampling)
advancedSampling.ProactiveSamplingDecision = SamplingDecision.SampledOut;
// For the case that we cannot filter out the telemetry, we mark it as synthetic
if (string.IsNullOrWhiteSpace(telemetry.Context.Operation.SyntheticSource))
telemetry.Context.Operation.SyntheticSource = "HealthCheck";
}
}
}
Then just add an instance to your services and Application Insights will pick it up
services.AddSingleton<ITelemetryInitializer, FilterHealthchecksTelemetryInitializer>();

.NET Core Logging in Console App - Detail level

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).

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
}
}
}

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