From 7ba9498cb20008715aa93ee77cfd933d4352acbc Mon Sep 17 00:00:00 2001 From: dantelmomsft Date: Thu, 12 Sep 2024 17:46:36 +0200 Subject: [PATCH] back to azd standard folder structure. set gpt-4o-mini as default model --- .../{apps-ci.yaml => azure-dev.yaml} | 322 ++--- .../applicationinsights-dashboard.bicep | 1236 +++++++++++++++++ .../shared/monitor/applicationinsights.bicep | 31 + infra/shared/monitor/loganalytics.bicep | 23 + infra/shared/monitor/monitoring.bicep | 34 + 5 files changed, 1485 insertions(+), 161 deletions(-) rename .github/workflows/{apps-ci.yaml => azure-dev.yaml} (97%) create mode 100644 infra/shared/monitor/applicationinsights-dashboard.bicep create mode 100644 infra/shared/monitor/applicationinsights.bicep create mode 100644 infra/shared/monitor/loganalytics.bicep create mode 100644 infra/shared/monitor/monitoring.bicep diff --git a/.github/workflows/apps-ci.yaml b/.github/workflows/azure-dev.yaml similarity index 97% rename from .github/workflows/apps-ci.yaml rename to .github/workflows/azure-dev.yaml index d3bc196..fdbb0fc 100644 --- a/.github/workflows/apps-ci.yaml +++ b/.github/workflows/azure-dev.yaml @@ -1,162 +1,162 @@ -name: Container Apps CI/CD pipeline - -on: - push: - branches: - - main - paths: - - "app/**" - tags: - - v*.*.* - workflow_dispatch: - -jobs: - changes-detection: - runs-on: ubuntu-latest - outputs: - env-name: ${{steps.set-deploy-env.outputs.DEPLOY_ENVIRONMENT}} - build-copilot: ${{ steps.changes.outputs.copilot }} - build-frontend: ${{ steps.changes.outputs.frontend }} - build-account-api: ${{ steps.changes.outputs.account-api }} - build-payment-api: ${{ steps.changes.outputs.payment-api }} - build-transaction-api: ${{ steps.changes.outputs.transaction-api }} - steps: - - uses: actions/checkout@v2 - - name: Filter Changes - uses: dorny/paths-filter@v2 - id: changes - with: - filters: | - copilot: - - 'app/copilot/**' - frontend: - - 'app/frontend/**' - account-api: - - 'app/business-api/account/**' - payment-api: - - 'app/business-api/payment/**' - transaction-api: - - 'app/business-api/transactions-history/**' - - - name: Set environment for branch - id: set-deploy-env - run: | - echo "checking branch name [${{github.ref_name}}]" - if [[ ${{github.ref_name}} == 'main' ]]; then - echo "main branch detected. Set Development environment" - echo "DEPLOY_ENVIRONMENT=Development" >> "$GITHUB_OUTPUT" - elif [[ ${{github.ref_name}} == *'release'* ]]; then - echo "release branch detected. Set Test environment" - echo "DEPLOY_ENVIRONMENT=Test" >> "$GITHUB_OUTPUT" - elif [[ ${{github.ref_name}} == *'v'* ]]; then - echo "tag detected. Set Production environment" - echo "DEPLOY_ENVIRONMENT=Production" >> "$GITHUB_OUTPUT" - else - echo "branch not detected. Set Development environment as default" - echo "DEPLOY_ENVIRONMENT=Development" >> "$GITHUB_OUTPUT" - fi - - build-account-app: - needs: changes-detection - if : ${{ needs.changes-detection.outputs.build-account-api == 'true' }} - uses: ./.github/workflows/acr-build-push.yaml - with: - env-name: ${{ needs.changes-detection.outputs.env-name}} - image-name: personal-finance-assistance-java/account-api - app-folder-path: ./app/business-api/account - secrets: inherit - - deploy-account-app: - needs: [changes-detection,build-account-app] - if: ${{ needs.changes-detection.outputs.build-account-api == 'true' }} - uses: ./.github/workflows/aca-deploy.yaml - with: - env-name: ${{ needs.changes-detection.outputs.env-name}} - image-name: personal-finance-assistance-java/account-api - container-app-env-name: ${{ vars.ACA_DEV_ENV_NAME}} - container-app-name: ${{ vars.ACCOUNTS_ACA_DEV_APP_NAME }} - secrets: inherit - - build-transaction-app: - needs: changes-detection - if : ${{ needs.changes-detection.outputs.build-transaction-api == 'true' }} - uses: ./.github/workflows/acr-build-push.yaml - with: - env-name: ${{ needs.changes-detection.outputs.env-name}} - image-name: personal-finance-assistance-java/transactions-history-api - app-folder-path: ./app/business-api/transactions-history - secrets: inherit - - deploy-transaction-app: - needs: [changes-detection,build-transaction-app] - if: ${{ needs.changes-detection.outputs.build-transaction-api == 'true' }} - uses: ./.github/workflows/aca-deploy.yaml - with: - env-name: ${{ needs.changes-detection.outputs.env-name}} - image-name: personal-finance-assistance-java/transactions-history-api - container-app-env-name: ${{ vars.ACA_DEV_ENV_NAME}} - container-app-name: ${{ vars.TRANSACTIONS_ACA_DEV_APP_NAME }} - secrets: inherit - build-payment-app: - needs: changes-detection - if : ${{ needs.changes-detection.outputs.build-payment-api == 'true' }} - uses: ./.github/workflows/acr-build-push.yaml - with: - env-name: ${{ needs.changes-detection.outputs.env-name}} - image-name: personal-finance-assistance-java/payment-api - app-folder-path: ./app/business-api/payment - secrets: inherit - - deploy-payment-app: - needs: [changes-detection,build-payment-app] - if: ${{ needs.changes-detection.outputs.build-payment-api == 'true' }} - uses: ./.github/workflows/aca-deploy.yaml - with: - env-name: ${{ needs.changes-detection.outputs.env-name}} - image-name: personal-finance-assistance-java/payment-api - container-app-env-name: ${{ vars.ACA_DEV_ENV_NAME}} - container-app-name: ${{ vars.PAYMENTS_ACA_DEV_APP_NAME }} - secrets: inherit - - build-frontend-app: - needs: changes-detection - if : ${{ needs.changes-detection.outputs.build-frontend == 'true' }} - uses: ./.github/workflows/acr-build-push.yaml - with: - env-name: ${{ needs.changes-detection.outputs.env-name}} - image-name: personal-finance-assistance-java/web - app-folder-path: ./app/frontend - secrets: inherit - - deploy-frontend-app: - needs: [changes-detection,build-frontend-app] - if: ${{ needs.changes-detection.outputs.build-frontend == 'true' }} - uses: ./.github/workflows/aca-deploy.yaml - with: - env-name: ${{ needs.changes-detection.outputs.env-name}} - image-name: personal-finance-assistance-java/web - container-app-env-name: ${{ vars.ACA_DEV_ENV_NAME}} - container-app-name: ${{ vars.WEB_ACA_DEV_APP_NAME }} - secrets: inherit - - build-copilot-app: - needs: changes-detection - if : ${{ needs.changes-detection.outputs.build-copilot == 'true' }} - uses: ./.github/workflows/acr-build-push.yaml - with: - env-name: ${{ needs.changes-detection.outputs.env-name}} - image-name: personal-finance-assistance-java/copilot - app-folder-path: ./app/copilot - secrets: inherit - - deploy-copilot-app: - needs: [changes-detection,build-copilot-app] - if: ${{ needs.changes-detection.outputs.build-copilot == 'true' }} - uses: ./.github/workflows/aca-deploy.yaml - with: - env-name: ${{ needs.changes-detection.outputs.env-name}} - image-name: personal-finance-assistance-java/copilot - container-app-env-name: ${{ vars.ACA_DEV_ENV_NAME}} - container-app-name: ${{ vars.COPILOT_ACA_DEV_APP_NAME }} - secrets: inherit +name: Container Apps CI/CD pipeline + +on: + push: + branches: + - main + paths: + - "app/**" + tags: + - v*.*.* + workflow_dispatch: + +jobs: + changes-detection: + runs-on: ubuntu-latest + outputs: + env-name: ${{steps.set-deploy-env.outputs.DEPLOY_ENVIRONMENT}} + build-copilot: ${{ steps.changes.outputs.copilot }} + build-frontend: ${{ steps.changes.outputs.frontend }} + build-account-api: ${{ steps.changes.outputs.account-api }} + build-payment-api: ${{ steps.changes.outputs.payment-api }} + build-transaction-api: ${{ steps.changes.outputs.transaction-api }} + steps: + - uses: actions/checkout@v2 + - name: Filter Changes + uses: dorny/paths-filter@v2 + id: changes + with: + filters: | + copilot: + - 'app/copilot/**' + frontend: + - 'app/frontend/**' + account-api: + - 'app/business-api/account/**' + payment-api: + - 'app/business-api/payment/**' + transaction-api: + - 'app/business-api/transactions-history/**' + + - name: Set environment for branch + id: set-deploy-env + run: | + echo "checking branch name [${{github.ref_name}}]" + if [[ ${{github.ref_name}} == 'main' ]]; then + echo "main branch detected. Set Development environment" + echo "DEPLOY_ENVIRONMENT=Development" >> "$GITHUB_OUTPUT" + elif [[ ${{github.ref_name}} == *'release'* ]]; then + echo "release branch detected. Set Test environment" + echo "DEPLOY_ENVIRONMENT=Test" >> "$GITHUB_OUTPUT" + elif [[ ${{github.ref_name}} == *'v'* ]]; then + echo "tag detected. Set Production environment" + echo "DEPLOY_ENVIRONMENT=Production" >> "$GITHUB_OUTPUT" + else + echo "branch not detected. Set Development environment as default" + echo "DEPLOY_ENVIRONMENT=Development" >> "$GITHUB_OUTPUT" + fi + + build-account-app: + needs: changes-detection + if : ${{ needs.changes-detection.outputs.build-account-api == 'true' }} + uses: ./.github/workflows/acr-build-push.yaml + with: + env-name: ${{ needs.changes-detection.outputs.env-name}} + image-name: personal-finance-assistance-java/account-api + app-folder-path: ./app/business-api/account + secrets: inherit + + deploy-account-app: + needs: [changes-detection,build-account-app] + if: ${{ needs.changes-detection.outputs.build-account-api == 'true' }} + uses: ./.github/workflows/aca-deploy.yaml + with: + env-name: ${{ needs.changes-detection.outputs.env-name}} + image-name: personal-finance-assistance-java/account-api + container-app-env-name: ${{ vars.ACA_DEV_ENV_NAME}} + container-app-name: ${{ vars.ACCOUNTS_ACA_DEV_APP_NAME }} + secrets: inherit + + build-transaction-app: + needs: changes-detection + if : ${{ needs.changes-detection.outputs.build-transaction-api == 'true' }} + uses: ./.github/workflows/acr-build-push.yaml + with: + env-name: ${{ needs.changes-detection.outputs.env-name}} + image-name: personal-finance-assistance-java/transactions-history-api + app-folder-path: ./app/business-api/transactions-history + secrets: inherit + + deploy-transaction-app: + needs: [changes-detection,build-transaction-app] + if: ${{ needs.changes-detection.outputs.build-transaction-api == 'true' }} + uses: ./.github/workflows/aca-deploy.yaml + with: + env-name: ${{ needs.changes-detection.outputs.env-name}} + image-name: personal-finance-assistance-java/transactions-history-api + container-app-env-name: ${{ vars.ACA_DEV_ENV_NAME}} + container-app-name: ${{ vars.TRANSACTIONS_ACA_DEV_APP_NAME }} + secrets: inherit + build-payment-app: + needs: changes-detection + if : ${{ needs.changes-detection.outputs.build-payment-api == 'true' }} + uses: ./.github/workflows/acr-build-push.yaml + with: + env-name: ${{ needs.changes-detection.outputs.env-name}} + image-name: personal-finance-assistance-java/payment-api + app-folder-path: ./app/business-api/payment + secrets: inherit + + deploy-payment-app: + needs: [changes-detection,build-payment-app] + if: ${{ needs.changes-detection.outputs.build-payment-api == 'true' }} + uses: ./.github/workflows/aca-deploy.yaml + with: + env-name: ${{ needs.changes-detection.outputs.env-name}} + image-name: personal-finance-assistance-java/payment-api + container-app-env-name: ${{ vars.ACA_DEV_ENV_NAME}} + container-app-name: ${{ vars.PAYMENTS_ACA_DEV_APP_NAME }} + secrets: inherit + + build-frontend-app: + needs: changes-detection + if : ${{ needs.changes-detection.outputs.build-frontend == 'true' }} + uses: ./.github/workflows/acr-build-push.yaml + with: + env-name: ${{ needs.changes-detection.outputs.env-name}} + image-name: personal-finance-assistance-java/web + app-folder-path: ./app/frontend + secrets: inherit + + deploy-frontend-app: + needs: [changes-detection,build-frontend-app] + if: ${{ needs.changes-detection.outputs.build-frontend == 'true' }} + uses: ./.github/workflows/aca-deploy.yaml + with: + env-name: ${{ needs.changes-detection.outputs.env-name}} + image-name: personal-finance-assistance-java/web + container-app-env-name: ${{ vars.ACA_DEV_ENV_NAME}} + container-app-name: ${{ vars.WEB_ACA_DEV_APP_NAME }} + secrets: inherit + + build-copilot-app: + needs: changes-detection + if : ${{ needs.changes-detection.outputs.build-copilot == 'true' }} + uses: ./.github/workflows/acr-build-push.yaml + with: + env-name: ${{ needs.changes-detection.outputs.env-name}} + image-name: personal-finance-assistance-java/copilot + app-folder-path: ./app/copilot + secrets: inherit + + deploy-copilot-app: + needs: [changes-detection,build-copilot-app] + if: ${{ needs.changes-detection.outputs.build-copilot == 'true' }} + uses: ./.github/workflows/aca-deploy.yaml + with: + env-name: ${{ needs.changes-detection.outputs.env-name}} + image-name: personal-finance-assistance-java/copilot + container-app-env-name: ${{ vars.ACA_DEV_ENV_NAME}} + container-app-name: ${{ vars.COPILOT_ACA_DEV_APP_NAME }} + secrets: inherit \ No newline at end of file diff --git a/infra/shared/monitor/applicationinsights-dashboard.bicep b/infra/shared/monitor/applicationinsights-dashboard.bicep new file mode 100644 index 0000000..d082e66 --- /dev/null +++ b/infra/shared/monitor/applicationinsights-dashboard.bicep @@ -0,0 +1,1236 @@ +metadata description = 'Creates a dashboard for an Application Insights instance.' +param name string +param applicationInsightsName string +param location string = resourceGroup().location +param tags object = {} + +// 2020-09-01-preview because that is the latest valid version +resource applicationInsightsDashboard 'Microsoft.Portal/dashboards@2020-09-01-preview' = { + name: name + location: location + tags: tags + properties: { + lenses: [ + { + order: 0 + parts: [ + { + position: { + x: 0 + y: 0 + colSpan: 2 + rowSpan: 1 + } + metadata: { + inputs: [ + { + name: 'id' + value: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + { + name: 'Version' + value: '1.0' + } + ] + #disable-next-line BCP036 + type: 'Extension/AppInsightsExtension/PartType/AspNetOverviewPinnedPart' + asset: { + idInputName: 'id' + type: 'ApplicationInsights' + } + defaultMenuItemId: 'overview' + } + } + { + position: { + x: 2 + y: 0 + colSpan: 1 + rowSpan: 1 + } + metadata: { + inputs: [ + { + name: 'ComponentId' + value: { + Name: applicationInsights.name + SubscriptionId: subscription().subscriptionId + ResourceGroup: resourceGroup().name + } + } + { + name: 'Version' + value: '1.0' + } + ] + #disable-next-line BCP036 + type: 'Extension/AppInsightsExtension/PartType/ProactiveDetectionAsyncPart' + asset: { + idInputName: 'ComponentId' + type: 'ApplicationInsights' + } + defaultMenuItemId: 'ProactiveDetection' + } + } + { + position: { + x: 3 + y: 0 + colSpan: 1 + rowSpan: 1 + } + metadata: { + inputs: [ + { + name: 'ComponentId' + value: { + Name: applicationInsights.name + SubscriptionId: subscription().subscriptionId + ResourceGroup: resourceGroup().name + } + } + { + name: 'ResourceId' + value: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + ] + #disable-next-line BCP036 + type: 'Extension/AppInsightsExtension/PartType/QuickPulseButtonSmallPart' + asset: { + idInputName: 'ComponentId' + type: 'ApplicationInsights' + } + } + } + { + position: { + x: 4 + y: 0 + colSpan: 1 + rowSpan: 1 + } + metadata: { + inputs: [ + { + name: 'ComponentId' + value: { + Name: applicationInsights.name + SubscriptionId: subscription().subscriptionId + ResourceGroup: resourceGroup().name + } + } + { + name: 'TimeContext' + value: { + durationMs: 86400000 + endTime: null + createdTime: '2018-05-04T01:20:33.345Z' + isInitialTime: true + grain: 1 + useDashboardTimeRange: false + } + } + { + name: 'Version' + value: '1.0' + } + ] + #disable-next-line BCP036 + type: 'Extension/AppInsightsExtension/PartType/AvailabilityNavButtonPart' + asset: { + idInputName: 'ComponentId' + type: 'ApplicationInsights' + } + } + } + { + position: { + x: 5 + y: 0 + colSpan: 1 + rowSpan: 1 + } + metadata: { + inputs: [ + { + name: 'ComponentId' + value: { + Name: applicationInsights.name + SubscriptionId: subscription().subscriptionId + ResourceGroup: resourceGroup().name + } + } + { + name: 'TimeContext' + value: { + durationMs: 86400000 + endTime: null + createdTime: '2018-05-08T18:47:35.237Z' + isInitialTime: true + grain: 1 + useDashboardTimeRange: false + } + } + { + name: 'ConfigurationId' + value: '78ce933e-e864-4b05-a27b-71fd55a6afad' + } + ] + #disable-next-line BCP036 + type: 'Extension/AppInsightsExtension/PartType/AppMapButtonPart' + asset: { + idInputName: 'ComponentId' + type: 'ApplicationInsights' + } + } + } + { + position: { + x: 0 + y: 1 + colSpan: 3 + rowSpan: 1 + } + metadata: { + inputs: [] + type: 'Extension/HubsExtension/PartType/MarkdownPart' + settings: { + content: { + settings: { + content: '# Usage' + title: '' + subtitle: '' + } + } + } + } + } + { + position: { + x: 3 + y: 1 + colSpan: 1 + rowSpan: 1 + } + metadata: { + inputs: [ + { + name: 'ComponentId' + value: { + Name: applicationInsights.name + SubscriptionId: subscription().subscriptionId + ResourceGroup: resourceGroup().name + } + } + { + name: 'TimeContext' + value: { + durationMs: 86400000 + endTime: null + createdTime: '2018-05-04T01:22:35.782Z' + isInitialTime: true + grain: 1 + useDashboardTimeRange: false + } + } + ] + #disable-next-line BCP036 + type: 'Extension/AppInsightsExtension/PartType/UsageUsersOverviewPart' + asset: { + idInputName: 'ComponentId' + type: 'ApplicationInsights' + } + } + } + { + position: { + x: 4 + y: 1 + colSpan: 3 + rowSpan: 1 + } + metadata: { + inputs: [] + type: 'Extension/HubsExtension/PartType/MarkdownPart' + settings: { + content: { + settings: { + content: '# Reliability' + title: '' + subtitle: '' + } + } + } + } + } + { + position: { + x: 7 + y: 1 + colSpan: 1 + rowSpan: 1 + } + metadata: { + inputs: [ + { + name: 'ResourceId' + value: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + { + name: 'DataModel' + value: { + version: '1.0.0' + timeContext: { + durationMs: 86400000 + createdTime: '2018-05-04T23:42:40.072Z' + isInitialTime: false + grain: 1 + useDashboardTimeRange: false + } + } + isOptional: true + } + { + name: 'ConfigurationId' + value: '8a02f7bf-ac0f-40e1-afe9-f0e72cfee77f' + isOptional: true + } + ] + #disable-next-line BCP036 + type: 'Extension/AppInsightsExtension/PartType/CuratedBladeFailuresPinnedPart' + isAdapter: true + asset: { + idInputName: 'ResourceId' + type: 'ApplicationInsights' + } + defaultMenuItemId: 'failures' + } + } + { + position: { + x: 8 + y: 1 + colSpan: 3 + rowSpan: 1 + } + metadata: { + inputs: [] + type: 'Extension/HubsExtension/PartType/MarkdownPart' + settings: { + content: { + settings: { + content: '# Responsiveness\r\n' + title: '' + subtitle: '' + } + } + } + } + } + { + position: { + x: 11 + y: 1 + colSpan: 1 + rowSpan: 1 + } + metadata: { + inputs: [ + { + name: 'ResourceId' + value: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + { + name: 'DataModel' + value: { + version: '1.0.0' + timeContext: { + durationMs: 86400000 + createdTime: '2018-05-04T23:43:37.804Z' + isInitialTime: false + grain: 1 + useDashboardTimeRange: false + } + } + isOptional: true + } + { + name: 'ConfigurationId' + value: '2a8ede4f-2bee-4b9c-aed9-2db0e8a01865' + isOptional: true + } + ] + #disable-next-line BCP036 + type: 'Extension/AppInsightsExtension/PartType/CuratedBladePerformancePinnedPart' + isAdapter: true + asset: { + idInputName: 'ResourceId' + type: 'ApplicationInsights' + } + defaultMenuItemId: 'performance' + } + } + { + position: { + x: 12 + y: 1 + colSpan: 3 + rowSpan: 1 + } + metadata: { + inputs: [] + type: 'Extension/HubsExtension/PartType/MarkdownPart' + settings: { + content: { + settings: { + content: '# Browser' + title: '' + subtitle: '' + } + } + } + } + } + { + position: { + x: 15 + y: 1 + colSpan: 1 + rowSpan: 1 + } + metadata: { + inputs: [ + { + name: 'ComponentId' + value: { + Name: applicationInsights.name + SubscriptionId: subscription().subscriptionId + ResourceGroup: resourceGroup().name + } + } + { + name: 'MetricsExplorerJsonDefinitionId' + value: 'BrowserPerformanceTimelineMetrics' + } + { + name: 'TimeContext' + value: { + durationMs: 86400000 + createdTime: '2018-05-08T12:16:27.534Z' + isInitialTime: false + grain: 1 + useDashboardTimeRange: false + } + } + { + name: 'CurrentFilter' + value: { + eventTypes: [ + 4 + 1 + 3 + 5 + 2 + 6 + 13 + ] + typeFacets: {} + isPermissive: false + } + } + { + name: 'id' + value: { + Name: applicationInsights.name + SubscriptionId: subscription().subscriptionId + ResourceGroup: resourceGroup().name + } + } + { + name: 'Version' + value: '1.0' + } + ] + #disable-next-line BCP036 + type: 'Extension/AppInsightsExtension/PartType/MetricsExplorerBladePinnedPart' + asset: { + idInputName: 'ComponentId' + type: 'ApplicationInsights' + } + defaultMenuItemId: 'browser' + } + } + { + position: { + x: 0 + y: 2 + colSpan: 4 + rowSpan: 3 + } + metadata: { + inputs: [ + { + name: 'options' + value: { + chart: { + metrics: [ + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'sessions/count' + aggregationType: 5 + namespace: 'microsoft.insights/components/kusto' + metricVisualization: { + displayName: 'Sessions' + color: '#47BDF5' + } + } + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'users/count' + aggregationType: 5 + namespace: 'microsoft.insights/components/kusto' + metricVisualization: { + displayName: 'Users' + color: '#7E58FF' + } + } + ] + title: 'Unique sessions and users' + visualization: { + chartType: 2 + legendVisualization: { + isVisible: true + position: 2 + hideSubtitle: false + } + axisVisualization: { + x: { + isVisible: true + axisType: 2 + } + y: { + isVisible: true + axisType: 1 + } + } + } + openBladeOnClick: { + openBlade: true + destinationBlade: { + extensionName: 'HubsExtension' + bladeName: 'ResourceMenuBlade' + parameters: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + menuid: 'segmentationUsers' + } + } + } + } + } + } + { + name: 'sharedTimeRange' + isOptional: true + } + ] + #disable-next-line BCP036 + type: 'Extension/HubsExtension/PartType/MonitorChartPart' + settings: {} + } + } + { + position: { + x: 4 + y: 2 + colSpan: 4 + rowSpan: 3 + } + metadata: { + inputs: [ + { + name: 'options' + value: { + chart: { + metrics: [ + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'requests/failed' + aggregationType: 7 + namespace: 'microsoft.insights/components' + metricVisualization: { + displayName: 'Failed requests' + color: '#EC008C' + } + } + ] + title: 'Failed requests' + visualization: { + chartType: 3 + legendVisualization: { + isVisible: true + position: 2 + hideSubtitle: false + } + axisVisualization: { + x: { + isVisible: true + axisType: 2 + } + y: { + isVisible: true + axisType: 1 + } + } + } + openBladeOnClick: { + openBlade: true + destinationBlade: { + extensionName: 'HubsExtension' + bladeName: 'ResourceMenuBlade' + parameters: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + menuid: 'failures' + } + } + } + } + } + } + { + name: 'sharedTimeRange' + isOptional: true + } + ] + #disable-next-line BCP036 + type: 'Extension/HubsExtension/PartType/MonitorChartPart' + settings: {} + } + } + { + position: { + x: 8 + y: 2 + colSpan: 4 + rowSpan: 3 + } + metadata: { + inputs: [ + { + name: 'options' + value: { + chart: { + metrics: [ + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'requests/duration' + aggregationType: 4 + namespace: 'microsoft.insights/components' + metricVisualization: { + displayName: 'Server response time' + color: '#00BCF2' + } + } + ] + title: 'Server response time' + visualization: { + chartType: 2 + legendVisualization: { + isVisible: true + position: 2 + hideSubtitle: false + } + axisVisualization: { + x: { + isVisible: true + axisType: 2 + } + y: { + isVisible: true + axisType: 1 + } + } + } + openBladeOnClick: { + openBlade: true + destinationBlade: { + extensionName: 'HubsExtension' + bladeName: 'ResourceMenuBlade' + parameters: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + menuid: 'performance' + } + } + } + } + } + } + { + name: 'sharedTimeRange' + isOptional: true + } + ] + #disable-next-line BCP036 + type: 'Extension/HubsExtension/PartType/MonitorChartPart' + settings: {} + } + } + { + position: { + x: 12 + y: 2 + colSpan: 4 + rowSpan: 3 + } + metadata: { + inputs: [ + { + name: 'options' + value: { + chart: { + metrics: [ + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'browserTimings/networkDuration' + aggregationType: 4 + namespace: 'microsoft.insights/components' + metricVisualization: { + displayName: 'Page load network connect time' + color: '#7E58FF' + } + } + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'browserTimings/processingDuration' + aggregationType: 4 + namespace: 'microsoft.insights/components' + metricVisualization: { + displayName: 'Client processing time' + color: '#44F1C8' + } + } + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'browserTimings/sendDuration' + aggregationType: 4 + namespace: 'microsoft.insights/components' + metricVisualization: { + displayName: 'Send request time' + color: '#EB9371' + } + } + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'browserTimings/receiveDuration' + aggregationType: 4 + namespace: 'microsoft.insights/components' + metricVisualization: { + displayName: 'Receiving response time' + color: '#0672F1' + } + } + ] + title: 'Average page load time breakdown' + visualization: { + chartType: 3 + legendVisualization: { + isVisible: true + position: 2 + hideSubtitle: false + } + axisVisualization: { + x: { + isVisible: true + axisType: 2 + } + y: { + isVisible: true + axisType: 1 + } + } + } + } + } + } + { + name: 'sharedTimeRange' + isOptional: true + } + ] + #disable-next-line BCP036 + type: 'Extension/HubsExtension/PartType/MonitorChartPart' + settings: {} + } + } + { + position: { + x: 0 + y: 5 + colSpan: 4 + rowSpan: 3 + } + metadata: { + inputs: [ + { + name: 'options' + value: { + chart: { + metrics: [ + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'availabilityResults/availabilityPercentage' + aggregationType: 4 + namespace: 'microsoft.insights/components' + metricVisualization: { + displayName: 'Availability' + color: '#47BDF5' + } + } + ] + title: 'Average availability' + visualization: { + chartType: 3 + legendVisualization: { + isVisible: true + position: 2 + hideSubtitle: false + } + axisVisualization: { + x: { + isVisible: true + axisType: 2 + } + y: { + isVisible: true + axisType: 1 + } + } + } + openBladeOnClick: { + openBlade: true + destinationBlade: { + extensionName: 'HubsExtension' + bladeName: 'ResourceMenuBlade' + parameters: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + menuid: 'availability' + } + } + } + } + } + } + { + name: 'sharedTimeRange' + isOptional: true + } + ] + #disable-next-line BCP036 + type: 'Extension/HubsExtension/PartType/MonitorChartPart' + settings: {} + } + } + { + position: { + x: 4 + y: 5 + colSpan: 4 + rowSpan: 3 + } + metadata: { + inputs: [ + { + name: 'options' + value: { + chart: { + metrics: [ + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'exceptions/server' + aggregationType: 7 + namespace: 'microsoft.insights/components' + metricVisualization: { + displayName: 'Server exceptions' + color: '#47BDF5' + } + } + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'dependencies/failed' + aggregationType: 7 + namespace: 'microsoft.insights/components' + metricVisualization: { + displayName: 'Dependency failures' + color: '#7E58FF' + } + } + ] + title: 'Server exceptions and Dependency failures' + visualization: { + chartType: 2 + legendVisualization: { + isVisible: true + position: 2 + hideSubtitle: false + } + axisVisualization: { + x: { + isVisible: true + axisType: 2 + } + y: { + isVisible: true + axisType: 1 + } + } + } + } + } + } + { + name: 'sharedTimeRange' + isOptional: true + } + ] + #disable-next-line BCP036 + type: 'Extension/HubsExtension/PartType/MonitorChartPart' + settings: {} + } + } + { + position: { + x: 8 + y: 5 + colSpan: 4 + rowSpan: 3 + } + metadata: { + inputs: [ + { + name: 'options' + value: { + chart: { + metrics: [ + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'performanceCounters/processorCpuPercentage' + aggregationType: 4 + namespace: 'microsoft.insights/components' + metricVisualization: { + displayName: 'Processor time' + color: '#47BDF5' + } + } + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'performanceCounters/processCpuPercentage' + aggregationType: 4 + namespace: 'microsoft.insights/components' + metricVisualization: { + displayName: 'Process CPU' + color: '#7E58FF' + } + } + ] + title: 'Average processor and process CPU utilization' + visualization: { + chartType: 2 + legendVisualization: { + isVisible: true + position: 2 + hideSubtitle: false + } + axisVisualization: { + x: { + isVisible: true + axisType: 2 + } + y: { + isVisible: true + axisType: 1 + } + } + } + } + } + } + { + name: 'sharedTimeRange' + isOptional: true + } + ] + #disable-next-line BCP036 + type: 'Extension/HubsExtension/PartType/MonitorChartPart' + settings: {} + } + } + { + position: { + x: 12 + y: 5 + colSpan: 4 + rowSpan: 3 + } + metadata: { + inputs: [ + { + name: 'options' + value: { + chart: { + metrics: [ + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'exceptions/browser' + aggregationType: 7 + namespace: 'microsoft.insights/components' + metricVisualization: { + displayName: 'Browser exceptions' + color: '#47BDF5' + } + } + ] + title: 'Browser exceptions' + visualization: { + chartType: 2 + legendVisualization: { + isVisible: true + position: 2 + hideSubtitle: false + } + axisVisualization: { + x: { + isVisible: true + axisType: 2 + } + y: { + isVisible: true + axisType: 1 + } + } + } + } + } + } + { + name: 'sharedTimeRange' + isOptional: true + } + ] + #disable-next-line BCP036 + type: 'Extension/HubsExtension/PartType/MonitorChartPart' + settings: {} + } + } + { + position: { + x: 0 + y: 8 + colSpan: 4 + rowSpan: 3 + } + metadata: { + inputs: [ + { + name: 'options' + value: { + chart: { + metrics: [ + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'availabilityResults/count' + aggregationType: 7 + namespace: 'microsoft.insights/components' + metricVisualization: { + displayName: 'Availability test results count' + color: '#47BDF5' + } + } + ] + title: 'Availability test results count' + visualization: { + chartType: 2 + legendVisualization: { + isVisible: true + position: 2 + hideSubtitle: false + } + axisVisualization: { + x: { + isVisible: true + axisType: 2 + } + y: { + isVisible: true + axisType: 1 + } + } + } + } + } + } + { + name: 'sharedTimeRange' + isOptional: true + } + ] + #disable-next-line BCP036 + type: 'Extension/HubsExtension/PartType/MonitorChartPart' + settings: {} + } + } + { + position: { + x: 4 + y: 8 + colSpan: 4 + rowSpan: 3 + } + metadata: { + inputs: [ + { + name: 'options' + value: { + chart: { + metrics: [ + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'performanceCounters/processIOBytesPerSecond' + aggregationType: 4 + namespace: 'microsoft.insights/components' + metricVisualization: { + displayName: 'Process IO rate' + color: '#47BDF5' + } + } + ] + title: 'Average process I/O rate' + visualization: { + chartType: 2 + legendVisualization: { + isVisible: true + position: 2 + hideSubtitle: false + } + axisVisualization: { + x: { + isVisible: true + axisType: 2 + } + y: { + isVisible: true + axisType: 1 + } + } + } + } + } + } + { + name: 'sharedTimeRange' + isOptional: true + } + ] + #disable-next-line BCP036 + type: 'Extension/HubsExtension/PartType/MonitorChartPart' + settings: {} + } + } + { + position: { + x: 8 + y: 8 + colSpan: 4 + rowSpan: 3 + } + metadata: { + inputs: [ + { + name: 'options' + value: { + chart: { + metrics: [ + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'performanceCounters/memoryAvailableBytes' + aggregationType: 4 + namespace: 'microsoft.insights/components' + metricVisualization: { + displayName: 'Available memory' + color: '#47BDF5' + } + } + ] + title: 'Average available memory' + visualization: { + chartType: 2 + legendVisualization: { + isVisible: true + position: 2 + hideSubtitle: false + } + axisVisualization: { + x: { + isVisible: true + axisType: 2 + } + y: { + isVisible: true + axisType: 1 + } + } + } + } + } + } + { + name: 'sharedTimeRange' + isOptional: true + } + ] + #disable-next-line BCP036 + type: 'Extension/HubsExtension/PartType/MonitorChartPart' + settings: {} + } + } + ] + } + ] + } +} + +resource applicationInsights 'Microsoft.Insights/components@2020-02-02' existing = { + name: applicationInsightsName +} diff --git a/infra/shared/monitor/applicationinsights.bicep b/infra/shared/monitor/applicationinsights.bicep new file mode 100644 index 0000000..850e9fe --- /dev/null +++ b/infra/shared/monitor/applicationinsights.bicep @@ -0,0 +1,31 @@ +metadata description = 'Creates an Application Insights instance based on an existing Log Analytics workspace.' +param name string +param dashboardName string = '' +param location string = resourceGroup().location +param tags object = {} +param logAnalyticsWorkspaceId string + +resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = { + name: name + location: location + tags: tags + kind: 'web' + properties: { + Application_Type: 'web' + WorkspaceResourceId: logAnalyticsWorkspaceId + } +} + +module applicationInsightsDashboard 'applicationinsights-dashboard.bicep' = if (!empty(dashboardName)) { + name: 'application-insights-dashboard' + params: { + name: dashboardName + location: location + applicationInsightsName: applicationInsights.name + } +} + +output connectionString string = applicationInsights.properties.ConnectionString +output id string = applicationInsights.id +output instrumentationKey string = applicationInsights.properties.InstrumentationKey +output name string = applicationInsights.name diff --git a/infra/shared/monitor/loganalytics.bicep b/infra/shared/monitor/loganalytics.bicep new file mode 100644 index 0000000..2f3faf1 --- /dev/null +++ b/infra/shared/monitor/loganalytics.bicep @@ -0,0 +1,23 @@ +metadata description = 'Creates a Log Analytics workspace.' +param name string +param location string = resourceGroup().location +param tags object = {} + +resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2021-12-01-preview' = { + name: name + location: location + tags: tags + properties: any({ + retentionInDays: 30 + features: { + searchVersion: 1 + } + sku: { + name: 'PerGB2018' + } + }) +} + +output id string = logAnalytics.id +output name string = logAnalytics.name + diff --git a/infra/shared/monitor/monitoring.bicep b/infra/shared/monitor/monitoring.bicep new file mode 100644 index 0000000..12822bf --- /dev/null +++ b/infra/shared/monitor/monitoring.bicep @@ -0,0 +1,34 @@ +metadata description = 'Creates an Application Insights instance and a Log Analytics workspace.' +param logAnalyticsName string +param applicationInsightsName string +param applicationInsightsDashboardName string = '' +param location string = resourceGroup().location +param tags object = {} + +module logAnalytics 'loganalytics.bicep' = { + name: 'loganalytics' + params: { + name: logAnalyticsName + location: location + tags: tags + } +} + +module applicationInsights 'applicationinsights.bicep' = { + name: 'applicationinsights' + params: { + name: applicationInsightsName + location: location + tags: tags + dashboardName: applicationInsightsDashboardName + logAnalyticsWorkspaceId: logAnalytics.outputs.id + } +} + +output applicationInsightsConnectionString string = applicationInsights.outputs.connectionString +output applicationInsightsId string = applicationInsights.outputs.id +output applicationInsightsInstrumentationKey string = applicationInsights.outputs.instrumentationKey +output applicationInsightsName string = applicationInsights.outputs.name +output logAnalyticsWorkspaceId string = logAnalytics.outputs.id +output logAnalyticsWorkspaceName string = logAnalytics.outputs.name +