ILogger injected via constructor for Http trigger functions with Azure Function 2.x
Calling LogCategories.CreateFunctionUserCategory
fixed my problem. Complete example:
Azure Functions Core Tools (2.7.1158 Commit hash: f2d2a2816e038165826c7409c6d10c0527e8955b)
Function Runtime Version: 2.0.12438.0
Startup.cs
No need to add
builder.Services.AddLogging();
it's imported automatically in the container.
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
[assembly: FunctionsStartup(typeof(MyFunctionsNamespace.Startup))]
namespace MyFunctionsNamespace
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddTransient<IMyService, MyService>();
}
}
}
MyFunkyFunction.cs
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Extensions.Logging;
namespace MyFunctionsNamespace
{
public class MyFunkyFunction
{
private readonly IMyService _myService;
public MyFunkyFunction(IMyService myService)
{
_myService = myService;
}
[FunctionName("FunkyFunc")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]
HttpRequest req
, ILogger log
)
{
log.LogInformation("C# HTTP trigger function processed a request.");
_myService.Do();
return new OkObjectResult("Hello");
}
}
}
IMyService.cs
Anything in
LogCategories.CreateFunctionUserCategory
will do the job. It seems to be some WebJob legacy requirement.
using Microsoft.Azure.WebJobs.Logging;
using Microsoft.Extensions.Logging;
namespace MyFunctionsNamespace
{
public interface IMyService
{
void Do();
}
public class MyService : IMyService
{
private readonly ILogger _log;
public MyService(ILoggerFactory loggerFactory)
{
// Important: Call CreateFunctionUserCategory, otherwise log entries might be filtered out
// I guess it comes from Microsoft.Azure.WebJobs.Logging
_log = loggerFactory.CreateLogger(LogCategories.CreateFunctionUserCategory("Common"));
}
public void Do()
{
_log.Log(LogLevel.Information, "Hello from MyService");
}
}
}
I had this problem as well. I was able to fix it by calling AddLogging()
:
[assembly: WebJobsStartup(typeof(Startup))]
namespace MyApp
{
public class Startup : IWebJobsStartup
{
public void Configure(IWebJobsBuilder builder)
{
builder.Services.AddHttpClient();
builder.Services.AddTransient<IAppSettings, AppSettings>();
builder.Services.AddLogging();
}
}
And then, in the Azure Function, I had to do pass a ILoggerFactory
instead of an ILogger
and get the ILogger
instance from the loggerFactory
:
public class Functions
{
private HttpClient _httpClient;
private IAppSettings _appSettings;
private ILogger _log;
public Functions(HttpClient httpClient, IAppSettings appSettings, ILoggerFactory loggerFactory)
{
_log = loggerFactory.CreateLogger<Functions>();
}
[FunctionName("Token")]
public async Task<IActionResult> Token(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "Token")]
HttpRequest httpRequest)
{
// No need to keep getting the ILogger from the Run method anymore :)
}
}
I had this same problem. I finally found that adding this "logging" element to my host.json file solved it for me.
{
"version": "2.0",
"logging": {
"logLevel": {
"default": "Trace"
}
}
}
Now the standard .NET core constructor-injected logger method works fine.