azure-functions-host
azure-functions-host copied to clipboard
Remove filters for ILoggers created by customer DI
We need to be less restrictive on filtering logging categories. Today if someone creates a logger that is not in one of our "accepted" lists, we'll filter it away. You can get around this by adding one or more filters to get those categories flowing again, but this shouldn't be necessary.
The below settings will allow any category that starts with "OrderService" to be logged at "Information" and above levels.
{
"version": "2.0",
"logging": {
"logLevel": {
"OrderService": "Information"
}
}
}
@brettsam Thanks for the host.json workaround. Is there a way to specify log levels differently for development vs production environments?
@brettsam when you say: The below settings will allow any category that starts with "OrderService" to be logged at "Information" and above levels.
what is a "category"? I am experiencing this bug but I'm not quite sure what the workaround is? See my code below:
private ILogger<ServiceLogger> _logger;
private readonly string _version;
private readonly string _deploymentRegion;
public ServiceLogger(ILogger<ServiceLogger> logger, IAppSettings appSettings)
{
_logger = logger;
_version = appSettings.Version;
_deploymentRegion = appSettings.DeploymentRegion;
}
And then my host.json:
{
"version": "2.0",
"logging": {
"logLevel": {
"ServiceLogger": "Information"
}
}
}
I still don't get any logs. What am I missing?
@brettsam sorry, I've just found the answer to my own question by looking at this: https://github.com/Azure/azure-functions-host/issues/4425#issuecomment-492678381
You can reset all of the filters with this code in your Startup.cs (put it as late as possible):
builder.Services.RemoveAll<IConfigureOptions<LoggerFilterOptions>>();
builder.Services.ConfigureOptions<LoggerFilterConfigureOptions>();
Where LoggerFilterConfigureOptions
is an internal implementation in Microsoft.Extensions.Logging
that you'll have to bring in to your project (link).
Are there any updates to this besides removing all the filters?
No updates -- but the workaround above is fairly straightforward: https://github.com/Azure/azure-functions-host/issues/4345#issue-436407038.
Is this not working for you?
In the host.json, the category filtering is not working for the root namespace for my solution.
host.json
{
"version": "2.0",
"logging": {
"logLevel": {
"default": "Information",
"MySolution": "Trace"
}
}
}
Where I have a class that tries to use it that gets injected into the function...
namespace MySolution.Things {
public class Thing1 {
public Thing1(ILogger<Thing1> logger) => logger.LogTrace("this is a trace from thing1");
}
}
It does work if I use the full namespace + class name for the category in the host.json, e.g. MySolution.Things.Thing1
@smokedlinq -- is this happening in production, or locally using the core tools?
I have only noticed locally while debugging.
Can you share what version of the core tools and functions host you're running (it should be the first few lines of output in the console when you start your app).
@pragnagopa -- maybe another issue here with the logging setup in core tools.
@brettsam It's been 18 months since you filed this - when is it going to be implemented?
Logging is one of the most important parts of any application. Getting it right should thus be the first priority of any framework. I know Microsoft wants new features to sell Azure with, but Functions' logging woes need to get sorted out for once and for all.
@smokedlinq - Core Tools regression is fixed in the latest version: https://github.com/Azure/azure-functions-core-tools/releases/tag/3.0.2931 - if filter is still not working please open a separate issue here: https://github.com/Azure/azure-functions-core-tools/
Just confirmed, 3.0.2931 does behave as expected. Thanks all.
I think I'm seeing this problem as well.
I've created an Azure Service Bus function. The function uses a DI container using .NET Core's own DI libraries.
The function entry point receives an ILogger instance and we see log entries made with this instance. However, any log entries made with any generic instances of ILogger<MyClass>
never show up. I can't point to this exact timeframe, but a few months ago when this function was first deployed, log entries did show up correctly. In fact, these entries were used to debug an issue we had. This is how I know it worked at some point in the past.
The current function runtime is 3.0.15185.0
So far, I have tried ...
hosts.json
{
"version": "2.0",
"logging": {
"logLevel": {
"default": "Error",
"MySolution.Functions.Tasks": "Trace",
"MySolution.Functions.Tasks.MyFunction1": "Trace",
"MySolution.Functions.Tasks.MyFunction2": "Trace",
"MySolution.Functions.Tasks.Logic.Managers.Tasks.MyServiceClass1": "Information",
"MySolution.Functions.Tasks.Logic.Services.MyServiceClass2": "Information"
},
"applicationInsights": {
"samplingExcludedTypes": "Request",
"samplingSettings": {
"isEnabled": true
}
}
}
}
In my function, I do setup my DI container like so ..
public class MySolution.Functions.Tasks.MyFunction1
{
private readonly IServiceProvider _serviceProvider;
public ProcessTaskFunction()
{
_serviceProvider = Startup.BuildServiceProvider();
}
[FunctionName("MyFunction1")]
public async Task Run(
[ServiceBusTrigger("%TopicName%", "%SubscriptionName%", Connection = "ServiceBusConnectionString")]
string serviceBusMsg,
IDictionary<string, object> userProperties,
ILogger log)
{
{
//this message does show up in AppInsights
log.LogInformation($"C# ServiceBus topic trigger function processed message: {serviceBusMsg}");
using var scope = _serviceProvider.CreateScope();
var dep1 = scope.ServiceProvider.GetRequiredService<IMyDependency1>();
//This dependency takes an instance of ILogger<IMyDependency1>.
//Any calles to ILogger<IMyDependency1>.LogInformation() don't show up in AppInsights of the Kudu file system logs
dep1.DoStuff();
}
}
}
public class Startup
{
public static IServiceProvider BuildServiceProvider()
{
var configRoot = GetConfigurationRoot();
var services = new ServiceCollection();
AddOptions(services, configRoot);
AddConfiguration(services, configRoot);
AddLogging(services, configRoot);
AddSqlDbContext(services);
AddScopedServices(services);
AddHttpClients(services, configRoot);
//added these three lines of code after viewing comment https://github.com/Azure/azure-functions-host/issues/4345#issuecomment-580211775
services.AddSingleton<IConfiguration>(sp => configRoot);
services.RemoveAll<IConfigureOptions<LoggerFilterOptions>>();
services.ConfigureOptions<Common.Logging.LoggerFilterConfigureOptions>();
return services.BuildServiceProvider(true);
}
private static void AddLogging(IServiceCollection services, IConfiguration configRoot)
{
services.AddLogging(builder =>
{
builder.AddConfiguration(configRoot);
builder.AddConsole();
builder.AddDebug();
});
}
//other functions omitted
}
At this point, I'm debating rewriting my function and DI container to pass around the ILogger
instance received in the function entry method.
Any help would be appreciated.
Thanks.
I have the same issue thant @abjbhat and I would love to have a workaround :(
I am hitting the same issue, did you find a work around ? @jonathanantoine @abjbhat
@hachanMSFT @jonathanantoine
My solution was just to take the ILogger
instance passed in when the function is called and then register it in DI. Then every component which needed logging would get an instance of the original ILogger
//YourFunction.cs
public static void Run(/*other parameters*/, ILogger logger){
YourDependencyInjection.Create(logger)
}
//YourDependencyInjection.cs
private void Create(ILogger logger, ServiceCollection services){
services.AddScoped< ILoggerWrapper, LoggerWrapper>(builder => new LoggerWrapper(logger))
}
//ILoggerWrapper.cs maybe defined in a different project/dll. Add whatever methods you need
public interface ILoggerWrapper{
void LogInfo();
void LogError();
}
//LoggerWrapper
public class LoggerWrapper : ILoggerWrapper{
public LoggerWrapper(ILogger logger) {
//save the reference
}
}
//DependentComponentService.cs
public class DependentComponentService{
public DependentComponentService(ILoggerWrapper loggerWrapper){
//save the reference
}
}
This worked for me. I can now see logs in AppInsights. I couldn't see them earlier.
Is this issue still being worked on? Logging shouldn't be this hard to set up. If I have to troubleshoot to get my logs working, that's time that I waste not working on the app.
I've added my namespace to the host.json and I'm still not seeing my custom logs.
These 'workarounds' are great but I think it's ridiculous how I need to add more code than what's in my whole program just to see logs. Are we going to get a proper solution to this or is this inconsistent host.json workaround all we get?