SRPC支持产生和上报链路信息trace和span,并且可以通过多种途径进行上报,其中包括本地导出数据和上报到OpenTelemetry.
SRPC遵循OpenTelemetry的数据规范(data specification)以及w3c的trace context,因此可以使用插件RPCTraceOpenTelemetry进行上报。
秉承着Workflow的风格,所有的上报都是异步任务模式,对RPC的请求和服务不会产生任何性能影响。
先构造插件RPCTraceOpenTelemetry
,然后通过add_filter()
把插件加到server或client中。
以tutorial-02-srpc_pb_client.cc作为client的示例,我们如下加两行代码:
int main()
{
Example::SRPCClient client("127.0.0.1", 1412);
RPCTraceOpenTelemetry span_otel("http://127.0.0.1:4318");
client.add_filter(&span_otel);
...
}
以tutorial-01-srpc_pb_server.cc作为server的示例,也增加类似的两行。同时我们还增加一个本地插件,用于把本次请求的trace数据也在屏幕上打印:
int main()
{
SRPCServer server;
RPCTraceOpenTelemetry span_otel("http://127.0.0.1:4318");
server.add_filter(&span_otel);
RPCTraceDefault span_log; // 这个插件会把本次请求的trace信息打到屏幕上
server.add_filter(&span_log);
...
}
执行命令make tutorial
可以编译出示例程序,并且分别把server和client跑起来,我们可以在屏幕上看到一些tracing信息:
我们可以看到上图client这边的span_id: 04d070f537f17d00,它在下图server这里变成了parent_span_id: 04d070f537f17d00:
打开Jaeger的主页,我们可以找到我们名为Example的服务(service)和名为Echo的函数(method)。这一个tracing记录上有两个span节点,是由server和client分别上报的。
我们可以在Jaeger看到client所上报的span_id: 04d070f537f17d00和server所上报的span_id: 00202cf737f17d00,同时也是能对应上刚才在屏幕看到的id的。
多久收集一份trace信息、上报请求的重试次数、以及其他参数,都可以通过RPCTraceOpenTelemetry
的构造函数指定。代码参考:src/module/rpc_trace_filter.h
默认每秒收集1000条trace信息,并且透传tracing信息等其他功能也已遵循上述规范实现。
我们可以通过add_attributes()
添加某些额外的信息,比如数据规范中的OTEL_RESOURCE_ATTRIBUTES。
注意我们的service名"Example"也是设置到attributes中的,key为service.name
。如果用户也在OTEL_RESOURCE_ATTRIBUTES中使用了service.name
这个key,则SRPC的service name优先级更高,参考:OpenTelemetry#resource
SRPC提供了log()
和baggage()
接口,用户可以添加需要通过链路透传的数据。
void log(const RPCLogVector& fields);
void baggage(const std::string& key, const std::string& value);
作为Server,我们可以使用RPCContext
上的接口来添加log:
class ExampleServiceImpl : public Example::Service
{
public:
void Echo(EchoRequest *req, EchoResponse *resp, RPCContext *ctx) override
{
resp->set_message("Hi back");
ctx->log({{"event", "info"}, {"message", "rpc server echo() end."}});
}
};
作为client,我们可以使用RPCClientTask
上的接口添加log:
srpc::SRPCClientTask *task = client.create_Echo_task(...);
task->log({{"event", "info"}, {"message", "log by rpc client echo()."}});