4
votes

http://azure.microsoft.com/en-us/documentation/articles/app-insights-monitor-performance-live-website-now/

I have a few sites hosted on a VM on azure that is deployed with Cloud Service Webroles.

Have anyone seen examples of installing the status monitor from code or command line? Goal is to add IIS sites automaticly to Azure App Insight without logging into remote desktop as shown in the link above.

2
We're working on this very same problem today... looking at using a combination of Startup Task in the csdef + Powershell & some custom chocolately/scripting to try and hack something together. though the 4th comment from Alan Willis doesn't fill me with hope. azure.microsoft.com/en-us/documentation/articles/…Eoin Campbell
Ye, I cant figure out if one need to sign in in teh status monitor also or its enough to install it and then add the AI stuff to the website solution.Poul K. Sørensen

2 Answers

4
votes

We ran into this issue also and wrote a script, which should plug into the existing method for installing VS Online App Insights.

if(${env:InstalledStatusMonitor} -eq 1)
{
    Write-Host "Status monitor has already been installed on this machine by this script" -ForegroundColor Green
}

Write-Host "Using chocolatey to install the Web Platform Installer ..."  -ForegroundColor Green
iex ((new-object net.webclient).downloadstring('https://chocolatey.org/install.ps1'))
cinst webpi -y
Stop-Process -Name WebPlatformInstaller

Write-Host "Using Web Platform Installer to install Status Monitor ..." -ForegroundColor Green
&"$env:ProgramFiles\Microsoft\Web Platform Installer\WebpiCmd.exe" /Install /AcceptEula /Products:ApplicationInsightsStatusMonitor

Write-Host "Adding app pool account to the 'Performance Monitor Users' local group" -ForegroundColor Green
$group = "Performance Monitor Users"
$user = "Network Service"
$computer = $(Get-WmiObject Win32_Computersystem).name
$de = [ADSI]"WinNT://$computer/$group,group" 
$de.psbase.Invoke("Add",([ADSI]"WinNT://$user").path)
Write-Host "Waiting 30 seconds for Status Monitor to finish its install ..." -ForegroundColor Green
Start-Sleep -Seconds 30

Write-Host "Stop-Starting services to enable tracing..." -ForegroundColor Green
# For some reason, even though Status Monitor calls "iisreset.exe /restart"
# calling it here leaves IIS and website stopped.
&iisreset.exe /restart

Write-Host "waiting a few seconds..." -ForegroundColor Yellow
Start-Sleep -Seconds 2
Write-Host "starting..." -ForegroundColor Yellow

Start-Service -Name W3SVC
Get-WebApplication | Select ApplicationPool -Unique | %{ Start-WebAppPool $_.applicationPool }
Get-Website | Start-Website
Write-Host "started" -ForegroundColor Yellow

Write-Host "Cleaning up running applications" -ForegroundColor Green
Stop-Process -Name Microsoft.Diagnostics.Agent.StatusMonitor


Write-Host "Setting environment variable to indicate status monitor has been installed" -ForegroundColor Green
[Environment]::SetEnvironmentVariable("InstalledStatusMonitor", "1", "Machine")

Write-Host "Installation complete" -ForegroundColor Green

I wrote a blog post about it here, so if we run into issues and I forget to update this post you should be able to see updates there.

Update 1

Thanks to pksorensen for the direct link, it looks like this is where the Web Platform installer downloads the package from. I've done some more with this and now have a fully automated process working. I have a sample repository available here with a working project.. This commit should describe what you need to do to your own web project to get Status Monitor working on a Web Role.

There is a post by Sergey Kanzhelev, indicating that it should be possible to do this to worker roles too.

Here are the individual steps required. I will try to provide an update on non-web roles if I get a chance to look into it:

1. ServiceDefinition.csdef

Add the following Startup entry into your web deployment project, it will run when the role is being created or deployed to.

<ServiceDefinition>
  <WebRole>

    ...

    <Startup>
      <Task commandLine="Role_Start\Bootstrap.bat" executionContext="elevated" taskType="simple">
        <Environment>
          <Variable name="EMULATED">
            <RoleInstanceValue xpath="/RoleEnvironment/Deployment/@emulated" />
          </Variable>
        </Environment>
      </Task>
    </Startup>
  </WebRole>
</ServiceDefinition>

2. WebProject/Role_Start/Bootstrap.bat

This is the batch file called by the startup task. It has to be placed in your web project. Set the properties to always copy the file to output directory.

:: The basis for this script is described here
:: http://blogs.msdn.com/b/visualstudioalm/archive/2014/04/16/new-agent-for-application-insights-available.aspx
:: The scripts can be downloaded directly from
:: http://go.microsoft.com/fwlink/?LinkID=329971

@echo off

:: Do not attempt to install the agent on an emulated environment
if "%EMULATED%"=="true" goto :EndOfScript

:: Set appropriate execution policy on the host machine
set ExecutionPolicyLevel=RemoteSigned
for /F "usebackq" %%i in (`powershell -noprofile -command "Get-ExecutionPolicy"`) do (
    set ExecutionPolicy=%%i
    if /I "%%i"=="Unrestricted" goto :AllIsWell
    if /I "%%i"=="RemoteSigned" goto :AllIsWell
    Powershell.exe -NoProfile -Command "Set-ExecutionPolicy RemoteSigned" < NUL >> NUL 2>> NUL
)

:AllIsWell

Powershell.exe -NoProfile -Command "& '%~dp0InstallStatusMonitor.ps1'" < NUL  >> NUL 2>> NUL
echo "done" >"%ROLEROOT%\startup.task.done.sem"

:EndOfScript

exit 0

3. WebProject/Role_Start/InstallStatusMonitor.ps1

Like the Bootstrap.bat file, set the properties to copy this file to the output directory also. This is an updated version of the script posted earlier

# The basis for this script is described here
# http://blogs.msdn.com/b/visualstudioalm/archive/2014/04/16/new-agent-for-application-insights-available.aspx
# The scripts can be downloaded directly from
# http://go.microsoft.com/fwlink/?LinkID=329971

#Constants
$downloadUrl = "https://go.microsoft.com/fwlink/?LinkID=512247&clcid=0x409"

# Variables
$rootDir = Split-Path $MyInvocation.MyCommand.Path
$downloadPath = Join-Path $rootDir "ApplicationInsightsAgent.msi"

# Functions
# Infrastructure functions
function TryV1
{
    param
    (
        [ScriptBlock] $Command = $(throw "The parameter -Command is required."),
        [ScriptBlock] $Catch   = { throw $_ },
        [ScriptBlock] $Finally = { }
    )

    & {
        $local:ErrorActionPreference = "SilentlyContinue"

        trap
        {
            trap
            {
                & {
                    trap { throw $_ }
                    & $Finally
                }

                throw $_
            }

            $_ | & { & $Catch }
        }

        & $Command
    }

    & {
        trap { throw $_ }
        & $Finally
    }
}

function Retry
{
    param (
        [ScriptBlock] $RetryCommand
    )

    for ($attempts=0; $attempts -lt 5; $attempts++)
    {        
        TryV1 {

            & $RetryCommand
            break

        } -Catch {

            if($attempts -lt 4)
            {
                Log-Message "Attempt:$attempts Exception Occured. Sleeping and Retrying..."
                Log-Message $_
                Log-Message $_.InvocationInfo.PositionMessage
                Start-Sleep -Seconds 1
            }
            else
            {
                throw $_
            }
        }
    }

}

function Log-Message
{
    param(
        [string] $message
    )

    $logString = ("{0}: {1}" -f (Get-Date), $message)
    $unifiedStartupInfoLogPath = Join-Path $rootDir "ApmAgentInstall.log"
    Add-Content $unifiedStartupInfoLogPath $logString
    Write-Host $logString -ForegroundColor Green
}

function Log-Error
{
    param(
        [string] $message
    )
    $logString =  ("{0}: {1}" -f (Get-Date), $message)
    $unifiedStartupErrorLogPath = Join-Path $rootDir "ApmAgentInstallError.log"
    Add-Content $unifiedStartupInfoLogPath $logString
    Write-Host $logString -ForegroundColor Red
}

# Functions
# Operations functions
function Get-AppInsightsInstallationStatus(){

    if(${env:InstalledStatusMonitor} -eq 1)
    {
        return $true
    }
    else
    {
        return $false
    }
}

function Download-StatusMonitor
{
    Retry {

        $wc = New-Object System.Net.WebClient
        $wc.DownloadFile($downloadUrl, $downloadPath)
    }
}

function Install-StatusMonitor(){
    $logPath = Join-Path $rootDir "StatusMonitorInstall.log"
    &$downloadPath /quiet /passive /log $logPath
    Log-Message "Waiting 30 seconds for Status Monitor to finish its install ..."
    Start-Sleep -Seconds 30
}

function Grant-LoggingPermissionToAppPool(){
    $groupName = "Performance Monitor Users"
    $user = "Network Service"
    $group = [ADSI]"WinNT://./$groupName,group"
    if(($group.PSBase.Invoke('Members') | %{$_.GetType().InvokeMember('Name', 'GetProperty', $null, $_, $null)}) -contains $user)
    {
        Log-Message "'$user' is already a member of '$groupName', don't need to do anything"
        return
    }    
    else
    {
        Log-Message "'$user' is now a member of '$groupName'"
        $group.Add("WinNT://$user")
    }
}

function Restart-IISOnAzureWebRole(){
    # For some reason, even though Status Monitor calls "iisreset.exe /restart"
    # calling it here leaves IIS and website stopped.
    &iisreset.exe /restart

    Log-Message "waiting a few seconds..."
    Start-Sleep -Seconds 2
    Log-Message "starting..."

    Start-Service -Name W3SVC
    Get-WebApplication | Select ApplicationPool -Unique | %{ Start-WebAppPool $_.applicationPool }
    Get-Website | Start-Website
    Log-Message "started"
}

# Main body
Log-Message "Starting Status Monitor installation"

Log-Message "Downloading component..."
Download-StatusMonitor

Log-Message "Installing component..."
Install-StatusMonitor

Log-Message "Adding app pool account to the 'Performance Monitor Users' local group"
Grant-LoggingPermissionToAppPool

Log-Message "Stop-Starting services to enable tracing..."
Restart-IISOnAzureWebRole

Log-Message "Completed installation successfully"

Update 2

If you need the capability to add custom properties to track on, such as being able to discriminate dependencies based on role names or role instances you need to get into the Application Insights pipleline earlier than is described in the documentation.

Let's say you want to be able to filter on Role Name and Role Instance Id, you would create a custom context initializer.

using System.Text.RegularExpressions;
using Microsoft.ApplicationInsights.DataContracts;
using Microsoft.WindowsAzure.ServiceRuntime;

namespace Utilities
{
    public class AppInsightsCurrentRoleIdAsTagInitializer : Microsoft.ApplicationInsights.Extensibility.IContextInitializer
    {
        public void Initialize(TelemetryContext context)
        {
            context.Properties["Greenfinch - RoleName"] = RoleEnvironment.CurrentRoleInstance.Role.Name;
            context.Properties["Greenfinch - RoleInstanceId"] = InstanceId;
        }

        private string InstanceId
        {
            get
            {
                var instanceId = Regex.Match(RoleEnvironment.CurrentRoleInstance.Id, "\\d+$", RegexOptions.Compiled).Value;
                return string.IsNullOrWhiteSpace(instanceId)
                    ? "unable to get instance id"
                    : instanceId;
            }
        }
    }
}

but instead of plugging it in in code, you would instead add it to the ApplicationInsights.config file:

<?xml version="1.0" encoding="utf-8"?>
<ApplicationInsights xmlns="http://schemas.microsoft.com/ApplicationInsights/2013/Settings" schemaVersion="2014-05-30">

  ...

  <ContextInitializers>

    ...

    <Add Type="Utilities.AppInsightsCurrentRoleIdAsTagInitializer, Utilities" />
  </ContextInitializers>

  ...

</ApplicationInsights>
0
votes

In my IAAS model, I referenced these scripts to set it up, it also uses the direct msi URL as opposed to Web Platform, before installation and restarts IIS.

I used PowerShell DSC for this and some sort of blue-green IIS resets so there are no outages, so servers could be configured with Status monitor as a part of initial provisioning and the application code could drive the telemetry.

Package AppInsights
     {                             

        Ensure      = "Present"  
        Path        = "E:\dsc\ApplicationInsightsAgent.msi" # copied at some vm location
        Name        = "Application Insights Status Monitor"
        ProductID   =  "CBF2C62C-9537-4D8E-9754-92E54A0822D4"                       
    }

If your web.config doesn't have the instrumentation key, you may use below to enable for your website in your DSC, post installation.

Import-Module 'C:\Program Files\Microsoft Application Insights\Status Monitor\PowerShell\Microsoft.Diagnostics.Agent.StatusMonitor.PowerShell.dll'
Start-ApplicationInsightsMonitoring -Name 'your web site' -InstrumentationKey '<KeyHere>'