非同步追蹤

本指南說明如何在程式碼中加入非同步追蹤。

必要條件

開始之前,請先確認您已完成下列事項:

新增非同步追蹤

有一組非同步追蹤函式,如果作業橫跨多個執行緒,就能使用一組非同步追蹤函式。

舉例來說,在多執行緒伺服器中,要求會由一個執行緒處理,然後在作業執行期間放回佇列中。一段時間後,另一個執行緒會收到作業已完成的通知,並「測試」該要求處理作業。非同步追蹤的目標,是藉由允許這些不連續的追蹤記錄事件建立關聯。

非同步追蹤會將相同的程式碼路徑用於多個不同的處理流程。在先前的範例中,我們希望查看特定函式的執行時間,或特定時間點的值為何。透過非同步追蹤,我們希望追蹤相同的資料,但適用於邏輯處理流程,而不是以程式位置為基礎的流程。

在佇列處理範例中,接收要求的程式碼會將每個要求標記為「nonce」,這是出現在要求周圍的唯一值。這個 Nonce 可以使用 TRACE_NONCE() 產生,而後者只會遞增全域計數器。

接著來看看運作方式。 首先,您必須宣告存放 Nonce 的位置。以下內容通常位於要求本身的結構定義結構中:

typedef struct {
...
    // add the nonce to your context structure
    trace_async_id_t async_id;
} my_request_context_t;

要求送達後,請擷取 Nonce,並開始非同步追蹤流程:

// a new request; start asynchronous tracing
ctx->async_id = TRACE_NONCE();
TRACE_ASYNC_BEGIN("category", "name", ctx->async_id, "key", TA_STRING("value"));

您可以使用 TRACE_ASYNC_INSTANT() 巨集定期記錄追蹤事件 (與上方 TRACE_INSTANT() 巨集的操作類似):

TRACE_ASYNC_INSTANT("category", "name", ctx->async_id, "state", TA_STRING("phase2"));

並透過 TRACE_ASYNC_END() 清理:

TRACE_ASYNC_END("category", "name", ctx->async_id);

請勿混淆使用「非同步」功能和在程序中執行的非同步迴圈,兩者無關。

流量追蹤

非同步追蹤適合在相同程序內進行追蹤,但或許是透過不同的執行緒進行追蹤。

有一種較高層級的追蹤機制稱為「資料流」追蹤,可在程序或抽象層之間使用。

呼叫 TRACE_FLOW_BEGIN() 以標示「資料流」的開始。和 TRACE_ASYNC_BEGIN() 一樣,您可以傳入 Nonce 來表示這個特定流程。流程 ID 是無正負號的 64 位元整數。

接著,您可以選擇呼叫 TRACE_FLOW_STEP(),指出該流程中的追蹤作業。

完成後,系統會使用 TRACE_FLOW_END() 結束流程。

例如,在用戶端與伺服器之間使用流程,可用於追蹤用戶端、透過伺服器和傳回用戶端的端對端要求。