🌊

Azure Logic AppsによるLog Analyticsワークスペースへのデータインジェクション

に公開

検証の背景

Logic Appsを使ってLog Analyticsワークスペース(以降、LAW)にデータ送る方法は、意外と記事が少ない。
以下の公式ドキュメントを基に検証したときのハマりどころを中心にTIPSを残す。
https://learn.microsoft.com/ja-jp/azure/azure-monitor/logs/tutorial-logs-ingestion-portal

作成したLogic AppsのワークフローのJSON版

簡単な処理の流れとしては呼び出し元からリクエスボディにデータがセットされた状態でHTTPトリガーで本Logic Appsが呼び出される。Logic Appsではリクエストのデータからいくつかのデータを取り出し、それをLAWのカスタムログテーブルに挿入する流れである。

ワークフローのJSON版
{
    "definition": {
        "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
        "contentVersion": "1.0.0.0",
        "triggers": {
            "When_an_HTTP_request_is_received": {
                "type": "Request",
                "kind": "Http",
                "inputs": {
                    "schema": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "eventType": {
                                "type": "string"
                            },
                            "publisherId": {
                                "type": "string"
                            },
                            "message": {
                                "type": "object",
                                "properties": {
                                    "text": {
                                        "type": "string"
                                    },
                                    "html": {
                                        "type": "string"
                                    },
                                    "markdown": {
                                        "type": "string"
                                    }
                                }
                            },
                            "detailedMessage": {
                                "type": "object",
                                "properties": {
                                    "text": {
                                        "type": "string"
                                    },
                                    "html": {
                                        "type": "string"
                                    },
                                    "markdown": {
                                        "type": "string"
                                    }
                                }
                            },
                            "resource": {
                                "type": "object",
                                "properties": {
                                    "repository": {
                                        "type": "object",
                                        "properties": {
                                            "id": {
                                                "type": "string"
                                            },
                                            "name": {
                                                "type": "string"
                                            },
                                            "url": {
                                                "type": "string"
                                            },
                                            "project": {
                                                "type": "object",
                                                "properties": {
                                                    "id": {
                                                        "type": "string"
                                                    },
                                                    "name": {
                                                        "type": "string"
                                                    },
                                                    "url": {
                                                        "type": "string"
                                                    },
                                                    "state": {
                                                        "type": "string"
                                                    },
                                                    "revision": {
                                                        "type": "integer"
                                                    },
                                                    "visibility": {
                                                        "type": "string"
                                                    },
                                                    "lastUpdateTime": {
                                                        "type": "string"
                                                    }
                                                }
                                            },
                                            "defaultBranch": {
                                                "type": "string"
                                            },
                                            "size": {
                                                "type": "integer"
                                            },
                                            "remoteUrl": {
                                                "type": "string"
                                            },
                                            "sshUrl": {
                                                "type": "string"
                                            },
                                            "isDisabled": {
                                                "type": "boolean"
                                            }
                                        }
                                    },
                                    "initiatedBy": {
                                        "type": "object",
                                        "properties": {
                                            "displayName": {
                                                "type": "string"
                                            },
                                            "id": {
                                                "type": "string"
                                            },
                                            "uniqueName": {
                                                "type": "string"
                                            }
                                        }
                                    },
                                    "utcTimestamp": {
                                        "type": "string"
                                    }
                                }
                            },
                            "resourceVersion": {
                                "type": "string"
                            },
                            "resourceContainers": {
                                "type": "object",
                                "properties": {
                                    "collection": {
                                        "type": "object",
                                        "properties": {
                                            "id": {
                                                "type": "string"
                                            }
                                        }
                                    },
                                    "account": {
                                        "type": "object",
                                        "properties": {
                                            "id": {
                                                "type": "string"
                                            }
                                        }
                                    },
                                    "project": {
                                        "type": "object",
                                        "properties": {
                                            "id": {
                                                "type": "string"
                                            }
                                        }
                                    }
                                }
                            },
                            "createdDate": {
                                "type": "string"
                            }
                        }
                    }
                }
            }
        },
        "actions": {
            "HTTP": {
                "runAfter": {},
                "type": "Http",
                "inputs": {
                    "uri": "https://adotest-12k4.southeastasia-1.ingest.monitor.azure.com/dataCollectionRules/dcr-b5a1922176d746c880013d17504f4f60/streams/Custom-adotest_CL?api-version=2023-01-01",
                    "method": "POST",
                    "headers": {
                        "Content-Type": "application/json"
                    },
                    "body": [
                        {
                            "id": "@{triggerBody()?['id']}",
                            "createdDate": "@{triggerBody()?['createdDate']}"
                        }
                    ],
                    "authentication": {
                        "type": "ManagedServiceIdentity",
                        "identity": "/subscriptions/<サブスクリプションID>/resourceGroups/cloud-shell-storage-southeastasia/providers/Microsoft.ManagedIdentity/userAssignedIdentities/adotestmgdig",
                        "audience": "https://monitor.azure.com/"
                    }
                },
                "runtimeConfiguration": {
                    "contentTransfer": {
                        "transferMode": "Chunked"
                    }
                }
            }
        },
        "outputs": {},
        "parameters": {
            "$connections": {
                "type": "Object",
                "defaultValue": {}
            }
        }
    },
    "parameters": {
        "$connections": {
            "type": "Object",
            "value": {}
        }
    }
}

LAW周りのTIPS

  • LAWがプライベートリンク構成の場合のみ、DCEが必要になる。それ以外の場合はDCRのみで問題無し。
  • 大体のケースではログの送信先はカスタムログテーブルになるのではないかと思う。DCRはLAWにカスタムログテーブルを作成するときには必要になる。要はログの送信元とLAWの間の仲介役の存在になるのがDCRである。カスタムログテーブルを作成するときに必要となるDCRは、テーブルのスキーマを定義するルールである。
  • Logic AppsでのLog Injection APIの利用であれば、認証はマネージドIDでOK。マネージドIDには監視メトリック発行者の権限が必要。
  • LAWでカスタムテーブルを作る時には、サンプルデータをアップロードすることでカラム名をいい感じにしたテーブルを作成してくれる。妥当性は目視で確認した方が良いと思われる。
  • LAWにインジェストする際に呼び出すURIの構造は以下を参照して組み立てることになる。

https://learn.microsoft.com/ja-jp/azure/azure-monitor/logs/logs-ingestion-api-overview?source=recommendations#rest-api-call

  • LAWでは、TimeGeneratedのカラムが必須になる。どうやって作成するかの定義をする必要がある。今回はサンプルデータにcreatedDateが含まれていたので、この値をTimeGeneratedに流用するようにAzure Portal上で設定した。
  • Azure Portalから、LAW→カスタムログテーブルを作成するときには、まだDCEが必須で必要とのこと。作成を不要にするならば、ARMテンプレートからの構築しかない。

https://learn.microsoft.com/ja-jp/azure/azure-monitor/logs/tutorial-logs-ingestion-portal#create-data-collection-endpoint

Logic Apps周りのTIPS

  • Logic AppsをHTTPトリガーで実装するときに、サンプルのJSONをアップロードすることで、リクエストボディの型を抽出してくれる。
  • 実行が成功してもLAWにデータが取り込まれるのは数分かかるので、焦らないように。実行が成功すると、Azure Portal上で格納先のLAWS→ログ→テーブルに、該当のテーブル自体は出てくるので、それで成功確認をするのもありだと思う。
  • Logic AppsでマネージドID認証をするときにはaudienceは必須項目になっていないので空白のままでも作成はできてしまうが、実行上は必要になる。Azure のターゲットリソースまたはサービスのリソースIDを設定して認証を行うようである。ChatGpt曰く、「トークンを取得・使用するリソース ID(scope/resource URI)」らしい。一応、以下のドキュメントにaudicenceのスコープとして、LAWの場合はhttps://monitor.azure.comが定義されている。audience欄が空白のままだと401の認証エラーが発生するので注意。

https://learn.microsoft.com/en-us/azure/azure-monitor/logs/logs-ingestion-api-overview#request-headers

検証時の周辺情報

  • Azure DevOps のService WEBHOOKとして利用可能なものは以下。サンプルのJSONデータもあるのでLAWのカスタムログテーブルの作成時や、Logic AppsのHTTPトリガーのリクエストスキーマの作成時に有効活用できそう。

https://learn.microsoft.com/en-us/azure/devops/service-hooks/events?view=azure-devops&utm_source=chatgpt.com

  • DCEの要否についてのお話

https://learn.microsoft.com/ja-jp/azure/azure-monitor/data-collection/data-collection-endpoint-overview?tabs=portal#when-is-a-dce-required

  • Log Injection のAPIを呼び出す時のURLの形式

https://learn.microsoft.com/ja-jp/azure/azure-monitor/logs/logs-ingestion-api-overview#data-collection-rule-dcr

Discussion