From d0aeaeabc9fd505aab9da5f04fd703b46e8b67de Mon Sep 17 00:00:00 2001 From: "Martin Hinshelwood nkdAgility.com" Date: Thu, 5 Sep 2024 17:38:12 +0100 Subject: [PATCH 1/4] Update getting started config to be really simple. --- .../configuration-getstarted.json | 38 +++++++++++++++++++ docs/getstarted/index.md | 2 +- 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 docs/_includes/sampleConfig/configuration-getstarted.json diff --git a/docs/_includes/sampleConfig/configuration-getstarted.json b/docs/_includes/sampleConfig/configuration-getstarted.json new file mode 100644 index 000000000..fb31682fb --- /dev/null +++ b/docs/_includes/sampleConfig/configuration-getstarted.json @@ -0,0 +1,38 @@ +{ + "Serilog": { + "MinimumLevel": "Information" + }, + "MigrationTools": { + "Version": "16.0", + "Endpoints": { + "Source": { + "EndpointType": "TfsTeamProjectEndpoint", + "Collection": "https://dev.azure.com/nkdagility-preview/", + "Project": "migrationSource1", + "Authentication": { + "AuthenticationMode": "AccessToken", + "AccessToken": "jkashdjksahsjkfghsjkdaghvisdhuisvhladvnb" + } + }, + "Target": { + "EndpointType": "TfsTeamProjectEndpoint", + "Collection": "https://dev.azure.com/nkdagility-preview/", + "Project": "migrationTest5", + + "Authentication": { + "AuthenticationMode": "AccessToken", + "AccessToken": "lkasjioryislaniuhfhklasnhfklahlvlsdvnls" + }, + "ReflectedWorkItemIdField": "Custom.ReflectedWorkItemId" + } + }, + "CommonTools": {}, + "Processors": [ + { + "ProcessorType": "TfsWorkItemMigrationProcessor", + "Enabled": true, + "WIQLQuery": "SELECT [System.Id] FROM WorkItems WHERE [System.TeamProject] = @TeamProject AND [System.WorkItemType] NOT IN ('Test Suite', 'Test Plan','Shared Steps','Shared Parameter','Feedback Request') ORDER BY [System.ChangedDate] desc", + } + ] + } +} \ No newline at end of file diff --git a/docs/getstarted/index.md b/docs/getstarted/index.md index 6a4349747..b1f353633 100644 --- a/docs/getstarted/index.md +++ b/docs/getstarted/index.md @@ -32,7 +32,7 @@ This is going to be a crash course and I really recommend watching [What can go You can now customize the configuration depending on what you need to do. However, a basic config that you can use to migrate from one team project to another with the same process will likley look somethig like: ```JSON -{% include sampleConfig/configuration.json %} +{% include sampleConfig/configuration-getstarted.json %} ``` The default [TfsWorkItemMigrationProcesor](_reference/reference.processors.tfsworkitemmigrationprocessor.md) processor will perform the following operations: From 91ab41d255a21e0a3ae40850da2712fb2645bf73 Mon Sep 17 00:00:00 2001 From: "Martin Hinshelwood nkdAgility.com" Date: Fri, 6 Sep 2024 09:30:18 +0100 Subject: [PATCH 2/4] Update docs --- docs/_layouts/default.html | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html index 8aba0dc8b..aa34b1554 100644 --- a/docs/_layouts/default.html +++ b/docs/_layouts/default.html @@ -60,7 +60,21 @@
  • Created and maintained by Martin Hinshelwood of nkdagility.com

  • +
  • +

    Versions

    + +
  • +
    @@ -80,23 +94,23 @@
    In this article
    From a0ce5517df8106a9be489e4a09e6afb26176e098 Mon Sep 17 00:00:00 2001 From: "Martin Hinshelwood nkdAgility.com" Date: Fri, 6 Sep 2024 13:56:19 +0100 Subject: [PATCH 3/4] Move to New MigrationTools16 AI --- .../workflows/MigrationToolsTelemetery.yml | 53 ++++ .github/workflows/test-function.yml | 31 ++ MigrationTools.sln | 7 + docs/Reference/Generated/MigrationTools.xml | 20 +- src/MigrationTools.Telemetery/.gitignore | 264 ++++++++++++++++++ .../GetShieldIoWorkItemMetrics.cs | 55 ++++ .../MigrationTools.Telemetery.csproj | 30 ++ src/MigrationTools.Telemetery/Program.cs | 14 + ...grationToolsTelemetery - Web Deploy.pubxml | 23 ++ .../appInsights1.arm.json | 67 +++++ .../storage1.arm.json | 70 +++++ .../appInsights1.arm.json | 67 +++++ .../storage1.arm.json | 70 +++++ .../Properties/launchSettings.json | 9 + ...MigrationToolsTelemetery - Web Deploy.json | 14 + ...Dependencies.MigrationToolsTelemetery.json | 14 + .../Properties/serviceDependencies.json | 12 + .../Properties/serviceDependencies.local.json | 7 + src/MigrationTools.Telemetery/host.json | 12 + .../Services/ActivitySourceProvider.cs | 6 +- 20 files changed, 832 insertions(+), 13 deletions(-) create mode 100644 .github/workflows/MigrationToolsTelemetery.yml create mode 100644 .github/workflows/test-function.yml create mode 100644 src/MigrationTools.Telemetery/.gitignore create mode 100644 src/MigrationTools.Telemetery/GetShieldIoWorkItemMetrics.cs create mode 100644 src/MigrationTools.Telemetery/MigrationTools.Telemetery.csproj create mode 100644 src/MigrationTools.Telemetery/Program.cs create mode 100644 src/MigrationTools.Telemetery/Properties/PublishProfiles/MigrationToolsTelemetery - Web Deploy.pubxml create mode 100644 src/MigrationTools.Telemetery/Properties/ServiceDependencies/MigrationToolsTelemetery - Web Deploy/appInsights1.arm.json create mode 100644 src/MigrationTools.Telemetery/Properties/ServiceDependencies/MigrationToolsTelemetery - Web Deploy/storage1.arm.json create mode 100644 src/MigrationTools.Telemetery/Properties/ServiceDependencies/MigrationToolsTelemetery/appInsights1.arm.json create mode 100644 src/MigrationTools.Telemetery/Properties/ServiceDependencies/MigrationToolsTelemetery/storage1.arm.json create mode 100644 src/MigrationTools.Telemetery/Properties/launchSettings.json create mode 100644 src/MigrationTools.Telemetery/Properties/serviceDependencies.MigrationToolsTelemetery - Web Deploy.json create mode 100644 src/MigrationTools.Telemetery/Properties/serviceDependencies.MigrationToolsTelemetery.json create mode 100644 src/MigrationTools.Telemetery/Properties/serviceDependencies.json create mode 100644 src/MigrationTools.Telemetery/Properties/serviceDependencies.local.json create mode 100644 src/MigrationTools.Telemetery/host.json diff --git a/.github/workflows/MigrationToolsTelemetery.yml b/.github/workflows/MigrationToolsTelemetery.yml new file mode 100644 index 000000000..93710f782 --- /dev/null +++ b/.github/workflows/MigrationToolsTelemetery.yml @@ -0,0 +1,53 @@ +name: Build and deploy .NET Core application to Function App MigrationToolsTelemetery +on: + push: + branches: + - topic/niggles + +env: + AZURE_FUNCTIONAPP_NAME: MigrationToolsTelemetery + AZURE_FUNCTIONAPP_PACKAGE_PATH: src\MigrationTools.Telemetery\published + CONFIGURATION: Release + DOTNET_CORE_VERSION: 8.0.x + WORKING_DIRECTORY: src\MigrationTools.Telemetery + DOTNET_CORE_VERSION_INPROC: 6.0.x + +jobs: + build: + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + - name: Setup .NET SDK + uses: actions/setup-dotnet@v3 + with: + dotnet-version: ${{ env.DOTNET_CORE_VERSION }} + - name: Setup .NET Core (for inproc extensions) + uses: actions/setup-dotnet@v1 + with: + dotnet-version: ${{ env.DOTNET_CORE_VERSION_INPROC }} + - name: Restore + run: dotnet restore "${{ env.WORKING_DIRECTORY }}" + - name: Build + run: dotnet build "${{ env.WORKING_DIRECTORY }}" --configuration ${{ env.CONFIGURATION }} --no-restore + - name: Publish + run: dotnet publish "${{ env.WORKING_DIRECTORY }}" --configuration ${{ env.CONFIGURATION }} --no-build --output "${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}" + - name: Publish Artifacts + uses: actions/upload-artifact@v3 + with: + name: functionapp + path: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} + deploy: + runs-on: windows-latest + needs: build + steps: + - name: Download artifact from build job + uses: actions/download-artifact@v3 + with: + name: functionapp + path: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} + - name: Deploy to Azure Function App + uses: Azure/functions-action@v1 + with: + app-name: ${{ env.AZURE_FUNCTIONAPP_NAME }} + publish-profile: ${{ secrets.MigrationToolsTelemetery_3736 }} + package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} diff --git a/.github/workflows/test-function.yml b/.github/workflows/test-function.yml new file mode 100644 index 000000000..004132a1a --- /dev/null +++ b/.github/workflows/test-function.yml @@ -0,0 +1,31 @@ +name: Function Build & Release (Azure DevOps Migration Tools) + +permissions: + contents: read + pull-requests: write + +on: + push: + branches: ["main"] + tags-ignore: ["v*-*"] + pull_request: + branches: ["main"] + workflow_dispatch: + inputs: + ForceRelease: + description: 'Force a release! Use when changes hapen out of sync and `src` and `docs` folder changes are not detected.' + required: false + default: false + type: boolean + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: pwsh + +jobs: + + # Setup & Configuration diff --git a/MigrationTools.sln b/MigrationTools.sln index eb6fe64ac..ae1d2f48e 100644 --- a/MigrationTools.sln +++ b/MigrationTools.sln @@ -117,6 +117,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MigrationTools.Documentatio EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MigrationTools.Shadows", "src\MigrationTools.Shadows\MigrationTools.Shadows.csproj", "{FA314A24-7616-498C-83F1-84D64365D00F}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MigrationTools.Telemetery", "src\MigrationTools.Telemetery\MigrationTools.Telemetery.csproj", "{5B9D24D8-8F47-4EB8-847A-9D5634CBC010}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -183,6 +185,10 @@ Global {FA314A24-7616-498C-83F1-84D64365D00F}.Debug|Any CPU.Build.0 = Debug|Any CPU {FA314A24-7616-498C-83F1-84D64365D00F}.Release|Any CPU.ActiveCfg = Release|Any CPU {FA314A24-7616-498C-83F1-84D64365D00F}.Release|Any CPU.Build.0 = Release|Any CPU + {5B9D24D8-8F47-4EB8-847A-9D5634CBC010}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5B9D24D8-8F47-4EB8-847A-9D5634CBC010}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5B9D24D8-8F47-4EB8-847A-9D5634CBC010}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5B9D24D8-8F47-4EB8-847A-9D5634CBC010}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -210,6 +216,7 @@ Global {BADF6B5C-1987-4F2D-8316-41D78CD25366} = {83F36820-E9BC-4F48-8202-5EAF9530405E} {217A2F5E-C6C7-4B1A-9E22-C7A1D00E9BED} = {83F36820-E9BC-4F48-8202-5EAF9530405E} {FA314A24-7616-498C-83F1-84D64365D00F} = {BADF6B5C-1987-4F2D-8316-41D78CD25366} + {5B9D24D8-8F47-4EB8-847A-9D5634CBC010} = {83F36820-E9BC-4F48-8202-5EAF9530405E} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {62EE0B27-C55A-46EE-8D17-1691DE9BBD50} diff --git a/docs/Reference/Generated/MigrationTools.xml b/docs/Reference/Generated/MigrationTools.xml index a90fcc846..8b2ccd50b 100644 --- a/docs/Reference/Generated/MigrationTools.xml +++ b/docs/Reference/Generated/MigrationTools.xml @@ -258,37 +258,37 @@ - => @"topic/documentation-updates" + => @"topic/niggles" - => @"a13a3b5d" + => @"91ab41d2" - => @"a13a3b5d353f39a2b1becb256d39be53dee451c9" + => @"91ab41d255a21e0a3ae40850da2712fb2645bf73" - => @"2024-09-05T10:02:11+01:00" + => @"2024-09-06T09:30:18+01:00" - => @"7" + => @"2" - => @"v16.0.0-Preview.10-7-ga13a3b5d" + => @"v16.0.0-2-g91ab41d2" - => @"v16.0.0-Preview.10" + => @"v16.0.0" @@ -318,17 +318,17 @@ - => @"7" + => @"2" - => @"Preview.10" + => @"" - => @"-Preview.10" + => @"" diff --git a/src/MigrationTools.Telemetery/.gitignore b/src/MigrationTools.Telemetery/.gitignore new file mode 100644 index 000000000..ff5b00c50 --- /dev/null +++ b/src/MigrationTools.Telemetery/.gitignore @@ -0,0 +1,264 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# Azure Functions localsettings file +local.settings.json + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +#*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc \ No newline at end of file diff --git a/src/MigrationTools.Telemetery/GetShieldIoWorkItemMetrics.cs b/src/MigrationTools.Telemetery/GetShieldIoWorkItemMetrics.cs new file mode 100644 index 000000000..5056f5932 --- /dev/null +++ b/src/MigrationTools.Telemetery/GetShieldIoWorkItemMetrics.cs @@ -0,0 +1,55 @@ +using System.Text; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Azure.Functions.Worker; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; + +namespace MigrationTools.Telemetery +{ + + public class GetShieldIoWorkItemMetrics + { + + private static readonly HttpClient client = new HttpClient(); + + private readonly ILogger _logger; + + public GetShieldIoWorkItemMetrics(ILogger logger) + { + _logger = logger; + } + + [Function("GetShieldIoWorkItemMetrics_WorkItemTotals")] + public async Task GetShieldIoWorkItemMetrics_WorkItemTotals([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequest req) + { + _logger.LogInformation("Processing request for Application Insights data."); + + string appId = Environment.GetEnvironmentVariable("APP_INSIGHTS_APP_ID"); + string apiKey = Environment.GetEnvironmentVariable("APP_INSIGHTS_API_KEY"); + string query = @" + customMetrics + | where name == 'work_items_processed_total' + | summarize Total = sum(value) by application_Version"; + + var payload = new + { + query = query + }; + + client.DefaultRequestHeaders.Add("x-api-key", apiKey); + var content = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json"); + HttpResponseMessage response = await client.PostAsync($"https://api.applicationinsights.io/v1/apps/{appId}/query", content); + + if (response.IsSuccessStatusCode) + { + string result = await response.Content.ReadAsStringAsync(); + return new OkObjectResult(result); + } + else + { + return new BadRequestObjectResult("Error fetching data from Application Insights"); + } + } + } +} diff --git a/src/MigrationTools.Telemetery/MigrationTools.Telemetery.csproj b/src/MigrationTools.Telemetery/MigrationTools.Telemetery.csproj new file mode 100644 index 000000000..4ffe01ba9 --- /dev/null +++ b/src/MigrationTools.Telemetery/MigrationTools.Telemetery.csproj @@ -0,0 +1,30 @@ + + + net8.0 + v4 + Exe + enable + enable + + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + Never + + + + + + \ No newline at end of file diff --git a/src/MigrationTools.Telemetery/Program.cs b/src/MigrationTools.Telemetery/Program.cs new file mode 100644 index 000000000..c2df7fbe4 --- /dev/null +++ b/src/MigrationTools.Telemetery/Program.cs @@ -0,0 +1,14 @@ +using Microsoft.Azure.Functions.Worker; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +var host = new HostBuilder() + .ConfigureFunctionsWebApplication() + .ConfigureServices(services => + { + services.AddApplicationInsightsTelemetryWorkerService(); + services.ConfigureFunctionsApplicationInsights(); + }) + .Build(); + +host.Run(); diff --git a/src/MigrationTools.Telemetery/Properties/PublishProfiles/MigrationToolsTelemetery - Web Deploy.pubxml b/src/MigrationTools.Telemetery/Properties/PublishProfiles/MigrationToolsTelemetery - Web Deploy.pubxml new file mode 100644 index 000000000..818c6c3cb --- /dev/null +++ b/src/MigrationTools.Telemetery/Properties/PublishProfiles/MigrationToolsTelemetery - Web Deploy.pubxml @@ -0,0 +1,23 @@ + + + + + MSDeploy + AzureWebSite + Release + Any CPU + https://migrationtoolstelemetery.azurewebsites.net + false + /subscriptions/c2d1c3f0-0945-44b4-a0ba-67c45e9d16ac/resourceGroups/MigrationTools/providers/Microsoft.Web/sites/MigrationToolsTelemetery + win-x64 + false + migrationtoolstelemetery.scm.azurewebsites.net:443 + WMSVC + false + true + true + MigrationToolsTelemetery + + \ No newline at end of file diff --git a/src/MigrationTools.Telemetery/Properties/ServiceDependencies/MigrationToolsTelemetery - Web Deploy/appInsights1.arm.json b/src/MigrationTools.Telemetery/Properties/ServiceDependencies/MigrationToolsTelemetery - Web Deploy/appInsights1.arm.json new file mode 100644 index 000000000..b38ae846a --- /dev/null +++ b/src/MigrationTools.Telemetery/Properties/ServiceDependencies/MigrationToolsTelemetery - Web Deploy/appInsights1.arm.json @@ -0,0 +1,67 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "resourceGroupName": { + "type": "string", + "defaultValue": "MigrationTools", + "metadata": { + "_parameterType": "resourceGroup", + "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking." + } + }, + "resourceGroupLocation": { + "type": "string", + "defaultValue": "northeurope", + "metadata": { + "_parameterType": "location", + "description": "Location of the resource group. Resource groups could have different location than resources." + } + }, + "resourceLocation": { + "type": "string", + "defaultValue": "[parameters('resourceGroupLocation')]", + "metadata": { + "_parameterType": "location", + "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there." + } + } + }, + "resources": [ + { + "type": "Microsoft.Resources/resourceGroups", + "name": "[parameters('resourceGroupName')]", + "location": "[parameters('resourceGroupLocation')]", + "apiVersion": "2019-10-01" + }, + { + "type": "Microsoft.Resources/deployments", + "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat('MigrationToolAI', subscription().subscriptionId)))]", + "resourceGroup": "[parameters('resourceGroupName')]", + "apiVersion": "2019-10-01", + "dependsOn": [ + "[parameters('resourceGroupName')]" + ], + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "kind": "web", + "name": "MigrationToolAI", + "type": "microsoft.insights/components", + "location": "[parameters('resourceLocation')]", + "properties": {}, + "apiVersion": "2015-05-01" + } + ] + } + } + } + ], + "metadata": { + "_dependencyType": "appInsights.azure" + } +} \ No newline at end of file diff --git a/src/MigrationTools.Telemetery/Properties/ServiceDependencies/MigrationToolsTelemetery - Web Deploy/storage1.arm.json b/src/MigrationTools.Telemetery/Properties/ServiceDependencies/MigrationToolsTelemetery - Web Deploy/storage1.arm.json new file mode 100644 index 000000000..73bcb7e2e --- /dev/null +++ b/src/MigrationTools.Telemetery/Properties/ServiceDependencies/MigrationToolsTelemetery - Web Deploy/storage1.arm.json @@ -0,0 +1,70 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "resourceGroupName": { + "type": "string", + "defaultValue": "MigrationTools", + "metadata": { + "_parameterType": "resourceGroup", + "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking." + } + }, + "resourceGroupLocation": { + "type": "string", + "defaultValue": "northeurope", + "metadata": { + "_parameterType": "location", + "description": "Location of the resource group. Resource groups could have different location than resources." + } + }, + "resourceLocation": { + "type": "string", + "defaultValue": "[parameters('resourceGroupLocation')]", + "metadata": { + "_parameterType": "location", + "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there." + } + } + }, + "resources": [ + { + "type": "Microsoft.Resources/resourceGroups", + "name": "[parameters('resourceGroupName')]", + "location": "[parameters('resourceGroupLocation')]", + "apiVersion": "2019-10-01" + }, + { + "type": "Microsoft.Resources/deployments", + "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat('migrationtoolstorewe', subscription().subscriptionId)))]", + "resourceGroup": "[parameters('resourceGroupName')]", + "apiVersion": "2019-10-01", + "dependsOn": [ + "[parameters('resourceGroupName')]" + ], + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "sku": { + "name": "Standard_LRS", + "tier": "Standard" + }, + "kind": "Storage", + "name": "migrationtoolstorewe", + "type": "Microsoft.Storage/storageAccounts", + "location": "[parameters('resourceLocation')]", + "apiVersion": "2017-10-01" + } + ] + } + } + } + ], + "metadata": { + "_dependencyType": "storage.azure" + } +} \ No newline at end of file diff --git a/src/MigrationTools.Telemetery/Properties/ServiceDependencies/MigrationToolsTelemetery/appInsights1.arm.json b/src/MigrationTools.Telemetery/Properties/ServiceDependencies/MigrationToolsTelemetery/appInsights1.arm.json new file mode 100644 index 000000000..b38ae846a --- /dev/null +++ b/src/MigrationTools.Telemetery/Properties/ServiceDependencies/MigrationToolsTelemetery/appInsights1.arm.json @@ -0,0 +1,67 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "resourceGroupName": { + "type": "string", + "defaultValue": "MigrationTools", + "metadata": { + "_parameterType": "resourceGroup", + "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking." + } + }, + "resourceGroupLocation": { + "type": "string", + "defaultValue": "northeurope", + "metadata": { + "_parameterType": "location", + "description": "Location of the resource group. Resource groups could have different location than resources." + } + }, + "resourceLocation": { + "type": "string", + "defaultValue": "[parameters('resourceGroupLocation')]", + "metadata": { + "_parameterType": "location", + "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there." + } + } + }, + "resources": [ + { + "type": "Microsoft.Resources/resourceGroups", + "name": "[parameters('resourceGroupName')]", + "location": "[parameters('resourceGroupLocation')]", + "apiVersion": "2019-10-01" + }, + { + "type": "Microsoft.Resources/deployments", + "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat('MigrationToolAI', subscription().subscriptionId)))]", + "resourceGroup": "[parameters('resourceGroupName')]", + "apiVersion": "2019-10-01", + "dependsOn": [ + "[parameters('resourceGroupName')]" + ], + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "kind": "web", + "name": "MigrationToolAI", + "type": "microsoft.insights/components", + "location": "[parameters('resourceLocation')]", + "properties": {}, + "apiVersion": "2015-05-01" + } + ] + } + } + } + ], + "metadata": { + "_dependencyType": "appInsights.azure" + } +} \ No newline at end of file diff --git a/src/MigrationTools.Telemetery/Properties/ServiceDependencies/MigrationToolsTelemetery/storage1.arm.json b/src/MigrationTools.Telemetery/Properties/ServiceDependencies/MigrationToolsTelemetery/storage1.arm.json new file mode 100644 index 000000000..73bcb7e2e --- /dev/null +++ b/src/MigrationTools.Telemetery/Properties/ServiceDependencies/MigrationToolsTelemetery/storage1.arm.json @@ -0,0 +1,70 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "resourceGroupName": { + "type": "string", + "defaultValue": "MigrationTools", + "metadata": { + "_parameterType": "resourceGroup", + "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking." + } + }, + "resourceGroupLocation": { + "type": "string", + "defaultValue": "northeurope", + "metadata": { + "_parameterType": "location", + "description": "Location of the resource group. Resource groups could have different location than resources." + } + }, + "resourceLocation": { + "type": "string", + "defaultValue": "[parameters('resourceGroupLocation')]", + "metadata": { + "_parameterType": "location", + "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there." + } + } + }, + "resources": [ + { + "type": "Microsoft.Resources/resourceGroups", + "name": "[parameters('resourceGroupName')]", + "location": "[parameters('resourceGroupLocation')]", + "apiVersion": "2019-10-01" + }, + { + "type": "Microsoft.Resources/deployments", + "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat('migrationtoolstorewe', subscription().subscriptionId)))]", + "resourceGroup": "[parameters('resourceGroupName')]", + "apiVersion": "2019-10-01", + "dependsOn": [ + "[parameters('resourceGroupName')]" + ], + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "sku": { + "name": "Standard_LRS", + "tier": "Standard" + }, + "kind": "Storage", + "name": "migrationtoolstorewe", + "type": "Microsoft.Storage/storageAccounts", + "location": "[parameters('resourceLocation')]", + "apiVersion": "2017-10-01" + } + ] + } + } + } + ], + "metadata": { + "_dependencyType": "storage.azure" + } +} \ No newline at end of file diff --git a/src/MigrationTools.Telemetery/Properties/launchSettings.json b/src/MigrationTools.Telemetery/Properties/launchSettings.json new file mode 100644 index 000000000..1e26bb917 --- /dev/null +++ b/src/MigrationTools.Telemetery/Properties/launchSettings.json @@ -0,0 +1,9 @@ +{ + "profiles": { + "MigrationTools.Telemetery": { + "commandName": "Project", + "commandLineArgs": "--port 7008", + "launchBrowser": false + } + } +} \ No newline at end of file diff --git a/src/MigrationTools.Telemetery/Properties/serviceDependencies.MigrationToolsTelemetery - Web Deploy.json b/src/MigrationTools.Telemetery/Properties/serviceDependencies.MigrationToolsTelemetery - Web Deploy.json new file mode 100644 index 000000000..50afcd51e --- /dev/null +++ b/src/MigrationTools.Telemetery/Properties/serviceDependencies.MigrationToolsTelemetery - Web Deploy.json @@ -0,0 +1,14 @@ +{ + "dependencies": { + "storage1": { + "resourceId": "/subscriptions/[parameters('subscriptionId')]/resourceGroups/[parameters('resourceGroupName')]/providers/Microsoft.Storage/storageAccounts/migrationtoolstorewe", + "type": "storage.azure", + "connectionId": "AzureWebJobsStorage" + }, + "appInsights1": { + "resourceId": "/subscriptions/[parameters('subscriptionId')]/resourceGroups/[parameters('resourceGroupName')]/providers/microsoft.insights/components/MigrationToolAI", + "type": "appInsights.azure", + "connectionId": "APPLICATIONINSIGHTS_CONNECTION_STRING" + } + } +} \ No newline at end of file diff --git a/src/MigrationTools.Telemetery/Properties/serviceDependencies.MigrationToolsTelemetery.json b/src/MigrationTools.Telemetery/Properties/serviceDependencies.MigrationToolsTelemetery.json new file mode 100644 index 000000000..e60b0ebf4 --- /dev/null +++ b/src/MigrationTools.Telemetery/Properties/serviceDependencies.MigrationToolsTelemetery.json @@ -0,0 +1,14 @@ +{ + "dependencies": { + "appInsights1": { + "resourceId": "/subscriptions/[parameters('subscriptionId')]/resourceGroups/[parameters('resourceGroupName')]/providers/microsoft.insights/components/MigrationToolAI", + "type": "appInsights.azure", + "connectionId": "APPLICATIONINSIGHTS_CONNECTION_STRING" + }, + "storage1": { + "resourceId": "/subscriptions/[parameters('subscriptionId')]/resourceGroups/[parameters('resourceGroupName')]/providers/Microsoft.Storage/storageAccounts/migrationtoolstorewe", + "type": "storage.azure", + "connectionId": "AzureWebJobsStorage" + } + } +} \ No newline at end of file diff --git a/src/MigrationTools.Telemetery/Properties/serviceDependencies.json b/src/MigrationTools.Telemetery/Properties/serviceDependencies.json new file mode 100644 index 000000000..ce1d90cda --- /dev/null +++ b/src/MigrationTools.Telemetery/Properties/serviceDependencies.json @@ -0,0 +1,12 @@ +{ + "dependencies": { + "storage1": { + "type": "storage", + "connectionId": "AzureWebJobsStorage" + }, + "appInsights1": { + "type": "appInsights", + "connectionId": "APPLICATIONINSIGHTS_CONNECTION_STRING" + } + } +} \ No newline at end of file diff --git a/src/MigrationTools.Telemetery/Properties/serviceDependencies.local.json b/src/MigrationTools.Telemetery/Properties/serviceDependencies.local.json new file mode 100644 index 000000000..5a956e859 --- /dev/null +++ b/src/MigrationTools.Telemetery/Properties/serviceDependencies.local.json @@ -0,0 +1,7 @@ +{ + "dependencies": { + "appInsights1": { + "type": "appInsights.sdk" + } + } +} \ No newline at end of file diff --git a/src/MigrationTools.Telemetery/host.json b/src/MigrationTools.Telemetery/host.json new file mode 100644 index 000000000..ee5cf5f83 --- /dev/null +++ b/src/MigrationTools.Telemetery/host.json @@ -0,0 +1,12 @@ +{ + "version": "2.0", + "logging": { + "applicationInsights": { + "samplingSettings": { + "isEnabled": true, + "excludedTypes": "Request" + }, + "enableLiveMetricsFilters": true + } + } +} \ No newline at end of file diff --git a/src/MigrationTools/Services/ActivitySourceProvider.cs b/src/MigrationTools/Services/ActivitySourceProvider.cs index 21e6c3f0c..b823e9283 100644 --- a/src/MigrationTools/Services/ActivitySourceProvider.cs +++ b/src/MigrationTools/Services/ActivitySourceProvider.cs @@ -22,8 +22,8 @@ namespace MigrationTools.Services public class ActivitySourceProvider { public static readonly string ActivitySourceName = "MigrationTools"; - //private static string OpenTelemetryConnectionString = "InstrumentationKey=823d0de3-69c9-42ee-b902-de7675f681bc;IngestionEndpoint=https://westeurope-5.in.applicationinsights.azure.com/;LiveEndpoint=https://westeurope.livediagnostics.monitor.azure.com/;ApplicationId=4dd8f684-2f91-48ac-974f-dc898b686786"; - private static string MigrationToolAIConnectionString = "InstrumentationKey=2d666f84-b3fb-4dcf-9aad-65de038d2772;IngestionEndpoint=https://northeurope-0.in.applicationinsights.azure.com/;LiveEndpoint=https://northeurope.livediagnostics.monitor.azure.com/;ApplicationId=9146fe72-5c18-48d7-a0f2-8fb891ef1277"; + private static string OpenTelemetryConnectionString = "InstrumentationKey=823d0de3-69c9-42ee-b902-de7675f681bc;IngestionEndpoint=https://westeurope-5.in.applicationinsights.azure.com/;LiveEndpoint=https://westeurope.livediagnostics.monitor.azure.com/;ApplicationId=4dd8f684-2f91-48ac-974f-dc898b686786"; + //private static string MigrationToolAIConnectionString = "InstrumentationKey=2d666f84-b3fb-4dcf-9aad-65de038d2772;IngestionEndpoint=https://northeurope-0.in.applicationinsights.azure.com/;LiveEndpoint=https://northeurope.livediagnostics.monitor.azure.com/;ApplicationId=9146fe72-5c18-48d7-a0f2-8fb891ef1277"; public static ActivitySource ActivitySource { get; private set; } @@ -33,7 +33,7 @@ public class ActivitySourceProvider public static string GetConnectionString() { - return MigrationToolAIConnectionString; + return OpenTelemetryConnectionString; } From 6464122b297640f5bc77fad739ec20bb54fb43c3 Mon Sep 17 00:00:00 2001 From: "Martin Hinshelwood nkdAgility.com" Date: Fri, 6 Sep 2024 14:38:58 +0100 Subject: [PATCH 4/4] Update to send new bits --- README.md | 3 + docs/Reference/Generated/MigrationTools.xml | 12 +- .../GetShieldIoWorkItemMetrics.cs | 181 ++++++++++++++++-- .../profile.arm.json | 113 +++++++++++ .../Services/ActivitySourceProvider.cs | 1 - 5 files changed, 283 insertions(+), 27 deletions(-) create mode 100644 src/MigrationTools.Telemetery/Properties/ServiceDependencies/MigrationToolsTelemetery - Web Deploy/profile.arm.json diff --git a/README.md b/README.md index 5dbc262e0..5dccb3762 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,9 @@ The documentation for the preview is on [Preview](https://nkdagility.com/docs/az | Migration Run Total | **19bn Seconds** | Thats **316m hours** or **13m days** of run time in the last 30 days. | | Average Work item Migration Time | **22s** | Work Item (includes all revisions, links, and attachments for the work item) | +![All Work Items Migrated with new version](https://img.shields.io/endpoint?url=https%3A%2F%2Fmigrationtoolstelemetery.azurewebsites.net%2Fapi%2FGetShieldIoWorkItemMetrics_WorkItemTotals%3Fcode%3DN0Lfmkrz_Rzh1lrd5eol1IuDIUfOVnX0oFaT8k6m_uX8AzFu27y_og%3D%3D) + + This tool uses OpenTelemetery to collect metrics and logs, and Application Insights to store and analyse them. Exceptions are also sent to [Elmah.io](https://elmah.io) for analysis and improvement. ## Advanced tools diff --git a/docs/Reference/Generated/MigrationTools.xml b/docs/Reference/Generated/MigrationTools.xml index 8b2ccd50b..0929d08d0 100644 --- a/docs/Reference/Generated/MigrationTools.xml +++ b/docs/Reference/Generated/MigrationTools.xml @@ -263,27 +263,27 @@ - => @"91ab41d2" + => @"a0ce5517" - => @"91ab41d255a21e0a3ae40850da2712fb2645bf73" + => @"a0ce5517df8106a9be489e4a09e6afb26176e098" - => @"2024-09-06T09:30:18+01:00" + => @"2024-09-06T13:56:19+01:00" - => @"2" + => @"3" - => @"v16.0.0-2-g91ab41d2" + => @"v16.0.0-3-ga0ce5517" @@ -318,7 +318,7 @@ - => @"2" + => @"3" diff --git a/src/MigrationTools.Telemetery/GetShieldIoWorkItemMetrics.cs b/src/MigrationTools.Telemetery/GetShieldIoWorkItemMetrics.cs index 5056f5932..430bca04e 100644 --- a/src/MigrationTools.Telemetery/GetShieldIoWorkItemMetrics.cs +++ b/src/MigrationTools.Telemetery/GetShieldIoWorkItemMetrics.cs @@ -1,55 +1,196 @@ -using System.Text; +using System; +using System.Text; +using System.Threading.Tasks; +using System.Net.Http; +using System.Collections.Generic; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.Functions.Worker; +using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Logging; using Newtonsoft.Json; namespace MigrationTools.Telemetery { - public class GetShieldIoWorkItemMetrics { - private static readonly HttpClient client = new HttpClient(); - private readonly ILogger _logger; + private readonly IMemoryCache _cache; + private static readonly TimeSpan CacheDuration = TimeSpan.FromMinutes(10); // Cache duration - public GetShieldIoWorkItemMetrics(ILogger logger) + public GetShieldIoWorkItemMetrics(ILogger logger, IMemoryCache cache) { _logger = logger; + _cache = cache; } [Function("GetShieldIoWorkItemMetrics_WorkItemTotals")] - public async Task GetShieldIoWorkItemMetrics_WorkItemTotals([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequest req) + public async Task GetShieldIoWorkItemMetrics_WorkItemTotals( + [HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequest req) { _logger.LogInformation("Processing request for Application Insights data."); string appId = Environment.GetEnvironmentVariable("APP_INSIGHTS_APP_ID"); string apiKey = Environment.GetEnvironmentVariable("APP_INSIGHTS_API_KEY"); - string query = @" - customMetrics - | where name == 'work_items_processed_total' - | summarize Total = sum(value) by application_Version"; - var payload = new + if (string.IsNullOrEmpty(appId) || string.IsNullOrEmpty(apiKey)) { - query = query - }; + return new BadRequestObjectResult("Application Insights environment variables not set"); + } - client.DefaultRequestHeaders.Add("x-api-key", apiKey); - var content = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json"); - HttpResponseMessage response = await client.PostAsync($"https://api.applicationinsights.io/v1/apps/{appId}/query", content); + string versionPrefix = req.Query["version"]; // Get the 'version' query parameter if provided - if (response.IsSuccessStatusCode) + // Check if cached result exists + if (!_cache.TryGetValue("ai_work_items", out AppInsightsResponse cachedData)) { - string result = await response.Content.ReadAsStringAsync(); - return new OkObjectResult(result); + _logger.LogInformation("Cache miss. Fetching data from Application Insights."); + + string query = @" + customMetrics + | where name == 'work_items_processed_total' + | summarize Total = sum(value) by application_Version"; + + var payload = new + { + query = query + }; + + client.DefaultRequestHeaders.Add("x-api-key", apiKey); + var content = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json"); + HttpResponseMessage response = await client.PostAsync($"https://api.applicationinsights.io/v1/apps/{appId}/query", content); + + if (response.IsSuccessStatusCode) + { + string result = await response.Content.ReadAsStringAsync(); + cachedData = JsonConvert.DeserializeObject(result); + + // Cache the result with a defined expiration + _cache.Set("ai_work_items", cachedData, CacheDuration); + } + else + { + return new BadRequestObjectResult($"Error fetching data from Application Insights: {response.StatusCode}"); + } } else { - return new BadRequestObjectResult("Error fetching data from Application Insights"); + _logger.LogInformation("Cache hit. Returning cached data."); } + + // Check if the user requested a specific version prefix or if we should return the sum + double totalWorkItems = 0; + string formattedVersionLabel = "All Versions"; // Default label if no version is provided + if (!string.IsNullOrEmpty(versionPrefix)) + { + // Sum totals for all versions that start with the provided version prefix + totalWorkItems = GetWorkItemTotalForVersionPrefix(cachedData, versionPrefix); + if (totalWorkItems == -1) + { + // No matching versions found, return "No Data" message + return new JsonResult(new + { + schemaVersion = 1, + label = $"Total Work Items ({FormatVersionLabel(versionPrefix)})", + message = "No Data", + color = "orange" + }); + } + + // Format the version label as X.Y.Z (3 digits) + formattedVersionLabel = FormatVersionLabel(versionPrefix); + } + else + { + // Sum all work items for all versions + totalWorkItems = GetTotalWorkItems(cachedData); + if (totalWorkItems == 0) + { + // No data found at all, return "No Data" + return new JsonResult(new + { + schemaVersion = 1, + label = "Total Work Items (All Versions)", + message = "No Data", + color = "orange" + }); + } + } + + // Create the response for Shields.io with total work items + var shieldsIoResponse = new + { + schemaVersion = 1, + label = $"Total Work Items ({formattedVersionLabel})", + message = totalWorkItems.ToString(), + color = "orange" + }; + + return new JsonResult(shieldsIoResponse); } + + // Method to calculate the total work items for all versions + private double GetTotalWorkItems(AppInsightsResponse appInsightsData) + { + double total = 0; + foreach (var row in appInsightsData.Tables[0].Rows) + { + total += Convert.ToDouble(row[1]); // Sum the "Total" column + } + return total; + } + + // Method to get the work item total for all versions that start with the provided version prefix + private double GetWorkItemTotalForVersionPrefix(AppInsightsResponse appInsightsData, string versionPrefix) + { + double total = 0; + bool foundAnyMatchingVersion = false; + + foreach (var row in appInsightsData.Tables[0].Rows) + { + string version = row[0].ToString(); // "application_Version" column + if (version.StartsWith(versionPrefix)) + { + total += Convert.ToDouble(row[1]); // Sum the "Total" column for matching versions + foundAnyMatchingVersion = true; + } + } + + return foundAnyMatchingVersion ? total : -1; // Return -1 if no matching versions were found + } + + // Helper method to format the version label to always have three parts (e.g., X.Y.Z) + private string FormatVersionLabel(string version) + { + var versionParts = version.Split('.'); + if (versionParts.Length == 1) + { + return $"{versionParts[0]}.0.0"; // Pad with .0.0 + } + else if (versionParts.Length == 2) + { + return $"{versionParts[0]}.{versionParts[1]}.0"; // Pad with .0 + } + return version; // Already in X.Y.Z format + } + } + + // Classes to represent the structure of the Application Insights response + public class AppInsightsResponse + { + public List Tables { get; set; } + } + + public class Table + { + public string Name { get; set; } + public List Columns { get; set; } + public List> Rows { get; set; } + } + + public class Column + { + public string Name { get; set; } + public string Type { get; set; } } } diff --git a/src/MigrationTools.Telemetery/Properties/ServiceDependencies/MigrationToolsTelemetery - Web Deploy/profile.arm.json b/src/MigrationTools.Telemetery/Properties/ServiceDependencies/MigrationToolsTelemetery - Web Deploy/profile.arm.json new file mode 100644 index 000000000..fcacd5fc3 --- /dev/null +++ b/src/MigrationTools.Telemetery/Properties/ServiceDependencies/MigrationToolsTelemetery - Web Deploy/profile.arm.json @@ -0,0 +1,113 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_dependencyType": "compute.appService.windows" + }, + "parameters": { + "resourceGroupName": { + "type": "string", + "defaultValue": "MigrationTools", + "metadata": { + "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking." + } + }, + "resourceGroupLocation": { + "type": "string", + "defaultValue": "northeurope", + "metadata": { + "description": "Location of the resource group. Resource groups could have different location than resources, however by default we use API versions from latest hybrid profile which support all locations for resource types we support." + } + }, + "resourceName": { + "type": "string", + "defaultValue": "MigrationToolsTelemetery", + "metadata": { + "description": "Name of the main resource to be created by this template." + } + }, + "resourceLocation": { + "type": "string", + "defaultValue": "[parameters('resourceGroupLocation')]", + "metadata": { + "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there." + } + } + }, + "variables": { + "appServicePlan_name": "[concat('Plan', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]", + "appServicePlan_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/serverFarms/', variables('appServicePlan_name'))]" + }, + "resources": [ + { + "type": "Microsoft.Resources/resourceGroups", + "name": "[parameters('resourceGroupName')]", + "location": "[parameters('resourceGroupLocation')]", + "apiVersion": "2019-10-01" + }, + { + "type": "Microsoft.Resources/deployments", + "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]", + "resourceGroup": "[parameters('resourceGroupName')]", + "apiVersion": "2019-10-01", + "dependsOn": [ + "[parameters('resourceGroupName')]" + ], + "properties": { + "mode": "Incremental", + "template": { + "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "location": "[parameters('resourceLocation')]", + "name": "[parameters('resourceName')]", + "type": "Microsoft.Web/sites", + "apiVersion": "2015-08-01", + "tags": { + "[concat('hidden-related:', variables('appServicePlan_ResourceId'))]": "empty" + }, + "dependsOn": [ + "[variables('appServicePlan_ResourceId')]" + ], + "kind": "app", + "properties": { + "name": "[parameters('resourceName')]", + "kind": "app", + "httpsOnly": true, + "reserved": false, + "serverFarmId": "[variables('appServicePlan_ResourceId')]", + "siteConfig": { + "metadata": [ + { + "name": "CURRENT_STACK", + "value": "dotnetcore" + } + ] + } + }, + "identity": { + "type": "SystemAssigned" + } + }, + { + "location": "[parameters('resourceLocation')]", + "name": "[variables('appServicePlan_name')]", + "type": "Microsoft.Web/serverFarms", + "apiVersion": "2015-08-01", + "sku": { + "name": "S1", + "tier": "Standard", + "family": "S", + "size": "S1" + }, + "properties": { + "name": "[variables('appServicePlan_name')]" + } + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/src/MigrationTools/Services/ActivitySourceProvider.cs b/src/MigrationTools/Services/ActivitySourceProvider.cs index b823e9283..0f2f7af19 100644 --- a/src/MigrationTools/Services/ActivitySourceProvider.cs +++ b/src/MigrationTools/Services/ActivitySourceProvider.cs @@ -23,7 +23,6 @@ public class ActivitySourceProvider { public static readonly string ActivitySourceName = "MigrationTools"; private static string OpenTelemetryConnectionString = "InstrumentationKey=823d0de3-69c9-42ee-b902-de7675f681bc;IngestionEndpoint=https://westeurope-5.in.applicationinsights.azure.com/;LiveEndpoint=https://westeurope.livediagnostics.monitor.azure.com/;ApplicationId=4dd8f684-2f91-48ac-974f-dc898b686786"; - //private static string MigrationToolAIConnectionString = "InstrumentationKey=2d666f84-b3fb-4dcf-9aad-65de038d2772;IngestionEndpoint=https://northeurope-0.in.applicationinsights.azure.com/;LiveEndpoint=https://northeurope.livediagnostics.monitor.azure.com/;ApplicationId=9146fe72-5c18-48d7-a0f2-8fb891ef1277"; public static ActivitySource ActivitySource { get; private set; }