Skip to content

Latest commit

 

History

History
329 lines (196 loc) · 18.4 KB

DEMO.md

File metadata and controls

329 lines (196 loc) · 18.4 KB

Demo

The demo requires an Azure Service Bus namespace to run. Functions can run both locally and in Azure, when running locally I recommend stopping the Functions deployed in Azure otherwise the Service Bus triggers will compete for messages.

Before being able to deploy and run the Functions you will need to have the below software installed:

You'll first need to run build.ps1 --package to publish the Functions to file system.

Run Deploy.ps1 to deploy the project to Azure. This will deploy:

  • A Workspace based Application Insights instance
  • A basic Service Bus namespace
  • Five Function Apps and their supporting storage accounts
.\deploy\Deploy.ps1 -Location {AzureRegion} -ResourceNamePrefix {UniquePrefix}

The project contains five Functions Apps:

  • DefaultV3InProcessFunction and DefaultV4InProcessFunction demonstrate the quirks of in-process Azure Functions v3 / v4 Application Insights integration
  • CustomV3InProcessFunction and CustomV4InProcessFunction demonstrate the workarounds I use to improve in-process Azure Functions v3 / v4 Application Insights integration
  • DefaultV4IsolatedFunction demonstrates the quirks of an isolated Azure Function v4

I've decided to commit the local.settings.json file. This is not the default or recommended approach but it makes it easier for new joiners to get started.

You can start the Function Apps by issuing the below commands from the root of repository:

cd .\samples\DefaultV3InProcessFunction\
func start
cd .\samples\DefaultV4InProcessFunction\
func start
cd .\samples\CustomV3InProcessFunction\
func start
cd .\samples\CustomV4InProcessFunction\
func start
cd .\samples\DefaultV4IsolatedFunction\
func start

The Function Apps run on fixed ports locally so that you can run all five Functions at the same time:

  • Default in-process v3: 7071
  • Default in-process v4: 7073
  • Custom in-process v3: 7072
  • Custom in-process v4: 7074
  • Default isolated v4: 7075

You can call the different endpoints using this Postman collection.

AvailabilityFunction

Navigate to http://localhost:7074/availability (Custom in-process v4) in your favourite browser.

Emits an availability telemetry item. This is normally emitted by tooling such as Application Insights URL ping test. The reason I'm emitting it manually is to demonstrate that the telemetry processors are called for availability telemetry items.

CustomEventFunction

You'll need to delete the Application Insights connection string secret in order to reproduce the error. Stop all the Functions and then run:

dotnet user-secrets list --id 074ca336-270b-4832-9a1a-60baf152b727

Make a note of the value of the APPLICATIONINSIGHTS_CONNECTION_STRING secret, then delete it:

dotnet user-secrets remove APPLICATIONINSIGHTS_CONNECTION_STRING `
    --id 074ca336-270b-4832-9a1a-60baf152b727

Navigate to http://localhost:7073/event (Default in-process v4) in your favourite browser.

Demonstrate that when the secret APPLICATIONINSIGHTS_CONNECTION_STRING is not set, attempting to retrieve TelemetryConfiguration from the container results in an exception:

Default in-process: without the secret APPLICATIONINSIGHTS_CONNECTION_STRING, TelemetryConfiguration is not registered and an exception is thrown

📝 When using ASP.NET Core, TelemetryConfiguration is registered by calling AddApplicationInsightsTelemetry() in Startup.cs but this method should not be called in Azure Functions:

Don't add AddApplicationInsightsTelemetry() to the services collection, which registers services that conflict with services provided by the environment.

Navigate to http://localhost:7074/event (Custom in-process v4) in your favourite browser.

Demonstrate that when the secret APPLICATIONINSIGHTS_CONNECTION_STRING is not set, attempting to retrieve TelemetryConfiguration from the container does not result in an exception because I register a no-op TelemetryConfiguration if one was not registered already:

Custom in-process: without the secret APPLICATIONINSIGHTS_CONNECTION_STRING, TelemetryConfiguration is registered and no exception is thrown

This has been fixed for the isolated mode: http://localhost:7075/event.

Finally once done, you can add the secret again:

dotnet user-secrets set APPLICATIONINSIGHTS_CONNECTION_STRING '{YourConnectionString}' `
    --id 074ca336-270b-4832-9a1a-60baf152b727

DependencyFunction

Navigate to http://localhost:7073/dependency (Default in-process v4) in your favourite browser.

Four telemetry items are recorded:

  • The request itself
  • The Executing ... and Executed ... traces
  • The custom dependency we've manually tracked

Dependency Function in-process default telemetry

Navigate to http://localhost:7074/dependency (Custom in-process v4) in your favourite browser.

Only the request is recorded:

  • The Executing ... and Executed ... traces have been discarded by the FunctionExecutionTracesFilter
  • The custom dependency we've manually tracked has been discarded by the CustomHttpDependencyFilter

Dependency Function in-process custom telemetry

Isolated mode supports telemetry processors (except for request telemetry items). Navigate to http://localhost:7075/dependency.

Four telemetry items are recorded:

  • The request itself
  • The Executing ... and Executed ... traces
  • The Invoke dependency (the host calling our Function)
  • The custom dependency we've manually tracked has been discarded by the CustomHttpDependencyFilter

Dependency Function isolated telemetry

The CustomHttpDependencyFilter discards a specific telemetry type. This is useful when having a noisy dependency. You can tweak the processor to only discard successful or fast dependencies.

🚨 Discarding telemetry items skews the statistics. Consider using sampling instead.

HealthFunction

To keep Function Apps on a consumption plan alive and limit the number of cold starts, I tend to use Application Insights URL ping test. This results in many requests being recorded in Application Insights.

📝 HEAD is more commonly used than GET for ping tests but it is easier to issue a GET with a web browser.

Navigate to http://localhost:7073/health (Default in-process v4) in your favourite browser. The Health request is recorded in Application Insights.

Navigate to http://localhost:7074/health (Custom in-process v4) in your favourite browser. The Health request is discarded by the HealthRequestFilter which is configured by the application setting ApplicationInsights:HealthCheckFunctionName.

Navigate to http://localhost:7075/health (Isolated v4) in your favourite browser. The Health request is recorded in Application Insights despite having a telemetry processor attempting to discard it. This is because request telemetry items are emitted by the host and the HealthRequestFilter applies to the worker.

HttpExceptionThrowingFunction

Navigate to http://localhost:7073/http-exception (Default v4) in your favourite browser.

Demonstrates that the stack trace is not present in the console logs when an exception is thrown.

In-process default: no stack trace in the console when an exception is thrown

This also proves that the same exception appears twice in Application Insights:

In-process default: the same exception is logged twice for the HTTP binding

Navigate to http://localhost:7074/http-exception (Custom v4) in your favourite browser.

Demonstrates that the stack trace is present in the console logs when an exception is thrown.

In-process custom: stack trace present in the console when an exception is thrown

This also proves that the same exception appears only once in Application Insights:

In-process custom: the same exception is logged only once for the HTTP binding

Navigate to http://localhost:7075/http-exception (Isolated v4) in your favourite browser.

The stack trace is present in the console logs when an exception is thrown (this is a welcome improvement).

Isolated: stack trace present in the console when an exception is thrown

The same exception appears twice in Application Insights. Note that this is an RpcException thrown by the host, which makes the Problem Id useless for filtering.

Isolated: the same exception is logged twice for the HTTP binding

ProcessorFunction

Navigate to http://localhost:7073/processor (Default v4) in your favourite browser.

Demonstrates that our TelemetryCounterProcessor telemetry processor is not being called even though I added it using AddApplicationInsightsTelemetryProcessor.

In-process default: our telemetry processor is not being called for requests

Navigate to http://localhost:7074/processor (Custom v4) in your favourite browser.

Demonstrates that our TelemetryCounterProcessor telemetry processor is being called:

In-process custom: our telemetry processor is even being called for requests

Note that the processor is also called for request telemetry items. When running in Azure you might get different results on each request as you might be hitting different instances and the state is kept in-memory.

Unfortunately, our TelemetryCounterProcessor is called for all telemetry item types except for requests for the Isolated v4 Function (http://localhost:7075/processor):

Isolated: our telemetry processor is being called for all but requests

ServiceBusFunction

You can send a message to the defaultv4inprocess-queue queue using the Service Bus Explorer in the Azure Portal or you can navigate to http://localhost:7073/service-bus (Default v4) in your favourite browser.

The Default Function does not have a URL or a Response code:

In-process default Service Bus binding: no URL and no response code

Four telemetry items are recorded for the Default Function execution:

  • The request itself
  • The Executing ... and Executed ... traces
  • The Trigger Details ... trace

In-process default Service Bus binding: telemetry

You can send a message to the customv4inprocess-queue queue using the Service Bus Explorer in the Azure Portal or you can navigate to http://localhost:7074/service-bus (Custom v4) in your favourite browser.

The Custom Function has both the Request URL and Response code set by ServiceBusRequestInitializer:

In-process custom Service Bus binding: URL and response code are set

Only the request is recorded for the Custom Function execution:

  • The Executing ... and Executed ... traces have been discarded by the FunctionExecutionTracesFilter
  • The Trigger Details ... trace has been discarded by the ServiceBusTriggerFilter (configured by setting the application setting ApplicationInsights:DiscardServiceBusTrigger)

You can send a message to the defaultv4isolated-queue queue using the Service Bus Explorer in the Azure Portal or you can navigate to http://localhost:7075/service-bus (Isolated v4) in your favourite browser.

The Default Isolated Function does not have a URL or a Response code:

Isolated Service Bus binding: no URL and no response code

Five telemetry items are recorded for the Default Isolated Function execution:

  • The request itself
  • The Executing ... and Executed ... traces
  • The Trigger Details ... trace
  • The Invoke dependency (the host calling our Function)

Isolated Service Bus binding: telemetry

ServiceBusExceptionThrowingFunction

You can send a message to the defaultv4inprocess-exception-queue queue using the Service Bus Explorer in the Azure Portal or you can navigate to http://localhost:7073/service-bus-exception (Default v4) in your favourite browser.

Demonstrate that a single exception thrown by the Function is recorded three times in Application Insights and that a total of nine telemetry items are emitted during the Function execution.

In-process default Service Bus binding exception: nine telemetry items emitted by the Functions runtime

You can send a message to the customv4inprocess-exception-queue queue using the Service Bus Explorer in the Azure Portal or you can navigate to http://localhost:7074/service-bus-exception (Custom v4) in your favourite browser.

Demonstrate that a single exception thrown by the Function is recorded only once in Application Insights and that a total of three telemetry items are emitted during the Function execution.

In-process custom Service Bus binding exception: three telemetry items emitted by the Functions runtime

You can send a message to the defaultv4isolated-exception-queue queue using the Service Bus Explorer in the Azure Portal or you can navigate to http://localhost:7075/service-bus-exception (Isolated v4) in your favourite browser.

Demonstrate that a single exception thrown by the Function is recorded four times in Application Insights and that a total of eleven telemetry items are emitted during the Function execution.

Isolated Service Bus binding exception: eleven telemetry items emitted by the Functions runtime

TraceLogFunction

Navigate to http://localhost:7073/trace-log (Default v4) / http://localhost:7074/trace-log (Custom v4) / http://localhost:7075/trace-log (Isolated v4) in your favourite browser.

Demonstrate that log events are not filtered before being sent to Live Metrics. This is not a limitation of Azure Functions, that's how Application Insights works and something you need to be aware of.

A Trace log event is displayed in the Live Metrics

UserSecretFunction

Navigate to http://localhost:7073/secret (Default v4) / http://localhost:7074/secret (Custom v4) / http://localhost:7075/secret (Isolated v4) in your favourite browser.

Demonstrates that Azure Functions can use the Secret Manager when running locally.

Application Version and Cloud Role Name

By default, the Application Version is not set, and the Cloud Role Name will be the Function App Azure resource name:

Default Cloud Role Name and Application Version

For the custom Function, each telemetry will be stamped with the Assembly Informational Version and the configured application name:

Custom Cloud Role Name and Application Version

Discarding SystemTraceMiddleware logs

The SystemTraceMiddleware emits two log events per HTTP Function execution when running an in-process v3 / v4 Function locally:

SystemTraceMiddleware: two log events per HTTP Function execution when running locally

These can be suppressed by adding the below Value to local.settings.json (not host.json):

"logging:logLevel:Microsoft.Azure.WebJobs.Script.WebHost.Middleware.SystemTraceMiddleware": "None"

SystemTraceMiddleware: suppressed logs

Anthony Chu has documented how to suppress some logs.