SimplePSLogger.AzLogAnalytics/SimplePSLogger.AzLogAnalytics.psm1
<#
Source - https://docs.microsoft.com/en-us/azure/azure-monitor/platform/data-collector-api#powershell-sample #> Function Build-Signature ($customerId, $sharedKey, $date, $contentLength, $method, $contentType, $resource) { $xHeaders = "x-ms-date:" + $date $stringToHash = $method + "`n" + $contentLength + "`n" + $contentType + "`n" + $xHeaders + "`n" + $resource $bytesToHash = [Text.Encoding]::UTF8.GetBytes($stringToHash) $keyBytes = [Convert]::FromBase64String($sharedKey) $sha256 = New-Object System.Security.Cryptography.HMACSHA256 $sha256.Key = $keyBytes $calculatedHash = $sha256.ComputeHash($bytesToHash) $encodedHash = [Convert]::ToBase64String($calculatedHash) $authorization = 'SharedKey {0}:{1}' -f $customerId, $encodedHash return $authorization } <# #> Function Send-LogAnalyticsData($customerId, $sharedKey, $body, $logType) { $method = "POST" $contentType = "application/json" $resource = "/api/logs" $rfc1123date = [DateTime]::UtcNow.ToString("r") $contentLength = $body.Length $signature = Build-Signature ` -customerId $customerId ` -sharedKey $sharedKey ` -date $rfc1123date ` -contentLength $contentLength ` -method $method ` -contentType $contentType ` -resource $resource if (-Not $logType) { $logType = "SimplePSLogger" } $headers = @{ "Authorization" = $signature; "Log-Type" = $logType; "x-ms-date" = $rfc1123date; } $endpoint = "https://" + $customerId + ".ods.opinsights.azure.com" + $resource + "?api-version=2016-04-01" try { $params = @{ "ContentType" = "application/json" "Header" = $headers "Body" = $body "Method" = "POST" "URI" = $endpoint } # TODO : add status code check and resiliency $response = Invoke-RestMethod @params } catch { throw } } <# .SYNOPSIS AzLogAnalytics logging provider for SimplePSLogger logger This provider send log to Azure Log Analytics https://dev.loganalytics.io/documentation/Overview Use - https://docs.microsoft.com/en-us/azure/azure-monitor/platform/data-collector-api https://docs.microsoft.com/en-us/azure/azure-monitor/platform/metrics-store-custom-rest-api Limits - https://docs.microsoft.com/en-us/azure/azure-monitor/platform/data-collector-api#data-limits .DESCRIPTION TODO: add more details More details .PARAMETER Name SimplePSLogger action execution id which is used to identify executing action .PARAMETER Level Log level : allowed values are - "verbose", "debug", "information", "warning", "error", "critical", "none" TODO : add more infor for each level .PARAMETER Message Log message : String - plain text string OtherTypes - json serialized string .PARAMETER Config Required configuration provided by user .EXAMPLE TODO : Add examples .NOTES Author: Ganesh Raskar #> Function New-AzLogAnalytics-Logger { [CmdletBinding()] param ( [Parameter(Mandatory = $true, HelpMessage = "Name of the SimplePSLogger instance")] [string] $Name, [Parameter(Mandatory = $false, HelpMessage = "Log level, default value is information")] [string] $Level, [Parameter(Mandatory = $true, HelpMessage = "Log message")] [string] $Message, [Parameter(Mandatory = $false, HelpMessage = "Configuration object")] [object] $Config ) # TODO : SimpleLogger will pass on current provider name(my name :P) #$CurrentProviderName = "AzLogAnalytics" #$bufferedFile = Join-Path $([system.io.path]::GetTempPath()) -ChildPath "$Name.$CurrentProviderName.log" # TODO : refactor? if (-Not $Config) { Write-Warning "Configuration not provided for 'AzLogAnalytics' provider" } if (-Not $Config['WorkspaceId']) { Write-Warning "Azure Log Analytics WorkspaceId not provided for 'AzLogAnalytics' provider" } if (-Not $Config['WorkspaceKey']) { Write-Warning "Azure Log Analytics WorkspaceKey(secret) not provided for 'AzLogAnalytics' provider" } if (-Not $Config['LogType']) { $Config['LogType'] = "SimplePSLogger" } <# TODO : create buffer file and flush on buffer length match, instead of making outbound call on every .Log() call. #> $LogMsg = [System.Collections.ArrayList]@(@{ TimeStamp = $((Get-Date).ToUniversalTime().ToString("yyyy/MM/dd HH:mm:ss:ffff tt")) LoggerName = $Name Level = $Level Message = $Message }) $json = ConvertTo-Json -Compress -Depth 20 $LogMsg try { Send-LogAnalyticsData -customerId $Config['WorkspaceId'] -sharedKey $Config['WorkspaceKey'] -body $json -logType $Config['LogType'] } catch { throw } finally { # TODO : retains logs and try agian } } # TODO : is there any way to ignore other functions export? Export-ModuleMember -Function New-AzLogAnalytics-Logger, Send-LogAnalyticsData, Build-Signature |