azure-functions-host icon indicating copy to clipboard operation
azure-functions-host copied to clipboard

Remove filters for ILoggers created by customer DI

Open brettsam opened this issue 5 years ago • 18 comments

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 avatar Apr 23 '19 21:04 brettsam

@brettsam Thanks for the host.json workaround. Is there a way to specify log levels differently for development vs production environments?

sandeepiiit avatar Jun 05 '19 01:06 sandeepiiit

@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?

bchrisb avatar Jun 19 '19 14:06 bchrisb

@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

bchrisb avatar Jun 19 '19 14:06 bchrisb

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

jamesharling avatar Jan 30 '20 11:01 jamesharling

Are there any updates to this besides removing all the filters?

ilushka85 avatar May 09 '20 16:05 ilushka85

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?

brettsam avatar May 11 '20 13:05 brettsam

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 avatar Sep 29 '20 19:09 smokedlinq

@smokedlinq -- is this happening in production, or locally using the core tools?

brettsam avatar Sep 30 '20 14:09 brettsam

I have only noticed locally while debugging.

smokedlinq avatar Sep 30 '20 22:09 smokedlinq

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 avatar Oct 01 '20 13:10 brettsam

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

IanKemp avatar Oct 01 '20 15:10 IanKemp

@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/

pragnagopa avatar Oct 01 '20 20:10 pragnagopa

Just confirmed, 3.0.2931 does behave as expected. Thanks all.

smokedlinq avatar Oct 01 '20 21:10 smokedlinq

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.

abjbhat avatar Dec 14 '20 07:12 abjbhat

I have the same issue thant @abjbhat and I would love to have a workaround :(

jonathanantoine avatar Mar 26 '21 09:03 jonathanantoine

I am hitting the same issue, did you find a work around ? @jonathanantoine @abjbhat

hachanMSFT avatar Dec 21 '21 00:12 hachanMSFT

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

abjbhat avatar Dec 21 '21 01:12 abjbhat

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?

erikmf12 avatar Feb 01 '24 23:02 erikmf12