Complete OTEL sample with Azure functions and Application insights

Hi All,

we are trying to use OTEL with Azure functions, is there a sample that i could use as a strating point ?, or any guidance on how to get started?

few questions below, a simple sample with with logs, metrics and traces would really help.

  1. Where should we enable opentelemetry on the endpointConfiguration object or the advancedConfiguration object ?

Thanks -Nen

I have created the following code which works for tracing and metrics but there are no logs avilable in appinisights

Questions

  1. is this the correct way of implementing OTEL in Azure functions
  2. what changes do i need to do to get the logs in application insights.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Azure.Cosmos;
using NServiceBus.Logging;
using OpenTelemetry;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using OpenTelemetry.Metrics;
using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.Extensibility;
using Azure.Monitor.OpenTelemetry.Exporter;
using Microsoft.Extensions.Logging;
using OpenTelemetry.Logs;


//#region configuration-with-function-host-builder
[assembly: NServiceBusTriggerFunction("ASBEndpoint")]


var attributes = new Dictionary<string, object>
{
    ["service.name"] = "ASBEndpoint",
    ["service.instance.id"] = Guid.NewGuid().ToString(),
};

var resourceBuilder = ResourceBuilder.CreateDefault().AddAttributes(attributes);

#region enable-tracing

string appInsightsConnectionString = "";
var traceProvider = Sdk.CreateTracerProviderBuilder()
    .SetResourceBuilder(resourceBuilder)
    .AddSource("NServiceBus.Core")
    .AddAzureMonitorTraceExporter(o => o.ConnectionString = appInsightsConnectionString)
    .AddConsoleExporter()
    .Build();

#endregion



#region enable-meters

var telemetryConfiguration = TelemetryConfiguration.CreateDefault();
telemetryConfiguration.ConnectionString = appInsightsConnectionString;
var telemetryClient = new TelemetryClient(telemetryConfiguration);
telemetryClient.Context.GlobalProperties["Endpoint"] = "ASBEndpoint";

var meterProvider = Sdk.CreateMeterProviderBuilder()
    .SetResourceBuilder(resourceBuilder)
    .AddMeter("NServiceBus.Core")
    .AddAzureMonitorMetricExporter(o => o.ConnectionString = appInsightsConnectionString)
    .AddConsoleExporter()
    .Build();

#endregion




// TODO: move config values to local.settings.json and secrets
ILog log = LogManager.GetLogger<Program>();
var host = new HostBuilder()
    .ConfigureFunctionsWorkerDefaults()

    .ConfigureLogging(logging =>
    {
        logging.AddOpenTelemetry(loggingOptions =>
        {
            loggingOptions.IncludeFormattedMessage = true;
            loggingOptions.IncludeScopes = true;
            loggingOptions.ParseStateValues = true;
            loggingOptions.AddConsoleExporter();
            logging.AddApplicationInsights();
        });
    })      
    .UseNServiceBus(nsb =>
    {
        #region OTEL
        nsb.AdvancedConfiguration.EnableOpenTelemetry();
        #endregion

        #region CosmosDBConfig
        PersistenceExtensions<CosmosPersistence> persistence = nsb.AdvancedConfiguration.UsePersistence<CosmosPersistence>();
        string connection = @"AccountEndpoint = https://localhost:8081/;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==";
        persistence.DatabaseName("Endpoint");
        persistence.CosmosClient(new CosmosClient(connection));
        persistence.DefaultContainer("Customer", "/CustomerId");
        #endregion

        #region TransactionInformationFromLogicalMessage

        var transactionInformation = persistence.TransactionInformation();
        transactionInformation.ExtractPartitionKeyFromMessage<IProvideCustomerId>(provideOrderId =>
        {
            log.Info($"Found partition key '{provideOrderId.CustomerId}' from '{nameof(IProvideCustomerId)}'");
            return new PartitionKey(provideOrderId.CustomerId.ToString());
        });
        #endregion




    })
    .Build();

host.Run();



i have this finally working, had to add the following to get the logging working.

@danielmarbach how can i contribute to the samples ?, an azure function with complete OTEL impl.

   .ConfigureLogging(logging =>
   {
       logging.AddOpenTelemetry(loggingOptions =>
       {
           loggingOptions.IncludeFormattedMessage = true;
           loggingOptions.IncludeScopes = true;
           loggingOptions.ParseStateValues = true;
           loggingOptions.AddConsoleExporter();
           loggingOptions.AddAzureMonitorLogExporter(e => e.ConnectionString = appInsightsConnectionString);
       });
   })
 

Hi Nen,

Our samples are all open source and available under docs.particular.net/samples at master · Particular/docs.particular.net · GitHub. You could raise an issue in that repository and then submit a PR with your proposed changes and we will have a look at it.

Does that help?

Regards
Daniel