Home > Software engineering >  OpenTelemetry & correlation support for Azure Functions
OpenTelemetry & correlation support for Azure Functions

Time:10-25

I have a project written in .net 6. I use Azure Function to send data to Service bus and MediatR. How can I add Open Telemetry to my Azure functions?

[Function("EBcktErroredFunction")]
  public Task EBcktErroredFunctionAsync([ServiceBusTrigger("e-bckt-errored", "bckts-creation-finalize")] EBcktErrored payload)
  {
    return _mediator.Send(
      new SyncBcktErroredToStoreCommand
      {
        SBcktId = payload.BcktId,
        EBcktId = payload.ExternalBcktId
      }
    );

Not related but in the bicep file it looks like this;

resource eBcktErroredSubscription 'Microsoft.ServiceBus/namespaces/topics/subscriptions' = {
  name: '${serviceBusName}/e-bckt-errored/${appName}'
  properties: {
    autoDeleteOnIdle: ''
    deadLetteringOnMessageExpiration: 
    defaultMessageTimeToLive: ''
    enableBatchedOperations: true
    lockDuration: ''
  }
}

CodePudding user response:

You can find a full example on GitHub and a corresponding discussion about "Using OpenTelemetry Sdk with Azure Functions".

Most relevant code (you should look at the full code for reference):

    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            // OpenTelemetry Resource to be associated with logs, metrics and traces
            var openTelemetryResourceBuilder = ResourceBuilder.CreateDefault().AddService("opentelemetry-service");

            // Enable Logging with OpenTelemetry
            builder.Services.AddLogging( (loggingBuilder) => 
                {
                    // Only Warning or above will be sent to Opentelemetry
                    loggingBuilder.AddFilter<OpenTelemetryLoggerProvider>("*", LogLevel.Warning);
                }
            );
            
            builder.Services.AddSingleton<ILoggerProvider, OpenTelemetryLoggerProvider>();
            builder.Services.Configure<OpenTelemetryLoggerOptions>( (openTelemetryLoggerOptions) =>
                {
                    openTelemetryLoggerOptions.SetResourceBuilder(openTelemetryResourceBuilder);
                    openTelemetryLoggerOptions.IncludeFormattedMessage = true;
                    openTelemetryLoggerOptions.AddConsoleExporter();
                }
            );

            // Enable Tracing with OpenTelemetry
            var openTelemetryTracerProvider = Sdk.CreateTracerProviderBuilder()
                .SetResourceBuilder(openTelemetryResourceBuilder)
                .SetSampler(new AlwaysOnSampler())
                .AddAspNetCoreInstrumentation()
                .AddConsoleExporter()
                .Build();
            builder.Services.AddSingleton(openTelemetryTracerProvider);

            // Enable Metrics with OpenTelemetry
            var openTelemetryMeterProvider = Sdk.CreateMeterProviderBuilder()
                .SetResourceBuilder(openTelemetryResourceBuilder)
                .AddAspNetCoreInstrumentation()
                .AddMeter(Function1.MyMeter.Name)
                .AddConsoleExporter(consoleOptions =>
                    {
                        consoleOptions.MetricReaderType = MetricReaderType.Periodic;
                        consoleOptions.AggregationTemporality = AggregationTemporality.Cumulative;
                        consoleOptions.PeriodicExportingMetricReaderOptions.ExportIntervalMilliseconds = 10000;
                    })
                .Build();
            builder.Services.AddSingleton(openTelemetryMeterProvider);
        [FunctionName("Function1")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogWarning("C# HTTP trigger function processed a request.");
            MyCounter.Add(1, new("name", "apple"), new("color", "red"));

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

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

            string responseMessage = string.IsNullOrEmpty(name)
                ? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
                : $"Hello, {name}. This HTTP triggered function executed successfully.";

            log.LogWarning("Name is {name}", name);
            Activity.Current?.SetTag("name", name);

            return new OkObjectResult(responseMessage);
        }
  • Related