問題描述
根據文檔 https://docs.azure.cn/zh-cn/api-management/api-management-howto-log-event-hubs , 可以将Azure API Management中的請求記錄到Azure 事件中心。文檔中有詳細的步驟描述。但是在對于如何建立APIM的Logger, 如何在API中配置政策描述非常不清楚,是以本文就補充如何建立Logger及在APIM的API中添加log-to-eventhub 政策。
前提條件
- 建立 Azure 事件中心:https://docs.azure.cn/zh-cn/event-hubs/event-hubs-create
- Create APIM Logger: https://docs.microsoft.com/zh-cn/rest/api/apimanagement/2020-12-01/logger/create-or-update
- Postman
- 下載下傳 Service Bus Explorer檢視事件中心消息:https://github.com/paolosalvatori/ServiceBusExplorer/releases
操作步驟
1) 建立APIM Logger
示例
PUT https://management.chinacloudapi.cn/subscriptions/<your subscription id>/resourceGroups/<group name>/providers/Microsoft.ApiManagement/service/<your apim name>/loggers/<loggerideh01>?api-version=2020-12-01
注:替換<>中的内容為自己的相應資源資訊,同時也定義loggers的名稱。
這裡的Endpoint為中國區Azure的Endpoint: https://management.chinacloudapi.cn/, 如果需要Global Azure,則為:https://management.azure.com/
Authorization
兩種方式任選其一:
- Azure Active Directory OAuth2 Flow : https://www.cnblogs.com/lulight/p/14279338.html
- 似乎用浏覽器打開Azure APIM的門戶,通過F12--開發者選項中的 Network, 檢視其中對API的請求,複制其中的Authorization 值

Body
{
"properties": {
"loggerType": "azureEventHub",
"description": "adding a new logger",
"credentials": {
"name": "<your event hub name>",
"connectionString": "Endpoint=sb://<your event hub namespace>.servicebus.chinacloudapi.cn/;SharedAccessKeyName=xxxxxxxxxxxxxxxxx;SharedAccessKey=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
}
}
Response - 201 Created
{
"id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/xxxx-rg/providers/Microsoft.ApiManagement/service/xxxx/loggers/loggerideh01",
"type": "Microsoft.ApiManagement/service/loggers",
"name": "loggerideh01",
"properties": {
"loggerType": "azureEventHub",
"description": "adding a new logger",
"credentials": {
"name": "xxxxxxxxxxxx",
"connectionString": "{{Logger-Credentials--xxxxxxxxxxxx}}"
},
"isBuffered": true,
"resourceId": null
}
}
示範動畫
2) 添加 log-to-eventhub 政策
- 浏覽到自己的 APIM 執行個體。
- 選擇“API”頁籤。
- 選擇要将政策添加到的 API。
- 選擇“所有操作”。
- 選擇螢幕頂部的“設計”頁籤。
- 在“入站或出站處理”視窗中,單擊三角形(鉛筆旁邊)。
- 選擇“代碼編輯器”。 有關詳細資訊,請參閱如何設定或編輯政策。
- 将光标放在
或inbound
政策部分中。outbound
- 在右側視窗中,選擇“進階政策” > “記錄到 EventHub”。 這會插入
政策語句模闆。log-to-eventhub
注: Log-to-eventhub 中的logger-id由上面第一步建立。 Request Body的資訊一定要進行格式轉換。是以需要使用 context.Request.Body.As<string>()
<policies>
<inbound>
<base />
<log-to-eventhub logger-id="loggerideh01">@{
return new JObject(
new JProperty("EventTime", DateTime.UtcNow.ToString()),
new JProperty("ServiceName", context.Deployment.ServiceName),
new JProperty("RequestId", context.RequestId),
new JProperty("RequestBody1", context.Request.Body.As<string>()),
new JProperty("OperationName", context.Operation.Name)
).ToString();
}</log-to-eventhub>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
<log-to-eventhub logger-id="loggerideh01">@{
return new JObject(
new JProperty("EventTime", DateTime.UtcNow.ToString()),
new JProperty("ServiceName", context.Deployment.ServiceName),
new JProperty("RequestId", context.RequestId),
new JProperty("RequestBody2", context.Response.Body.As<string>()),
new JProperty("OperationName", context.Operation.Name)
).ToString();
}</log-to-eventhub>
</outbound>
<on-error>
<base />
</on-error>
</policies>
3) 連接配接到Event Hub,檢視 Request Body 資訊
下載下傳zip包,解壓後在裡面找到檔案名為:ServiceBusExplorer.exe。 輕按兩下即可運作
在下面的字元串框中輸入Event Hub Namespace的連接配接字元串。點選Save/ OK後,即可連接配接到Event Hub中。
進入儲存日志的Event Hub中,找到合适的分區數,點選“Create Partitions Listener ”, 然後再彈出的頁面中點選 “Strat”按鈕,就可以收到Event Hub中所存儲的消息
附錄一:如何在APIM的Policy set-variable 中為參數在進行格式轉換時候進行驗證是否為null呢?避免Expression evaluation failed.
使用C#的問号表達式 (condition == null ? value1 :value2)
在APIM中,如果在測試階段,出現Expression evaluation failed錯誤,可以在Test 的Trace中進行檢視,了解真實的錯誤資訊。如:
{
"source": "log-to-eventhub",
"timestamp": "2021-12-01T03:25:33.7362765Z",
"elapsed": "00:00:00.0007502",
"data": {
"messages": [
{
"message": "Expression evaluation failed.",
"expression": "\n return new JObject(\n new JProperty(\"EventTime\", DateTime.UtcNow.ToString()),\n new JProperty(\"ServiceName\", context.Deployment.ServiceName),\n new JProperty(\"RequestId\", context.RequestId),\n new JProperty(\"RequestIp\", context.Request.Body),\n new JProperty(\"OperationName\", context.Operation.Name)\n ).ToString();\n ",
"details": "Could not determine JSON object type for type Microsoft.WindowsAzure.ApiManagement.Proxy.Gateway.MessageBody.\r\n at Newtonsoft.Json.Linq.JValue.GetValueType(Nullable`1 current, Object value)\r\n at Newtonsoft.Json.Linq.JContainer.CreateFromContent(Object content)\r\n at Newtonsoft.Json.Linq.JProperty..ctor(String name, Object content)"
},
"Expression evaluation failed. Could not determine JSON object type for type Microsoft.WindowsAzure.ApiManagement.Proxy.Gateway.MessageBody.\r\n at Newtonsoft.Json.Linq.JValue.GetValueType(Nullable`1 current, Object value)\r\n at Newtonsoft.Json.Linq.JContainer.CreateFromContent(Object content)\r\n at Newtonsoft.Json.Linq.JProperty..ctor(String name, Object content)",
"Could not determine JSON object type for type Microsoft.WindowsAzure.ApiManagement.Proxy.Gateway.MessageBody."
]
}
}
為了避免這樣的情況,在格式轉換時候,最好對其進行 null 檢測,當時 null的時候就可以改變其值的或者指派為“”。
<set-variable name="testvalue" value="@(context.Variables["tokenvalue"]==null?context.Request.Headers.GetValueOrDefault("User-Agent","empty"):"")" />
<set-variable name="requestbody" value="@(context.Request.Body==null?"no body":context.Request.Body.As<string>())" />
參考資料
如何在 Azure API 管理中将事件記錄到 Azure 事件中心 : https://docs.azure.cn/zh-cn/api-management/api-management-howto-log-event-hubs#configure-log-to-eventhub-policies
Logger - Create Or Update : https://docs.microsoft.com/zh-cn/rest/api/apimanagement/2020-12-01/logger/create-or-update#apimanagementcreateehlogger
建立 Azure 事件中心:https://docs.azure.cn/zh-cn/event-hubs/event-hubs-create
當在複雜的環境中面臨問題,格物之道需:濁而靜之徐清,安以動之徐生。 雲中,恰是如此!