本文地址: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的方式来看待和处理问题
Ctrl+Enter 发布
发布
取消