Search code examples
azuredependency-injectionazure-functionsazure-application-insightstelemetry

How to use dependency inject for TelemetryConfiguration in Azure Function


I try to use Dependency injection in Azure Functions for TelemetryConfiguration. In my function I will have it resolved when I inject TelemetryConfiguration in the functions constructor. I suppose I don't really understand how I will do with TelemetryConfiguration in StartUp, thats why I get an exception. How will I add the TelemetryConfiguration I already configured.

I have did an easy example here what I'm doing so far.

[assembly: FunctionsStartup(typeof(StartUp))]
public class StartUp : FunctionsStartup
{
    private string OmsModule { get; } = "OMS.VA";

    public override void Configure(IFunctionsHostBuilder builder)
    {
        builder.Services.Configure<TelemetryConfiguration>(
            (o) =>
            {
                o.InstrumentationKey = Environment.GetEnvironmentVariable("APPINSIGHTS_INSTRUMENTATIONKEY");
                o.TelemetryInitializers.Add(new OperationCorrelationTelemetryInitializer());
            });
    }
}

public class StopPlaceUpdateTimerTrigger
{
    private TelemetryClient _telemetryClient;
    private string _azureWebJobsStorage;

    public StopPlaceUpdateTimerTrigger(TelemetryConfiguration telemetryConfiguration)
    {
        _telemetryClient = new TelemetryClient(telemetryConfiguration);
    }

    [FunctionName("StopPlaceLoader")]
    public async Task StopPlaceLoaderMain([TimerTrigger("%CRON_EXPRESSION%", RunOnStartup = true)]TimerInfo myTimerInfo, ILogger log, ExecutionContext context)
    {
        SetConfig(context);
        var cloudTable = await GetCloudTableAsync();
        if (cloudTable == null)
        {
            //Do nothing
        }
        //Do nothing
    }

    private async Task<CloudTable> GetCloudTableAsync()
    {
        var storageAccount = CloudStorageAccount.Parse(_azureWebJobsStorage);
        var tableClient = storageAccount.CreateCloudTableClient();
        var table = tableClient.GetTableReference(nameof(StopPlaceLoaderCacheRecord));

        if (!await table.ExistsAsync())
        {
            await table.CreateIfNotExistsAsync();
        }
        return table;
    }

    private void SetConfig(ExecutionContext context)
    {
        var config = new ConfigurationBuilder()
            .SetBasePath(context.FunctionAppDirectory)
            .AddJsonFile("local.settings.json", optional: true)
            .AddEnvironmentVariables()
            .Build();
        _azureWebJobsStorage = config["AzureWebJobsStorage"];
    }
}


//local.settings.json
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "DefaultEndpointsProtocol...",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"EnableMSDeployAppOffline": "True",
    "CRON_EXPRESSION": "0 */5 22-3 * * *",
"APPINSIGHTS_INSTRUMENTATIONKEY": "..."
  }
}

I get the following Exception; Microsoft.Extensions.DependencyInjection.Abstractions: Unable to resolve service for type 'Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration' while attempting to activate 'OMS.VA.RealTime.StopPlaceLoader.StopPlaceUpdateTimerTrigger'.


Solution

  • Update:

    We can change this line of code var newConfig = TelemetryConfiguration.Active; to var newConfig = TelemetryConfiguration.CreateDefault(); , since TelemetryConfiguration.Active is deprecated.


    Please use the code below for TelemetryConfiguration DI, I test it with a blob trigger function and works well:

    using System.IO;
    using System.Linq;
    using Microsoft.ApplicationInsights;
    using Microsoft.ApplicationInsights.Extensibility;
    using Microsoft.Azure.WebJobs;
    using Microsoft.Azure.WebJobs.Hosting;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Logging;
    
    [assembly: WebJobsStartup(typeof(FunctionApp17.MyStartup))]
    namespace FunctionApp17
    {
    
        public class MyStartup : IWebJobsStartup
        {
            public void Configure(IWebJobsBuilder builder)
            {
                var configDescriptor = builder.Services.SingleOrDefault(tc => tc.ServiceType == typeof(TelemetryConfiguration));
                if (configDescriptor?.ImplementationFactory != null)
                {
                    var implFactory = configDescriptor.ImplementationFactory;
                    builder.Services.Remove(configDescriptor);
                    builder.Services.AddSingleton(provider =>
                    {
                        if (implFactory.Invoke(provider) is TelemetryConfiguration config)
                        {
                            var newConfig = TelemetryConfiguration.Active;
                            newConfig.ApplicationIdProvider = config.ApplicationIdProvider;
                            newConfig.InstrumentationKey = config.InstrumentationKey;
    
                            return newConfig;
                        }
                        return null;
                    });
                }
            }
        }
    
        public class Function1
        {
            private TelemetryClient _telemetryClient;
    
            public Function1(TelemetryConfiguration telemetryConfiguration)
            {
                _telemetryClient = new TelemetryClient(telemetryConfiguration);
            }
    
            [FunctionName("Function1")]
            public void Run([BlobTrigger("samples-workitems/{name}", Connection = "AzureWebJobsStorage")]Stream myBlob, string name, ILogger log)
            {
                log.LogInformation($"!!!!!!!!!! C# Blob trigger function Processed blob\n Name:{name} \n Size: {myBlob.Length} Bytes");
                _telemetryClient.TrackTrace("this is a test message from DI of telemetry client !!!!!!!!!!!!!!");
            }
        }
    }
    

    the test result as below, I can see the logs in the application insights in azure portal:

    enter image description here

    And one more thing, I see you try to use ITelemetry Initializer in your code. You can follow this GitHub issue for your ITelemetry Initializer or Itelemetry Processor