Este artigo ainda é a ideia anterior. No artigo anterior, compartilhamos uma ideia. Você pode baixar o log de acesso da conta de armazenamento por meio do script do PowerShell e carregá-lo automaticamente no Log Analytics, para que possa ser diretamente em LA Analise e consulte o log. Embora esse método seja simples e conveniente, não é um método automatizado, afinal. Depois de expandir nossas ideias, podemos também tentar usar o eventgrid combinado com a função para converter esse método em uma solução automatizada.
Primeiro, vamos primeiro popularizar o que EventGrid e Function são
EventGrid
Com o Azure Event Grid, os aplicativos podem ser gerados facilmente usando uma arquitetura baseada em eventos. Primeiro, selecione o recurso do Azure no qual deseja se inscrever e, em seguida, forneça um manipulador de eventos ou ponto de extremidade WebHook para o qual enviar eventos. A grade de eventos inclui suporte integrado para eventos de serviços do Azure, como blobs de armazenamento e grupos de recursos. A grade de eventos também suporta seus próprios eventos usando temas customizados.
Simplificando, é como um gatilho, que pode acionar vários eventos e, em seguida, dar respostas direcionadas. Parece um pouco como gatilhos em aplicativos lógicos, mas o eventgrid é apenas uma ferramenta simples de transferência de eventos, métodos de processamento downstream Completamente preenchido por outros produtos, a seguinte imagem também pode ser vista onde a eventgrid está localizada, semelhante a uma fila de mensagens para transmissão de eventos
https://docs.microsoft.com/en-us/azure/event-grid/?WT.mc_id=AZ-MVP-5001235
Função
Azure Functions é uma solução sem servidor que permite aos usuários reduzir a escrita de código, reduzir a infraestrutura que precisa ser mantida e economizar custos. Não há necessidade de se preocupar com a implantação e manutenção de servidores, a infraestrutura em nuvem fornece todos os recursos mais recentes necessários para manter os aplicativos em execução.
A função é realmente mais fácil de entender. Agora, todas as nuvens têm basicamente produtos semelhantes. Se você comparar horizontalmente, é AWS lambda, uma plataforma de execução de código totalmente gerenciada
https://docs.microsoft.com/zh-cn/azure/azure-functions/functions-overview?WT.mc_id=AZ-MVP-5001235
Combinando a figura acima, podemos realmente ver nosso pensamento. Eventgird tem gatilhos de blob embutidos, o que significa que quando um novo blob aparece, ele irá automaticamente disparar o eventgrid e procedimentos de processamento downstream, podemos combinar a função para Sim, o código já está pronto, basta usar o anterior, ele só precisa ser alterado um pouco, a carga de trabalho geral é muito pequena
Claro, há realmente um problema oculto aqui, porque o log da conta de armazenamento é armazenado no contêiner $ logs e esse contêiner não acionará o eventgrid no back-end do Azure. Isso é um pouco complicado. O método que usamos é para criar uma função , E, em seguida, use o azcopy para sincronizar periodicamente a sincronização do log com outro contêiner. Apenas uma linha de código é fácil, então não vou escrever por agora.
Etapas de implementação
Vejamos as etapas de implementação específicas abaixo. Primeiro, crie um aplicativo de funções. A relação entre o aplicativo de funções e a função é muito simples. O aplicativo de funções é equivalente à plataforma em que a função é executada. O código é executado nesta plataforma. O aplicativo de funções pode conter muitos Função
Criar aplicativo de funções
O processo de criação de aplicativos de funções é muito simples, escolhemos o tempo de execução como PowerShell Core
Criar Função
Depois que o aplicativo de funções é criado, você pode criar funções nele. O Azure, na verdade, tem uma função de gatilho de grade de evento integrada, basta selecioná-la ao criá-la
Criar assinatura de grade de eventos
A função está pronta, então você pode preparar a grade de eventos, você pode criar a assinatura da grade de eventos diretamente na função
Ao criar a assinatura da grade de eventos, existem muitos tipos que podem ser selecionados. Aqui, escolha o tipo de armazenamento.
Configure o tipo de evento da conta de armazenamento
Então preste atenção na necessidade de configurar o filtro, pois temos que limitar o caminho a um intervalo específico, nem todos os blobs irão disparar eventos
O gatilho também está pronto, e então você pode preparar o código para ser processado na função
Escrever código
Como o código anterior é processado em um loop e o eventgrid é realmente empurrado um por um, a lógica aqui precisa ser ligeiramente ajustada
Função 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 = [Converter ] :: FromBase64String ($ sharedKey) $ sha256 = Novo objeto System.Security.Cryptography.HMACSHA256 $ sha256.Key = $ keyBytes $ CalculadoHash = $ sha256.ComputeHash ($ bytesToHash) $ encodedHash = [Convert] :: ToBase64String ($ CalculadoHash) $ autorização = 'SharedKey {0}: {1}' -f $ customerId,$ encodedHash retorna $ autorização } Função Post-LogAnalyticsData ($ customerId, $ sharedKey, $ body, $ logType) { $ method = "POST" $ contentType = "application / json" $ resource = "/ api / logs" $ rfc1123date = [DateTime] :: UtcNow .ToString ("r") $ contentLength = $ body.Length $ assinatura = Build-Signature ` -customerId $ customerId` -sharedKey $ sharedKey ` -date $ rfc1123date` -contentLength $ contentLength ` -method $ method` -contentType $ contentType ` -resource $ resource $ uri =" https: // "+ $ customerId +" .ods.opinsights.azure.com "+ $ resource +"? api-version = 2016-04-01 " $ headers = @ { "Autorização" = $ assinatura; "Log-Type" = $ logType; "x-ms-date" = $ rfc1123date; "campo gerado pelo tempo" = $ TimeStampField; } $ response = Invoke-WebRequest -Uri $ uri -Method $ method -ContentType $ contentType -Headers $ headers -Body $ body -UseBasicParsing return $ response.StatusCode } Função ConvertSemicolonToURLEncoding ([String] $ InputText) { $ ReturnText = "" $ chars = $ InputText.ToCharArray () $ StartConvert = $ false foreach ($ c em $ chars) { if ($ c -eq '"') { $ StartConvert =! $ StartConvert } if ($ StartConvert -eq $ true -and $ c -eq ';') { $ ReturnText + = "% 3B" } else { $ ReturnText + = $ c } } return $ ReturnText } Função 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 } Função 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- latência-final-em-ms ", " latência-servidor-em-ms ", " tipo de autenticação ", "requester-account-name", "owner-account-name", "service-type", "request-url", "required-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 ", " última modificação ", "conditions-used", "user-agent-header", "referrer-header", "client-request-id" ) $ logJson = "[{"; Para ($ 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 "A conta de armazenamento especificada não existe nesta assinatura." } $ storageContext = $ storageAccount. $ 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 ("> Baixando blob: {0}" -f $ blob) $ filename = ". \ log .txt " Get-AzStorageBlobContent -Context $ storageContext -Container $ container -Blob $ blob -Destination $ filename -Force> Null Write-Output ("> Registros de postagem para log do espaço de trabalho analítico: {0} "-f $ blob) $ linhas = Get-Content $ filename foreach ($ linha em $ linhas) { $ json = ConvertLogLineToJson ($ linha) $ 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 "> Falha ao postar um log no espaço de trabalho do Log Analytics" } } remove-item $ filename -Force Write-Output "> Linhas de log postadas no espaço de trabalho do Log Analytics: success = $ successPost, failure = $ failedPost "
A última etapa é autorizar o aplicativo de funções a acessar o armazenamento. Esta etapa não será discutida em detalhes. Você também pode usar a chave da conta de armazenamento para fazer isso. Claro, esse método não é muito recomendado.
Por fim, você pode ver o efeito concluído no monitoramento na função
Resumindo
De modo geral, em comparação com a maneira de usar o script do PowerShell sozinho, não mudou muito, mas por causa da adição de eventgrid e função, toda a solução se tornou mais flexível. Ideias semelhantes também podem ser estendidas para muitas outras tarefas para serem mais nebulosas. para olhar e lidar com problemas de uma maneira nativa