この記事は以前のアイデアです。前回の記事では、アイデアを共有しました。PowerShellスクリプトを使用してストレージアカウントのアクセスログをダウンロードし、Log Analyticsに自動的にアップロードして、LAに直接アクセスできるようにすることができます。ログの分析とクエリ。この方法はシンプルで便利ですが、結局のところ自動化された方法ではありません。アイデアを拡張した後、eventgridと関数を組み合わせてこの方法を自動化されたソリューションに変換することもできます。
まず、EventGridとFunctionが何であるかを最初に普及させましょう
EventGrid
Azure Event Gridを使用すると、イベントベースのアーキテクチャを使用してアプリケーションを簡単に生成できます。まず、サブスクライブするAzureリソースを選択してから、イベントの送信先となるイベントハンドラーまたはWebHookエンドポイントを提供します。イベントグリッドには、ストレージブロブやリソースグループなどのAzureサービスからのイベントのサポートが組み込まれています。イベントグリッドは、カスタムテーマを使用した独自のイベントもサポートします。
簡単に言えば、さまざまなイベントをトリガーしてターゲットを絞った応答を行うことができるトリガーのようなものです。ロジックアプリのトリガーのように聞こえますが、eventgridは単純なイベント転送ツールであり、ダウンストリームの処理方法です。他の製品によって完全に完成した次の図は、イベント送信用のメッセージキューと同様に、イベントグリッドが配置されている場所にも表示されます。
https://docs.microsoft.com/en-us/azure/event-grid/?WT.mc_id=AZ-MVP-5001235
関数
Azure Functionsは、ユーザーがコードの記述を減らし、保守が必要なインフラストラクチャを減らし、コストを節約できるようにするサーバーレスソリューションです。サーバーの展開と保守について心配する必要はありません。クラウドインフラストラクチャは、アプリケーションの実行を維持するために必要なすべての最新のリソースを提供します。
機能は実際には理解しやすいです。今ではすべてのクラウドに基本的に同様の製品があります。水平方向に比較すると、フルマネージドコード実行プラットフォームであるAWSラムダです。
https://docs.microsoft.com/zh-cn/azure/azure-functions/functions-overview?WT.mc_id=AZ-MVP-5001235
上の図を組み合わせると、実際に私たちの考えを見ることができます。Eventgirdにはblobトリガーが組み込まれています。つまり、新しいblobが表示されると、自動的にeventgridがトリガーされ、ダウンストリームの処理手順では、次の機能を組み合わせることができます。コードは実際には既製です。前のコードを使用してください。少し変更する必要があります。全体的なワークロードは非常に小さいです。
もちろん、ストレージアカウントログは$ logsコンテナに保存され、このコンテナはAzureバックエンドでeventgridをトリガーしないため、実際にはここに隠れた問題があります。これは少し注意が必要です。使用する方法は、関数を作成することです。 、次にazcopyを使用して、ログ同期を別のコンテナに定期的に同期します。コードは1行だけで簡単なので、今は書きません。
実装手順
以下の具体的な実装手順を見てみましょう。まず、関数アプリを作成します。関数アプリと関数の関係は非常に単純です。関数アプリは、関数が実行されるプラットフォームと同等です。コードはこのプラットフォームで実行されます。関数アプリには、多くの関数
関数アプリを作成する
関数アプリを作成するプロセスは非常に簡単です。PowerShellコアとしてランタイムを選択します
関数の作成
Functionアプリを作成したら、その中に関数を作成できます。Azureには、実際には偶数グリッドトリガー機能が組み込まれています。作成時に選択するだけです。
イベントグリッドサブスクリプションの作成
関数の準備ができたら、eventgridを準備し、関数で直接イベントグリッドサブスクリプションを作成できます。
イベントグリッドサブスクリプションを作成する場合、選択できるタイプは多数あります。ここで、ストレージタイプを選択してください。
ストレージアカウントのイベントタイプを構成します
次に、パスを特定の範囲に制限する必要があるため、フィルターを構成する必要性に注意してください。すべてのblobがイベントをトリガーするわけではありません。
トリガーの準備もできたら、関数で処理するコードを準備できます
コードを書く
前のコードはループで処理され、eventgridは実際に1つずつプッシュされるため、ここでのロジックは少し調整する必要があります
関数ビルド-署名($ 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) $ encodingHash = [Convert] :: ToBase64String($計算された ハッシュ)$ authorization = 'SharedKey {0}:{1}' -f $ customerId、$ encodingHash return $ authorization } 関数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 =" https:// "+ $ customerId +" .ods.opinsights.azure.com "+ $ resource +"?api-version = 2016-04-01 " $ headers = @ { "承認" = $ 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 } 関数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 } 関数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」、 「リクエスターアカウント名」、 「所有者アカウント名」、 "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 "指定されたストレージアカウントはこのサブスクリプションに存在しません。" } $ storageContext = $ storageAccount。 $ maxReturn = 5000 $ successPost = 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( ">ブロブのダウンロード:{0}" -f $ blob ) $ filename = "。\ log.txt" Get-AzStorageBlobContent -Context $ storageContext -Container $ container -Blob $ blob -Destination $ filename -Force> Null Write-Output( ">ログをログ分析ワークスペースに投稿する:{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 "> 1つのログをLogAnalyticsワークスペースに投稿できません でした" } } remove-item $ filename -Force Write-Output "> Log Analyticsワークスペースに投稿されたログ行:success = $ successPost、failure = $ failedPost "
最後のステップは、ファンクションアプリにストレージへのアクセスを許可することです。このステップについては詳しく説明しません。ストレージアカウントキーを使用してアクセスすることもできます。もちろん、この方法はあまりお勧めしません。
最後に、機能のモニタリングで完了した効果を確認できます
総括する
一般的に言って、PowerShellスクリプトを使用する方法と比べてそれほど変わっていませんが、eventgridと関数が追加されたため、ソリューション全体がより柔軟になりました。同様のアイデアを他の多くのタスクに拡張して、よりクラウドベースにすることもできます。ネイティブな方法で問題を調べて対処する