Skip to content

ARM Templates - Deploying Azure Functions with Application Insights

2018-02-04

Manual Azure Function configuration for Application Insights Your Azure Functions,full stop, need to have telemetry. This post is not here to debate that issue. What I would like to share is a way to stand up your Azure Function, App Service Plan, Storage Account and a Application Insights in a single deployment via Azure Resource Manager.

Silvrback blog image sb_float_center

If you would like to hire me for pasting logos together I would suggest that you please contact the amazing David Neal @ReverentGeek for his amazing work with the digital pen.

Under the category of an Azure services deployment of your functions you can add this to the portal is fairly trivial. If you are not yet in a position to use an ARM Template for an Infrastructure as Code deployment you can update an existing resource group with support. If you don't have an Application Insights resource, create an instance and add an AppInsights_InstrumentationKey application settings key to your Azure Functions container instance.

Silvrback blog image sb_float_center

and in your AppSettings

Silvrback blog image sb_float_center

This will take the placeholder Application Insight placeholder Live Stream page from this

Silvrback blog image sb_float_center

To this live dashboard views where you can see your Function execution TraceWriter entries log.Info("C# HTTP trigger function processed a request.");

Silvrback blog image sb_float_center

Function completed (Success, Id=c0702774-4379-4037-8a80-194b65e87ea4, Duration=79ms)
C# HTTP trigger function processed a request.
Function started (Id=c0702774-4379-4037-8a80-194b65e87ea4)

At this point you can continue to expand on how your leverage App Insights in your functions to track timing, usage, and othe real-time statistics

Automatic Azure Function configuration for Application Insights

This part of almost borning to look at but when you consider how your punchlist of manual configuration changes its brevity will hopefully be excused.

The top level ARM resource is going to start out with the Application Insights service

{
  "type": "microsoft.insights/components",
  "kind": "other",
  "name": "[variables('appInsightsServiceName')]",
  "apiVersion": "2014-04-01",
  "location": "[parameters('appInsightsLocation')]",
  "tags": {},
  "scale": null,
  "properties": {
      "ApplicationId": "[variables('appInsightsServiceName')]"
  },
  "dependsOn": []
}

Take note that Application Insights doesn't not have the same resource group locations available to it as other resources in Azure. This is why in my template I have a specific parameter that sets the location for AppInsights instead of a standard entry of [resourceGroup().location]

Below is a example of a top-level ARM resource for a Functions app without the required App Service Plan, Storage Account and the Application Insights resources

{
    "type": "Microsoft.Web/sites",
    "kind": "functionapp",
    "name": "[variables('webAppName')]",
    "apiVersion": "2016-08-01",
    "location": "[resourceGroup().location]",
    "scale": null,
    "properties": {
        "name": "[variables('webAppName')]",
        "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]",
        "clientAffinityEnabled": false,
        "siteConfig": {
            "appSettings": [
                {
                    "name": "AzureWebJobsDashboard",
                    "value": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1)]"
                },
                {
                    "name": "AzureWebJobsStorage",
                    "value": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1)]"
                },
                {
                    "name": "FUNCTIONS_EXTENSION_VERSION",
                    "value": "~1"
                },
                {
                    "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
                    "value": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1)]"
                },
                {
                    "name": "WEBSITE_CONTENTSHARE",
                    "value": "[concat(toLower(variables('webAppName')))]"
                },
                {
                    "name": "WEBSITE_NODE_DEFAULT_VERSION",
                    "value": "6.5.0"
                },
                {
                    "name": "AppInsights_InstrumentationKey",
                    "value": "[reference(concat('microsoft.insights/components/', variables('appInsightsServiceName'))).InstrumentationKey]"
                }
            ]
        }
    },
    "dependsOn": [
        "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]",
        "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]",
        "[resourceId('microsoft.insights/components', variables('appInsightsServiceName'))]"
    ]
}
One of the JSON patterns for getting application settings values is through properties/siteConfig/appSettings which hold an array of name/value objects. This is where the Application Insights Instrumentation Key comes from, for free:

{
  "name": "AppInsights_InstrumentationKey",
  "value": "[reference(concat('microsoft.insights/components/', variables('appInsightsServiceName'))).InstrumentationKey]"
}

In the example I am also grabbing the storage account information for use in the AzureWebJobsDashboard, AzureWebJobsStorage and Website_ContentAzureFileConnectionString values.

Once this is deployed you have a Azure Functions container, Storage Account and Application Insights instance that is ready to accept telemetry readings once your deploy your actual Azure Functions application.