本指南介绍了如何向代码添加异步跟踪。
前提条件
在开始之前,请确保您已完成以下操作:
此外,请务必在代码中使用相关库:
C
#include <lib/trace/event.h>
C++
#include <lib/trace/event.h>
Rust
use fuchsia_trace::{ArgValue, Scope, ...};
添加了异步跟踪
有一组异步跟踪函数,用于在操作跨多个线程时使用。
例如,在多线程服务器中,一个请求由一个线程处理,然后在操作进行期间放回队列。一段时间后,另一个线程会收到操作已完成的通知,并“接手”处理该请求。异步跟踪的目标是允许关联这些不相交的轨迹事件。
异步跟踪会考虑到同一代码路径会用于多种不同的处理流程。在前面的示例中,我们希望了解特定函数的运行时长,或特定值在给定时间点的值。使用异步跟踪时,我们希望跟踪相同的数据,但跟踪的是逻辑处理流程,而不是基于程序位置的流程。
在队列处理示例中,接收请求的代码会为每个请求添加一个“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);
请勿将这种“async”用法与进程中运行的异步循环混淆;它们没有关联。
流跟踪
异步跟踪适用于同一进程内的跟踪,但可能通过不同的线程进行。
还有一种更高级别的跟踪机制,称为“流”跟踪,适用于进程或抽象层之间使用。
您可以调用 TRACE_FLOW_BEGIN()
来标记“流程”的开始。与 TRACE_ASYNC_BEGIN()
一样,您需要传入 Nonce 来标识此特定流程。流 ID 是无符号 64 位整数。
然后,您可以(可选)调用 TRACE_FLOW_STEP()
来指明该流程中的轨迹操作。
完成后,使用 TRACE_FLOW_END()
结束流程。
例如,您可以在客户端和服务器之间使用流程,以便从客户端通过服务器返回客户端对请求进行端到端跟踪。