AIException.psm1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
<#
.Synopsis
    Handle sending exceptions and Powershell errors via App Insights
 
    Two events will be sent :
    - A Trace event with the PowerShell Stack information
    - A (Client) exception event
#>

function Send-AIException
{
    [CmdletBinding(DefaultParameterSetName = "Exception")]
    #[OutputType([int])]
    Param
    (
        # An Exception from a catch clause.
        [Parameter(Mandatory=$False,ValueFromPipelineByPropertyName=$true)]
        [Parameter(ParameterSetName='Exception')]
        [System.Exception] $Exception,

        #Defaults to "unhandled"
        [Parameter(ParameterSetName='Exception')]
        $HandledAt = $null,

        # An Exception from a catch clause.
        [Parameter(Mandatory=$False,ValueFromPipelineByPropertyName=$true)]
        [Parameter(ParameterSetName='Error')]
        #[System.Management.Automation.ErrorRecord]
        $ErrorInfo,

        #Map of string to string: Additional data used to filter pages in the portal.
        $Properties = $null,
        #Map of string to number: Metrics associated with this page, displayed in Metrics Explorer on the portal.
        $Metrics = $null,

        #The Severity of the Exception 0 .. 4 : Default = 4 (Error)
        $Severity = 'Error', 

        #The AppInsights Client object to use.
        [Parameter(Mandatory=$false)]
        [Microsoft.ApplicationInsights.TelemetryClient] $Client ,
        
        #include call stack information (Default)
        [switch] $NoStack,
        #The number of Stacklevels to go up
        [int]$StackWalk = 0,

        #Directly flush the AI events to the service (Default:$True)
        [switch]$Flush=$true

    )
    #Check for a specified AI client
    if ($Client -eq $null) {
        If ( ($Global:AISingleton ) -AND ( $Global:AISingleton.Client ) ) {
            #Use Current Client
            $Client = $Global:AISingleton.Client
        }
    }
    #no need to do anything if there is no client
    if ($Client -eq $null) { 
        Write-Verbose 'No AI Client found'
        return 
    }  


    #Create a new empty AIException object
    $AIExeption = New-Object Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry


    #If an exception was passed in then
    If ( $PsCmdlet.ParameterSetName -ieq 'Exception' ) { 
        #Add The exeption
        $AIExeption.Exception = $Exception

        #Send the PowerShell StackTrace and additional info in an AI Trace
        $MSG = "PSSCallStack for exception: {0}" -f $Exception.ToString()
        Send-AITrace -Message $MSG -NoStack:$NoStack -Properties $Properties -Client:$Client -StackWalk:($StackWalk+1) -FullStack -SeverityLevel 'Error'

    } 
    
    #If an Error was passed in then
    If ( $PsCmdlet.ParameterSetName -ieq 'Error' ) { 

        $AIExeption.Exception = $ErrorInfo.Exception

        #Send the PowerShell StackTrace and additional info in an AI Trace
        $MSG = "PSSCallStack for Error: {0}" -f $ErrorInfo.ToString()
        $ErrProperties = ( $ErrorInfo | Select -ExcludeProperty InvocationInfo | ConvertTo-Hashtable ) `
                       + ( $ErrorInfo.InvocationInfo | Select -ExcludeProperty Line,PositionMessage |  ConvertTo-Hashtable )
        Send-AITrace -Message $MSG -NoStack:$NoStack -Properties $ErrProperties -Client:$Client -StackWalk:($StackWalk+1) -FullStack -SeverityLevel 'Error'

    }
    
    #ToDo : Linkup Operation ID ?

    #Add the PowerShell callstack (Full)
    #Note this is apparently ignored by AI
<#
    if ($NoStack -ne $True) {
        $dictProperties = getCallerInfo -level (2+$StackWalk) -FullStack
        #Add the caller info in the callstack
        foreach ($Prop in $dictProperties.GetEnumerator()) {
            $Result = $AIExeption.Properties.TryAdd($Prop.Key, $Prop.Value)
            #Write-Verbose $Result -Verbose
        }
    }
    #Add the Properties to Dictionary
    #Note this is apparently ignored by AI
    if ($Properties) {
        foreach ($Prop in $Properties.GetEnumerator() ) {
            $Result = $AIExeption.Properties.TryAdd($Prop.Key, $Prop.Value)
            Write-Verbose $Result -Verbose
        }
    }
    #Add metrics to Dictionary
    #Note this is apparently ignored by AI
    if ($Metrics) {
        foreach ($Metric in $Metrics.GetEnumerator()) {
            $AIExeption.Metrics.TryAdd($Metric.Name, $Metric.Value)
            Write-Verbose $Result -Verbose
        }
    }
    #>


    #Send the exeption to AI
    $client.TrackException($AIException) 

    <#
    #$client.TrackException($Exception, $HandledAt, $Properties, $Metrics, $Severity)
 
        exception
        An Error from a catch clause.
        handledAt
        Defaults to "unhandled".
        properties
        Map of string to string: Additional data used to filter exceptions in the portal. Defaults to empty.
        measurements
        Map of string to number: Metrics associated with this page, displayed in Metrics Explorer on the portal. Defaults to empty.
        severityLevel
        Supported values: SeverityLevel.ts
 
 
            SeverityLevel[SeverityLevel["Verbose"] = 0] = "Verbose";
            SeverityLevel[SeverityLevel["Information"] = 1] = "Information";
            SeverityLevel[SeverityLevel["Warning"] = 2] = "Warning";
            SeverityLevel[SeverityLevel["Error"] = 3] = "Error";
            SeverityLevel[SeverityLevel["Critical"] = 4] = "Critical";
 
 
        void TrackException(System.Exception exception,
                            System.Collections.Generic.IDictionary[string,string] properties,
                            System.Collections.Generic.IDictionary[string,double] metrics)
    #>
    
    
    if ($Flush) { 
        $client.Flush()
    }
}