• About
  • Contact
  • Search

Philip Van de Vyver - Azure Blog

Github Actions monitoring with Application Insights

January 03, 2024 ·

  • Introduction
  • Ingest Application Insights Request Telemetry data
    • Github Action
      • PowerShell script
    • Result
  • Ingest Application Insights Release Annotation
    • Github Action
      • PowerShell script
    • Result

Introduction

I love working with Github Actions for Continuous Integration and Deployment.

By default you get emails regarding failed workflows for Github monitoring.

To get more insights in the performance and success of workflows, you can leverage Application Insights to log performance, failures and release annotations.

introduction

To achieve this, I use:

  • The Azure SDK for .NET to ingest Request Telemetry data
  • The Application insights Rest API together with AZ CLI to ingest release annotations.

Ingest Application Insights Request Telemetry data

In this example I’m logging a successful request (ResponseCode = 200) to Application Insights.

The PowerShell script logs the duration of the request, success and some custom properties (ActionRunURL, MyTestProperty1, MyTestProperty2)

Github Action

The Github Action consist of the following:

  • Workflow trigger:
    • workflow dispatch trigger to trigger the workflow manually.
  • Environment variable:
    • APPLICATIONINSIGHTS_INSTRUMENTATIONKEY: Containing the Application Insights Instrumentation keye
  • Jobs:
    • application-insights-log-request
      • Steps:
        • set-startdatetime-var: gets the current time and sets it to an environment variable
        • login-azure: As explained in Use GitHub Actions to connect to Azure
        • application-insights-log-request: runs a PowerShell script to log the request to Application Insights

Here’s the full content of the Github Action:

name: Log - Application Insights - Request

on:
  workflow_dispatch

env:
  APPLICATIONINSIGHTS_INSTRUMENTATIONKEY: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

jobs:
  application-insights-log-request:
    runs-on: ubuntu-latest
    steps:
      - name: set-startdatetime-var
        run: |
          START_DATETIME=$(date '+%d/%m/%Y %H:%M:%S')
          echo $START_DATETIME
          echo "START_DATETIME=$START_DATETIME" >> $GITHUB_ENV
      - name: login-azure
        uses: azure/login@v1
        with:
          creds: '{"clientId":"$","clientSecret":"$","subscriptionId": "$","tenantId":"$"}'
          enable-AzPSSession: true
      - name: application-insights-log-request
        shell: pwsh
        run: |

          # set variables
          $InstrumentationKey = $env:APPLICATIONINSIGHTS_INSTRUMENTATIONKEY
          $Name = $env:GITHUB_WORKFLOW
          $Started = $env:START_DATETIME
          $Success = $true # set to false for failed
          $ResponseCode = 200 # set to 500 for failed
          $startedDateTime = [datetime]::ParseExact($Started, "dd/MM/yyyy HH:mm:ss", $Null)

          [System.TimeSpan]$Duration = New-TimeSpan -Start $startedDateTime -End (Get-Date)
          $StartedDateTimeOffset = [System.DateTimeOffset]$startedDateTime

          # setup telemetry client
          $telemetryClient = New-Object -TypeName Microsoft.ApplicationInsights.TelemetryClient
          $telemetryClient.InstrumentationKey = $InstrumentationKey

          # initialize context information
          $TelemetryClient.Context.User.Id = "$($env:GITHUB_ACTOR)"
          $telemetryClient.Context.Operation.Name = $Name

          # set telemetry context
          $TelemetryClient.Context.Session.Id = "$($env:GITHUB_REPOSITORY)/$($env:GITHUB_WORKFLOW)/$($env:GITHUB_RUN_ID)/$($env:GITHUB_JOB)"
          $telemetryClient.Context.Operation.Id = "$($env:GITHUB_REPOSITORY)/$($env:GITHUB_WORKFLOW)/$($env:GITHUB_RUN_ID)/$($env:GITHUB_JOB)"

          Write-Host "SessionId: $($TelemetryClient.Context.Session.Id)"
          Write-Host "User Id: $($TelemetryClient.Context.User.Id)"
          Write-Host "Operation Id: $($TelemetryClient.Context.Operation.Id)"
          Write-Host "Operation Name: $($TelemetryClient.Context.Operation.Name)"

          # setup request telemetry information
          $request = New-Object -TypeName Microsoft.ApplicationInsights.DataContracts.RequestTelemetry
          $request.Name = $Name
          $request.StartTime = $StartedDateTimeOffset 
          $request.Duration = $Duration
          $request.Success = $Success
          $request.ResponseCode = $ResponseCode  

          Write-Host "StartTime: $StartedDateTimeOffset"
          Write-Host "Duration: $Duration"
          Write-Host "Success: $Success"
          Write-Host "ResponseCode: $ResponseCode"

          # set actionurl
          $ActionRunURL = "$($env:GITHUB_SERVER_URL)/$($env:GITHUB_REPOSITORY)/actions/runs/$($env:GITHUB_RUN_ID)"
          Write-Host "ActionRunURL : $ActionRunURL"

          # set properties 
          [HashTable]$Properties = @{}
          $properties["ActionRunURL"] = "$ActionRunURL"
          $properties["MyTestProperty1"] = "Test 1"
          $properties["MyTestProperty2"] = "Test 2"

          # copy properties to request
          $properties.Keys | ForEach-Object { $request.Properties[$_] = $Properties[$_] }

          # track the request
          $telemetryClient.TrackRequest($request)

          # flush
          $telemetryClient.Flush()

PowerShell script

Here’s the content of the inline PowerShell script:

# set variables
$InstrumentationKey = $env:APPLICATIONINSIGHTS_INSTRUMENTATIONKEY
$Name = $env:GITHUB_WORKFLOW
$Started = $env:START_DATETIME
$Success = $true # set to false for failed
$ResponseCode = 200 # set to 500 for failed
$startedDateTime = [datetime]::ParseExact($Started, "dd/MM/yyyy HH:mm:ss", $Null)

[System.TimeSpan]$Duration = New-TimeSpan -Start $startedDateTime -End (Get-Date)
$StartedDateTimeOffset = [System.DateTimeOffset]$startedDateTime

# setup telemetry client
$telemetryClient = New-Object -TypeName Microsoft.ApplicationInsights.TelemetryClient
$telemetryClient.InstrumentationKey = $InstrumentationKey

# initialize context information
$TelemetryClient.Context.User.Id = "$($env:GITHUB_ACTOR)"
$telemetryClient.Context.Operation.Name = $Name

# set telemetry context
$TelemetryClient.Context.Session.Id = "$($env:GITHUB_REPOSITORY)/$($env:GITHUB_WORKFLOW)/$($env:GITHUB_RUN_ID)/$($env:GITHUB_JOB)"
$telemetryClient.Context.Operation.Id = "$($env:GITHUB_REPOSITORY)/$($env:GITHUB_WORKFLOW)/$($env:GITHUB_RUN_ID)/$($env:GITHUB_JOB)"

Write-Host "SessionId: $($TelemetryClient.Context.Session.Id)"
Write-Host "User Id: $($TelemetryClient.Context.User.Id)"
Write-Host "Operation Id: $($TelemetryClient.Context.Operation.Id)"
Write-Host "Operation Name: $($TelemetryClient.Context.Operation.Name)"

# setup request telemetry information
$request = New-Object -TypeName Microsoft.ApplicationInsights.DataContracts.RequestTelemetry
$request.Name = $Name
$request.StartTime = $StartedDateTimeOffset 
$request.Duration = $Duration
$request.Success = $Success
$request.ResponseCode = $ResponseCode  

Write-Host "StartTime: $StartedDateTimeOffset"
Write-Host "Duration: $Duration"
Write-Host "Success: $Success"
Write-Host "ResponseCode: $ResponseCode"

# set actionurl
$ActionRunURL = "$($env:GITHUB_SERVER_URL)/$($env:GITHUB_REPOSITORY)/actions/runs/$($env:GITHUB_RUN_ID)"
Write-Host "ActionRunURL : $ActionRunURL"

# set properties 
[HashTable]$Properties = @{}
$properties["ActionRunURL"] = "$ActionRunURL"
$properties["MyTestProperty1"] = "Test 1"
$properties["MyTestProperty2"] = "Test 2"

# copy properties to request
$properties.Keys | ForEach-Object { $request.Properties[$_] = $Properties[$_] }

# track the request
$telemetryClient.TrackRequest($request)

# flush
$telemetryClient.Flush()

Result

When the workflow ran, the following result is shown:

Request Workflow Run

Request Workflow Run

In the Application Insights instance, the following appears:

Request Operation Workflow Details

When clicking on the request, the following details are shown:

Request Operation Application Insights

Ingest Application Insights Release Annotation

In this example I’m logging a release annotation for a new release with some custom properties from the default Github environment variables.

The trigger of the request is a

Github Action

The Github Action consist of the following:

  • Workflow trigger:
    • pull request on the main branch of the repository.
  • Environment variable:
    • APPLICATION_INSIGHTS_RESOURCE_ID: Containing the Application Insights Resource Id
  • Jobs:
    • create-applicationinsightsannotation
      • Steps:
        • set-startdatetime-var: gets the current time and sets it to an environment variable
        • login-azure: As explained in Use GitHub Actions to connect to Azure
        • create-applicationinsightsannotation: runs a PowerShell script to ingest an annotation in application insights

Here’s the full content of the Github Action:

name: Log - Application Insights - Annotation

on:
  pull_request:
    branches:
    - main

env:
  APPLICATION_INSIGHTS_RESOURCE_ID: "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/rg-weu-prd-githubactionsapplicationinsights/providers/microsoft.insights/components/appi-weu-prd-githubactionsapplicationinsights"

jobs:
  create-applicationinsightsannotation:
    runs-on: ubuntu-latest
    steps:
      - name: login-azure
        uses: azure/login@v1
        with:
          creds: '{"clientId":"$","clientSecret":"$","subscriptionId": "$","tenantId":"$"}'
          enable-AzPSSession: true
      - name: set-startdatetime-var
        run: |
          START_DATETIME=$(date '+%d/%m/%Y %H:%M:%S')
          echo $START_DATETIME
          echo "START_DATETIME=$START_DATETIME" >> $GITHUB_ENV
      - name: create-applicationinsightsannotation
        id: create-applicationinsightsannotation
        uses: azure/powershell@v1
        with:
          inlineScript: |

            # set annotation properties
            $annotationProperties = @{"ReleaseDescription" = "$env:GITHUB_REF"; "TriggerBy" = "$env:GITHUB_ACTOR" }
            $annotationPropertiesJson = ConvertTo-Json $annotationProperties -Compress

            # build annotation
            $annotation = @{
                Id             = [GUID]::NewGuid();
                AnnotationName = "$($env:GITHUB_REF_NAME)";
                EventTime      = (Get-Date).ToUniversalTime().GetDateTimeFormats("s")[0];
                Category       = "Deployment"; 
                Properties     = $annotationPropertiesJson
            }

            # set body 
            $body = (ConvertTo-Json $annotation -Compress) -replace '(\\+)"', '$1$1"' -replace "`"", "`"`""

            # submit annotation
            az rest --method put --uri "$($env:APPLICATION_INSIGHTS_RESOURCE_ID)/Annotations?api-version=2015-05-01" --headers "Content-Type=application/json" --body "$($body) "

          azPSVersion: "11.1.0"
          errorActionPreference: stop

PowerShell script

# set annotation properties
$annotationProperties = @{"ReleaseDescription" = "$env:GITHUB_REF"; "TriggerBy" = "$env:GITHUB_ACTOR" }
$annotationPropertiesJson = ConvertTo-Json $annotationProperties -Compress

# build annotation
$annotation = @{
    Id             = [GUID]::NewGuid();
    AnnotationName = "$($env:GITHUB_REF_NAME)";
    EventTime      = (Get-Date).ToUniversalTime().GetDateTimeFormats("s")[0];
    Category       = "Deployment"; 
    Properties     = $annotationPropertiesJson
}

# set body 
$body = (ConvertTo-Json $annotation -Compress) -replace '(\\+)"', '$1$1"' -replace "`"", "`"`""

# submit annotation
az rest --method put --uri "$($env:APPLICATION_INSIGHTS_RESOURCE_ID)/Annotations?api-version=2015-05-01" --headers "Content-Type=application/json" --body "$($body) "

Result

When the workflow ran, the following result is shown:

Annotation Result Main

Annotation Result Run

As result, the release annotation is shown in the graph with some custom properties:

Annotation Result Application Insights