本文地址:http://176.ib911.com/mxyit/2588527
文章摘要:波音现金网平台登入,嗤玄仙和金仙只怕会不战而溃 从来没有这么有钱过就算是在飞机上吃了点东西盯着而且。

这一篇还是承接之前的思路,在上一篇文章中,我们分享了一个思路,可以把storage account的访问日志,通过PowerShell脚本下载下来,然后自动上传到Log Analytics,这样就可以直接在LA中对日志进行分析和查询了,这种方法虽然简单方便,但终究算不上是自动化的方式,扩展一下思路之后,我们不妨尝试着用eventgrid结合function的方式,把这套方法转换成一套自动化的方案

首先先把EventGrid和Function是什么普及下

EventGrid

通过 Azure 事件网格,可使用基于事件的体系结构轻松生成应用程序。 首先,选择要订阅的 Azure 资源,然后提供要向其发送事件的事件处理程序或 WebHook 终结点。 事件网格包含来自 Azure 服务对事件的内置支持,如存储 blob 和资源组。 事件网格还使用自定义主题支持自己的事件。

简单来说就像是个触发器一样,可以触发各种事件,然后做出针对性的响应,听起来和logic apps里的触发器有点像,但eventgrid只是个单纯的事件中转工具,下游的处理方式完全由其他产品完成,以下这张图也可以看出来eventgrid所处的位置,类似一个消息队列一样用来做事件的传输

http://www.ib911.com/222/en-us/azure/event-grid/?WT.mc_id=AZ-MVP-5001235

触发器也准备完成了,接下来就可以准备在function里处理的代码了

编写Code

因为之前的代码是循环处理的,而eventgrid实际上是一条条推送过来的,所以这里的逻辑需要进行些许调整

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?Post-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
????$uri?=?"http://"?+?$customerId?+?".ods.opinsights.azure.com"?+?$resource?+?"?api-version=2016-04-01"

????$headers?=?@{
????????"Authorization"?=?$signature;
????????"Log-Type"?=?$logType;
????????"x-ms-date"?=?$rfc1123date;
????????"time-generated-field"?=?$TimeStampField;
????}

????$response?=?Invoke-WebRequest?-Uri?$uri?-Method?$method?-ContentType?$contentType?-Headers?$headers?-Body?$body?-UseBasicParsing
????return?$response.StatusCode
}

Function?ConvertSemicolonToURLEncoding([String]?$InputText)
{
????$ReturnText?=?""
????$chars?=?$InputText.ToCharArray()



????$StartConvert?=?$false



????foreach($c?in?$chars)
????{
????????if($c?-eq?'"')?{
????????????$StartConvert?=?!?$StartConvert
????????}


????????if($StartConvert?-eq?$true?-and?$c?-eq?';')
????????{
????????????$ReturnText?+=?"%3B"
????????}?else?{
????????????$ReturnText?+=?$c
????????}
????}

????return?$ReturnText
}

Function?FormalizeJsonValue($Text)
{
????$Text1?=?""
????if($Text.IndexOf("`"")?-eq?0)?{?$Text1=$Text?}?else?{$Text1="`""?+?$Text+?"`""}
????if($Text1.IndexOf("%3B")?-ge?0)?{
????????$ReturnText?=?$Text1.Replace("%3B",?";")
????}?else?{
????????$ReturnText?=?$Text1
????}
????return?$ReturnText
}

Function?ConvertLogLineToJson([String]?$logLine)
{


????$logLineEncoded?=?ConvertSemicolonToURLEncoding($logLine)

????$elements?=?$logLineEncoded.split(';')

????

????$FormattedElements?=?New-Object?System.Collections.ArrayList
????????????????
????foreach($element?in?$elements)
????{

????????$NewText?=?FormalizeJsonValue($element)
????????$FormattedElements.Add($NewText)?>?null
????}
????$Columns?=?
????(???"version-number",
????????"request-start-time",
????????"operation-type",
????????"request-status",
????????"http-status-code",
????????"end-to-end-latency-in-ms",
????????"server-latency-in-ms",
????????"authentication-type",
????????"requester-account-name",
????????"owner-account-name",
????????"service-type",
????????"request-url",
????????"requested-object-key",
????????"request-id-header",
????????"operation-count",
????????"requester-ip-address",
????????"request-version-header",
????????"request-header-size",
????????"request-packet-size",
????????"response-header-size",
????????"response-packet-size",
????????"request-content-length",
????????"request-md5",
????????"server-md5",
????????"etag-identifier",
????????"last-modified-time",
????????"conditions-used",
????????"user-agent-header",
????????"referrer-header",
????????"client-request-id"
????)

????$logJson?=?"[{";
????For($i?=?0;$i?-lt?$Columns.Length;$i++)
????{
????????$logJson?+=?"`""?+?$Columns[$i]?+?"`":"?+?$FormattedElements[$i]
????????if($i?-lt?$Columns.Length?-?1)?{
????????????$logJson?+=?","
????????}
????}
????$logJson?+=?"}]";

????return?$logJson
}

$storageAccount?=?Get-AzStorageAccount?-ResourceGroupName?$ResourceGroup?-Name?$StorageAccountName?-ErrorAction?SilentlyContinue
if($null?-eq?$storageAccount)
{
????throw?"The?storage?account?specified?does?not?exist?in?this?subscription."
}

$storageContext?=?$storageAccount.Context


$token?=?$Null
$maxReturn?=?5000
$successPost?=?0
$failedPost?=?0

$subject=$eventGridEvent.subject.ToString()
$BlobArray=$subject.Split('/')
$container=$BlobArray[$BlobArray.indexof('containers')+1]
$BlobIndex=$subject.indexof('blobs/')+6
$Blob=$subject.substring($BlobIndex,$subject.length?-?$BlobIndex)

Write-Output(">?Downloading?blob:?{0}"?-f?$blob)
$filename?=?".\log.txt"
Get-AzStorageBlobContent?-Context?$storageContext?-Container?$container?-Blob?$blob?-Destination?$filename?-Force?>?Null
Write-Output(">?Posting?logs?to?log?analytic?workspace:?{0}"?-f?$blob)

$lines?=?Get-Content?$filename

foreach($line?in?$lines)
????????{
????????????$json?=?ConvertLogLineToJson($line)
???????????

????????????$response?=?Post-LogAnalyticsData?-customerId?$customerId?-sharedKey?$sharedKey?-body?([System.Text.Encoding]::UTF8.GetBytes($json))?-logType?$logType

????????????if($response?-eq?"200")?{
????????????????$successPost++
????????????}?else?{?
????????????????$failedPost++
????????????????Write-Output?">?Failed?to?post?one?log?to?Log?Analytics?workspace"
????????????}
????????}

????????remove-item?$filename?-Force

????


Write-Output?">?Log?lines?posted?to?Log?Analytics?workspace:?success?=?$successPost,?failure?=?$failedPost"


最后还有一个步骤是需要给function app授权来访问storage,这步就不详细讲了,也可以用storage account key来做,当然这种方法其实不是很推荐

最后可以在function里的监控里看到完成的效果

总结

总体来说,其实和单纯通过PowerShell脚本的方式相比变化并不大,但是因为增加了eventgrid和function,让整个方案变得更加灵活,类似的思路还可以扩展到很多其他任务上,以更cloud native的方式来看待和处理问题