-
-
Save johndowns/9158c048cb7cd5c204d28e55ac317829 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", | |
"contentVersion": "1.0.0.0", | |
"parameters": { | |
"uniqueResourceNameSuffix": { | |
"type": "string", | |
"defaultValue": "[uniqueString(subscription().subscriptionId, resourceGroup().id)]", | |
"metadata": { | |
"description": "The suffix to add to resource names that require global uniqueness." | |
} | |
} | |
}, | |
"variables": { | |
"functionsAppServicePlanName": "MonitoringFunctions", | |
"functionsAppName": "[concat('fn', parameters('uniqueResourceNameSuffix'))]", | |
"queueStorageAccountName": "[concat('q', parameters('uniqueResourceNameSuffix'))]", | |
"queueStorageAccountResourceId": "[resourceId('Microsoft.Storage/storageAccounts', variables('queueStorageAccountName'))]", | |
"functionsStorageAccountName": "[concat('fn', parameters('uniqueResourceNameSuffix'))]", | |
"functionsStorageAccountResourceId": "[resourceId('Microsoft.Storage/storageAccounts', variables('functionsStorageAccountName'))]", | |
"monitoringMetricsPublisherRoleAssignmentId": "34291c23-a1d5-4989-bb4a-85e27d539729", | |
"monitoringMetricsPublisherRoleDefinitionId": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '3913510d-42f4-4e42-8a64-420c390055eb')]", | |
"roleAssignmentScope": "[resourceGroup().id]" | |
}, | |
"resources": [ | |
{ | |
"name": "[variables('queueStorageAccountName')]", | |
"type": "Microsoft.Storage/storageAccounts", | |
"location": "[resourceGroup().location]", | |
"apiVersion": "2018-02-01", | |
"sku": { | |
"name": "Standard_LRS" | |
}, | |
"kind": "StorageV2", | |
"properties": { | |
"accessTier": "Hot", | |
"supportsHttpsTrafficOnly": true, | |
"encryption": { | |
"services": { | |
"blob": { | |
"enabled": true | |
} | |
}, | |
"keySource": "Microsoft.Storage" | |
} | |
} | |
}, | |
{ | |
"name": "[variables('functionsStorageAccountName')]", | |
"type": "Microsoft.Storage/storageAccounts", | |
"location": "[resourceGroup().location]", | |
"apiVersion": "2018-02-01", | |
"sku": { | |
"name": "Standard_LRS" | |
}, | |
"kind": "StorageV2", | |
"properties": { | |
"accessTier": "Hot", | |
"supportsHttpsTrafficOnly": true, | |
"encryption": { | |
"services": { | |
"blob": { | |
"enabled": true | |
} | |
}, | |
"keySource": "Microsoft.Storage" | |
} | |
} | |
}, | |
{ | |
"name": "[variables('functionsAppServicePlanName')]", | |
"type": "Microsoft.Web/serverfarms", | |
"location": "[resourceGroup().location]", | |
"apiVersion": "2016-09-01", | |
"sku": { | |
"name": "Y1", | |
"tier": "Dynamic", | |
"size": "Y1", | |
"family": "Y", | |
"capacity": 0 | |
}, | |
"kind": "functionapp", | |
"properties": { | |
"workerTierName": null, | |
"adminSiteName": null, | |
"hostingEnvironmentProfile": null, | |
"perSiteScaling": false, | |
"reserved": false, | |
"targetWorkerCount": 0, | |
"targetWorkerSizeId": 0 | |
} | |
}, | |
{ | |
"name": "[variables('functionsAppName')]", | |
"type": "Microsoft.Web/sites", | |
"location": "[resourceGroup().location]", | |
"apiVersion": "2016-08-01", | |
"kind": "functionapp", | |
"properties": { | |
"enabled": true, | |
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('functionsAppServicePlanName'))]", | |
"reserved": false, | |
"siteConfig": { | |
"ftpsState": "Disabled" | |
} | |
}, | |
"identity": { | |
"type": "SystemAssigned" | |
}, | |
"resources": [ | |
{ | |
"name": "appsettings", | |
"type": "config", | |
"apiVersion": "2014-11-01", | |
"properties": { | |
"FUNCTIONS_EXTENSION_VERSION": "~2", | |
"AzureWebJobsDashboard": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('functionsStorageAccountName'), ';AccountKey=', listKeys(variables('functionsStorageAccountResourceId'),'2015-05-01-preview').key1)]", | |
"AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('functionsStorageAccountName'), ';AccountKey=', listKeys(variables('functionsStorageAccountResourceId'),'2015-05-01-preview').key1)]", | |
"QueueStorageAccountResourceId": "[resourceId('Microsoft.Storage/storageAccounts', variables('queueStorageAccountName'))]", | |
"QueueStorageAccountResourceRegionId": "[reference(resourceId('Microsoft.Storage/storageAccounts', variables('queueStorageAccountName'))).primaryLocation]", | |
"QueueStorageAccountConnectionString": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('queueStorageAccountName'), ';AccountKey=', listKeys(variables('queueStorageAccountResourceId'),'2015-05-01-preview').key1)]" | |
}, | |
"dependsOn": [ | |
"[resourceId('Microsoft.Web/sites', variables('functionsAppName'))]", | |
"[resourceId('Microsoft.Storage/storageAccounts', variables('functionsStorageAccountName'))]", | |
"[resourceId('Microsoft.Storage/storageAccounts', variables('queueStorageAccountName'))]" | |
] | |
}, | |
{ | |
"name": "PublishQueueLength", | |
"type": "functions", | |
"apiVersion": "2015-08-01", | |
"properties": { | |
"config": { | |
"bindings": [ | |
{ | |
"name": "timer", | |
"type": "timerTrigger", | |
"direction": "in", | |
"schedule": "0 */5 * * * *" | |
} | |
], | |
"disabled": false | |
}, | |
"files": { | |
"run.csx": "#r \"Newtonsoft.Json\"\r\n\r\nusing System.Collections.Generic;\r\nusing System.Net.Http;\r\nusing System.Net.Http.Headers;\r\nusing System.Threading;\r\nusing Microsoft.Azure.Services.AppAuthentication;\r\nusing Newtonsoft.Json;\r\nusing Microsoft.WindowsAzure.Storage;\r\nusing Microsoft.WindowsAzure.Storage.Queue;\r\n\r\nprivate static HttpClient HttpClient = new HttpClient();\r\nprivate static AzureServiceTokenProvider AzureServiceTokenProvider = new AzureServiceTokenProvider();\r\nprivate static string QueueStorageAccountResourceId = System.Environment.GetEnvironmentVariable(\"QueueStorageAccountResourceId\");\r\nprivate static string QueueStorageAccountResourceRegionId = System.Environment.GetEnvironmentVariable(\"QueueStorageAccountResourceRegionId\");\r\nprivate static string QueueStorageAccountConnectionString = System.Environment.GetEnvironmentVariable(\"QueueStorageAccountConnectionString\");\r\nprivate const string MetricName = \"QueueLength\";\r\nprivate const string MetricNamespace = \"QueueProcessing\";\r\n\r\npublic static async Task Run(TimerInfo timer, ILogger log)\r\n{\r\n \/\/ connect to the storage account\r\n var storageAccount = CloudStorageAccount.Parse(QueueStorageAccountConnectionString);\r\n var queueClient = storageAccount.CreateCloudQueueClient();\r\n\r\n \/\/ list the queues in the account\r\n var queues = new List<CloudQueue>();\r\n QueueContinuationToken continuationToken = null;\r\n do\r\n {\r\n var segment = await queueClient.ListQueuesSegmentedAsync(continuationToken);\r\n queues.AddRange(segment.Results);\r\n continuationToken = segment.ContinuationToken;\r\n } while (continuationToken != null);\r\n\r\n if (!queues.Any())\r\n {\r\n log.LogInformation(\"There are no queues to process.\");\r\n return;\r\n }\r\n\r\n log.LogInformation(\"Found {queueCount} queues.\", queues.Count());\r\n\r\n \/\/ get the message count from each queue\r\n var queueSummaries = new List<(string queueName, int? queueLength)>();\r\n foreach (var queue in queues)\r\n {\r\n await queue.FetchAttributesAsync();\r\n queueSummaries.Add((queue.Name, queue.ApproximateMessageCount));\r\n }\r\n\r\n \/\/ prepare a metric to publish\r\n var metric = new Metric\r\n {\r\n Time = DateTime.UtcNow,\r\n Data = new MetricData\r\n {\r\n BaseData = new MetricBaseData\r\n {\r\n Metric = MetricName,\r\n Namespace = MetricNamespace,\r\n DimNames = new string[] {\r\n \"QueueName\"\r\n },\r\n Series = queueSummaries.Select(qs => {\r\n if (qs.queueLength == null)\r\n {\r\n return null;\r\n }\r\n else\r\n {\r\n return new MetricSeries {\r\n DimValues = new[] { \r\n qs.queueName\r\n },\r\n Min = qs.queueLength.Value,\r\n Max = qs.queueLength.Value,\r\n Sum = qs.queueLength.Value,\r\n Count = 1\r\n };\r\n }\r\n }).Where(qs => qs != null)\r\n }\r\n }\r\n };\r\n\r\n \/\/ publish the metric to Azure Monitor\r\n await PublishMetric(metric);\r\n}\r\n\r\npublic static async Task PublishMetric(Metric metric)\r\n{\r\n var metricJson = JsonConvert.SerializeObject(metric);\r\n var stringContent = new StringContent(metricJson, System.Text.Encoding.Default, \"application\/json\");\r\n var token = await AzureServiceTokenProvider.GetAccessTokenAsync(\"https:\/\/monitoring.azure.com\/\");\r\n HttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(\"Bearer\", token);\r\n var monitoringUri = $\"https:\/\/{QueueStorageAccountResourceRegionId}.monitoring.azure.com{QueueStorageAccountResourceId}\/metrics\";\r\n var result = await HttpClient.PostAsync(monitoringUri, stringContent);\r\n result.EnsureSuccessStatusCode();\r\n}\r\n\r\npublic class Metric\r\n{\r\n public DateTime Time { get; set; }\r\n public MetricData Data { get; set; }\r\n}\r\n\r\npublic class MetricData\r\n{\r\n public MetricBaseData BaseData { get; set; }\r\n}\r\n\r\npublic class MetricBaseData\r\n{\r\n public string Metric { get; set; }\r\n public string Namespace { get; set; }\r\n public IEnumerable<string> DimNames { get; set; }\r\n public IEnumerable<MetricSeries> Series { get; set; }\r\n}\r\n\r\npublic class MetricSeries\r\n{\r\n public IEnumerable<string> DimValues { get; set;}\r\n public double Min { get; set; }\r\n public double Max { get; set; }\r\n public double Sum { get; set; }\r\n public int Count { get; set; }\r\n}", | |
"function.proj": "<Project Sdk=\"Microsoft.NET.Sdk\">\r\n <PropertyGroup>\r\n <TargetFramework>netstandard2.0<\/TargetFramework>\r\n <\/PropertyGroup>\r\n <ItemGroup>\r\n <PackageReference Include=\"Microsoft.Azure.Services.AppAuthentication\" Version=\"1.0.3\"\/>\r\n <PackageReference Include=\"WindowsAzure.Storage\" Version=\"9.3.3\"\/>\r\n <\/ItemGroup>\r\n<\/Project>\r\n" | |
} | |
}, | |
"dependsOn": [ | |
"[resourceId('Microsoft.Web/sites', variables('functionsAppName'))]" | |
] | |
} | |
], | |
"dependsOn": [ | |
"[resourceId('Microsoft.Web/serverfarms', variables('functionsAppServicePlanName'))]" | |
] | |
}, | |
{ | |
"name": "[variables('monitoringMetricsPublisherRoleAssignmentId')]", | |
"type": "Microsoft.Authorization/roleAssignments", | |
"apiVersion": "2018-01-01-preview", | |
"properties": { | |
"roleDefinitionId": "[variables('monitoringMetricsPublisherRoleDefinitionId')]", | |
"principalId": "[reference(resourceId('Microsoft.Web/sites', variables('functionsAppName')), '2016-08-01', 'Full').identity.principalId]", | |
"scope": "[variables('roleAssignmentScope')]" | |
}, | |
"dependsOn": [ | |
"[resourceId('Microsoft.Web/sites', variables('functionsAppName'))]" | |
] | |
} | |
] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment