3

At the moment I'm trying to add an ILogger or ILogger<> to a Azure Durable Function so as to use logging in Activity Functions.

Logging in the Orchestration Function works fine and is injected in the method itself, but attempts at constructor injection for ILogger always results in a Null Exception.

builder.Services.AddLogging();

The above does not seem to work when added to the Startup file (Bootstrapper) and neither does variations on:

builder.Services.AddSingleton(typeof(ILogger<>), typeof(Logger<>));

Anyone solved this?

  • Are you trying to inject the logger into a different class? – Chris Nov 07 '19 at 16:31
  • I have indeed @chris. I think it's a limitation of Activity functions where the logging may need to be passed in using a tuple or otherwise. – Billy Ray Valentine Nov 07 '19 at 16:32
  • According to [this](https://learn.microsoft.com/en-us/azure/azure-functions/functions-dotnet-dependency-injection#iloggert-and-iloggerfactory), "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. – StriplingWarrior May 12 '22 at 20:11

1 Answers1

4

Remove either of these lines from your Startup file:

builder.Services.AddLogging();
builder.Services.AddSingleton(typeof(ILogger<>), typeof(Logger<>));

Then, wherever you are injecting your ILogger, add the type that your logger is being injected into using ILogger<T> i.e:

public class Function1
{
    private readonly ILogger _logger;

    public Function1(ILogger<Function1> logger)
    {
        _logger = logger;
    }

    [FunctionName("Function1")]
    public async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req)
    {
        _logger.LogInformation("C# HTTP trigger function processed a request.");

        string name = req.Query["name"];

        string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
        dynamic data = JsonConvert.DeserializeObject(requestBody);
        name = name ?? data?.name;

        return name != null
            ? (ActionResult)new OkObjectResult($"Hello, {name}")
            : new BadRequestObjectResult("Please pass a name on the query string or in the request body");
    }
}
Chris
  • 3,113
  • 5
  • 24
  • 46
  • I believe logging is added by default so your first suggestion about removing the registration was accurate. – Nkosi Nov 07 '19 at 19:16
  • https://learn.microsoft.com/en-us/azure/azure-functions/functions-dotnet-dependency-injection#registering-services – Nkosi Nov 07 '19 at 19:19
  • Thanks for your response @chris, this does not work though and is something I'd already tried. Bare in mind, this is Durable Functions and not stateless Azure Functions. – Billy Ray Valentine Nov 08 '19 at 09:07
  • @BillyRayValentine Did you ever find a solution to this? – idude Nov 07 '20 at 00:51
  • I didn't, in the end the ILogger was passed in the function as opposed to the constructor, which is not ideal but is still the correct logger bootstrapped by the framework. – Billy Ray Valentine Nov 11 '20 at 18:01
  • Worked perfectly for me adding the type to ILogger parameter in constructor. – gsubiran Aug 12 '22 at 15:50