Element.Azure.Functions.Worker.Extensions.HttpTelemetry 1.1.0

dotnet add package Element.Azure.Functions.Worker.Extensions.HttpTelemetry --version 1.1.0
                    
NuGet\Install-Package Element.Azure.Functions.Worker.Extensions.HttpTelemetry -Version 1.1.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Element.Azure.Functions.Worker.Extensions.HttpTelemetry" Version="1.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Element.Azure.Functions.Worker.Extensions.HttpTelemetry" Version="1.1.0" />
                    
Directory.Packages.props
<PackageReference Include="Element.Azure.Functions.Worker.Extensions.HttpTelemetry" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Element.Azure.Functions.Worker.Extensions.HttpTelemetry --version 1.1.0
                    
#r "nuget: Element.Azure.Functions.Worker.Extensions.HttpTelemetry, 1.1.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Element.Azure.Functions.Worker.Extensions.HttpTelemetry@1.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Element.Azure.Functions.Worker.Extensions.HttpTelemetry&version=1.1.0
                    
Install as a Cake Addin
#tool nuget:?package=Element.Azure.Functions.Worker.Extensions.HttpTelemetry&version=1.1.0
                    
Install as a Cake Tool

HTTP success/failure logging for Isolated Azure Functions

Provides standard HTTP request logging handling for Azure Functions running in Isolated mode so that 4xx and 5xx responses are logged as Failures in AppInsights.

Usage

Add the Element.Azure.Functions.Worker.Extensions.HttpTelemetry Nuget package to your Isolated Azure Functions project.

NOTE: Due to how the Azure Functions metadata generator works, you must actually use the extension in a function declaration. To meet that requirement, you must add the [HttpTelemetry] input binding attribute to any one of your HttpTrigger functions (does not need to be all of them):

[Function("Ping")]
public HttpResponseData Ping([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "ping")] HttpRequestData req, [HttpTelemetry] object ignore)
{
    // ... your code ...
}

How does it work?

As far as functions are concerned, there is no difference between and HttpTrigger and any other function trigger type. So even if your HttpTrigger returns a 4xx or 5xx error, the function itself was still successful (it returned exactly what you told it to do without error). So in AppInsights, these request show up as Success regardless of the HTTP response status code.

In ASP.NET Core and other web app technologies, HTTP response codes like this are treated as unsuccessful and hence show up in AppInsights logs in the 'Failures' blade. This package aims to make isolated functions log HTTP requests in this manner.

In the in-process model, the solution was to register an ITelemetryInitializer with the IServiceCollection and then you could watch for RequestTelemetry and modify the Success property based on the response code.

However, in the the isolated functions model, the functions host and your functions code run as two separate processes. The functions host recieves the incoming request then communicates with your worker process via gRPC. Although some telemetry data can be handled in the worker, only the host handles the RequestTelemetry. So even if you register an ITelemetryInitializer in your worker, you will never receive any RequestTelemetry events. The only way to get access to the RequestTelemetry is to do it from the host.

Unfortunately, the code you write in your function app only runs in the worker process and there is no way to 'reach into' the host to modify its behavior.

Except, there is. And it is via Binding Extensions.

Binding extensions are ways to add your own custom trigger types, input bindings, and output bindings. In order to allow them to work, they also have to run in the host. So this solution creates a custom extension that allows code (in this case, code to register the ITelemetryInitializer and convert the RequestTelemetry Success property) to run on the host.

One limitation of extensions is that they are only geared towards bindings. As such, your function app code must make use of at least one binding from your extension or else the function extension metadata generator will strip out the extension information from the generated host code. That is why the [HttpTelemetry] input binding attribute needs to be applied somewhere in a function in your function app - it doesnt do anything, other than prevent the rest of the extension code from being complied out.

The actual mechanisms of how extensions work is:

  • you add a reference to a worker extension library (in this case: Element.Azure.Functions.Worker.Extensions.HttpTelemetry available via Nuget)
  • that worker extension library has an [ExtensionInformation] attribute that points to a different Nuget package that contains the actual logic which will be injected into the host (in this case: Element.Azure.WebJobs.Extensions.HttpTelemetry, which is also available on Nuget but should not be referenced directly from your function app)
  • when you compile your function app, the function metadata generator scans your code for binding extensions, creates a temporary .csproj file, and outputs the necessary .dlls and and emits an extensions.json file with metadata about your extension and the entry points

You don't need to know any of that in order to take advantage of this package, but it might be interesting to know what is going on under the hood.

References

Credit goes to Maarten Balliauw for documenting how to write custom extensions for isolated functions. It was invaluable in understanding how things worked internally.

The source code for the functions metadata generator (where you can see how items are stripped out if not used) is also interesting reading.

The source code for the Microsoft-provided extensions was also a great reference, as was the Dapr extension source code.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.1.0 300 2/24/2025
1.0.3 29,949 12/5/2023
1.0.2 203 12/4/2023
1.0.1 223 10/12/2023