3

I have an Azure Function v2, like this:

public sealed class FindAccountFunction
{
    private readonly IAccountWorkflow m_accountWorkflow;

    public FindAccountFunction(ILogger<FindAccountFunction> logger)
    {
        m_logger = logger;
    }

    [FunctionName("FindAccount")]
    public async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "GET", Route = "v1/accounts/")] HttpRequest httpRequest)
    {
        // Do stuff.
        m_logger.LogInformation("Duuuddde");
    }
}

As described in a different question, the logger is being injected:

[assembly: WebJobsStartup(typeof(Startup))]

public sealed class Startup : IWebJobsStartup
{
    public void Configure(IWebJobsBuilder webJobsBuilder)
    {
        // Registers other services...

        // -- UPDATE - The AddLogging must be called here --
        webJobsBuilder.Services.AddLogging();
    }
}

Then I trigger my function through an HTTP request and go to the Function's portal on Azure DevOps to see if the logs is actually printed:

Azure Function's portal

I only see the logs indicating that the function ran successfully however I do not see my log.

Question

Why is the ILogger injected in my Azure Function v2 missing the APPINSIGHTS_INSTRUMENTATIONKEY?

Update

When I look at the injected ILogger, I can see that the InstrumentationKey of the Application Insights Provider is not set. The same applies for a ctor injected ILogger, but also for the injected ILogger in the Run method.

Instrumentation key

For my local tests, the instrumentation key is declared in the local.settings.json file:

local.settings.json

Kzryzstof
  • 7,688
  • 10
  • 61
  • 108

3 Answers3

4

I got confused with different variants of setup (ILogger vs ILoggerFactory vs other stuff).

In my Startup class, it is correct to call AddLogging (with a minimum level or not, as long as it is defined somewhere here or in the host.json file).

using InjectionHttpClientFactory;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

[assembly: WebJobsStartup(typeof(Startup))]

namespace InjectionHttpClientFactory
{
    public sealed class Startup : IWebJobsStartup
    {
        public void Configure(IWebJobsBuilder webJobsBuilder)
        {
            webJobsBuilder.Services.AddLogging();
        }
    }
}

In the Azure Function, I have an error if I specify HttpClient as a parameter:

Microsoft.Extensions.DependencyInjection.Abstractions: Unable to resolve service for type 'Microsoft.Extensions.Logging.ILogger' while attempting to activate 'XXX'

However, it does work if I specify an ILoggerFactory. The instrumentation key property that was empty somehow has no impact.

I have updated the host.json file to include the logging information with the minimum severity level as well as configuration information for Application Insights:

{
  "version": "2.0",
  "logging": {
    "fileLoggingMode": "debugOnly",
    "logLevel": {
      "default": "Trace"
    },
    "applicationInsights": {
        "samplingSettings": {
          "isEnabled": true,
          "maxTelemetryItemsPerSecond" : 5
        }
    }
  }
}

Update

As mentioned in comments, Microsoft released an update which introduces the FunctionsStartup class which should be the preferred way of doing this.

[assembly: FunctionsStartup(typeof(MyNamespace.Startup))]

namespace MyNamespace
{
    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            builder.Services.AddHttpClient();
            builder.Services.AddSingleton((s) => {
                return new CosmosClient(Environment.GetEnvironmentVariable("COSMOSDB_CONNECTIONSTRING"));
            });
            builder.Services.AddSingleton<ILoggerProvider, MyLoggerProvider>();
        }
    }
}
Kzryzstof
  • 7,688
  • 10
  • 61
  • 108
  • 2
    I think this is somewhat outdated now, should use [FunctionsStartup](https://learn.microsoft.com/en-us/azure/azure-functions/functions-dotnet-dependency-injection#registering-services) instead. – Kapé May 13 '19 at 16:02
  • What is the implementation of MyLoggerProvider? – João Antunes Sep 10 '19 at 15:22
  • @JoãoAntunes It is up to you to define your own provider. This specific code snippet comes from Microsoft's documentation (See https://learn.microsoft.com/en-us/azure/azure-functions/functions-dotnet-dependency-injection#registering-services). – Kzryzstof Sep 10 '19 at 16:28
1
    services.AddSingleton(context => 
        {
            var factory = context.GetRequiredService<ILoggerFactory>();
            var loggingConfiguration = <get your app insights's instrumentation key from your configuration provider>;
            var logger = new LoggerConfiguration()
                    .WriteTo
                    .ApplicationInsightsEvents(loggingConfiguration.ApplicationInsightsKey)
                    .CreateLogger();
            return factory.AddSerilog(logger).CreateLogger("MyLogger");
        });

Logger needs to be configured prior to ingest telemetry with your app-insights. Design Usage(Serilog) pattern may be different as this is just a stub to explain.

hemantsharma
  • 537
  • 1
  • 5
  • 12
-1

Logger is passed as a function argument:

public async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, Verbs.Get, Route = "v1/accounts/")] HttpRequest httpRequest, ILogger log)
{
    // ...
}
Kzryzstof
  • 7,688
  • 10
  • 61
  • 108
  • 1
    The most recent runtime Azure Function enables the ILogger to be injected not only in the Function itself but in the injected services also. Even if I add the ILogger to the Run method itself, I will most likely have the same issue with the services: where will I see the logs from those services? – Kzryzstof Mar 01 '19 at 13:53
  • Ok. Did you had a look at https://github.com/Ruard/ProcsIT.Azure.Functions.DependencyInjection ? I didn't tried it. – Thibault Cuvillie Mar 01 '19 at 14:12
  • Does not seem to be related to my problem: it looks like a custom solution with a custom attribute named Inject. I am using services.AddLogging(); which is supposed to do all of this. – Kzryzstof Mar 01 '19 at 15:45