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

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

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>();

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

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

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