[English version](/docs/en/docs-08-tracing.md) ## 08 - 上报Tracing到OpenTelemetry **SRPC**支持产生和上报链路信息trace和span,并且可以通过多种途径进行上报,其中包括本地导出数据和上报到[OpenTelemetry](https://opentelemetry.io). **SRPC**遵循**OpenTelemetry**的[数据规范(data specification)](https://github.com/open-telemetry/opentelemetry-specification)以及[w3c的trace context](https://www.w3.org/TR/trace-context/),因此可以使用插件**RPCTraceOpenTelemetry**进行上报。 秉承着**Workflow**的风格,所有的上报都是异步任务模式,对RPC的请求和服务不会产生任何性能影响。 ### 1. 用法 先构造插件`RPCTraceOpenTelemetry`,然后通过`add_filter()`把插件加到**server**或**client**中。 以[tutorial-02-srpc_pb_client.cc](https://github.com/sogou/srpc/blob/master/tutorial/tutorial-02-srpc_pb_client.cc)作为client的示例,我们如下加两行代码: ```cpp 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](https://github.com/sogou/srpc/blob/master/tutorial/tutorial-01-srpc_pb_server.cc)作为server的示例,也增加类似的两行。同时我们还增加一个本地插件,用于把本次请求的trace数据也在屏幕上打印: ```cpp 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信息: image 我们可以看到上图client这边的span_id: **04d070f537f17d00**,它在下图server这里变成了parent_span_id: **04d070f537f17d00**: image ### 2. Traces上报到Jaeger 打开Jaeger的主页,我们可以找到我们名为**Example**的服务(service)和名为**Echo**的函数(method)。这一个tracing记录上有两个span节点,是由server和client分别上报的。 image 我们可以在Jaeger看到client所上报的span_id: **04d070f537f17d00**和server所上报的span_id: **00202cf737f17d00**,同时也是能对应上刚才在屏幕看到的id的。 image ### 3. 参数 多久收集一份trace信息、上报请求的重试次数、以及其他参数,都可以通过`RPCTraceOpenTelemetry`的构造函数指定。代码参考:[src/module/rpc_trace_filter.h](https://github.com/sogou/srpc/blob/master/src/module/rpc_trace_filter.h#L238) 默认每秒收集1000条trace信息,并且透传tracing信息等其他功能也已遵循上述规范实现。 ### 4. Attributes 我们可以通过`add_attributes()`添加某些额外的信息,比如数据规范中的OTEL_RESOURCE_ATTRIBUTES。 注意我们的service名"Example"也是设置到attributes中的,key为`service.name`。如果用户也在OTEL_RESOURCE_ATTRIBUTES中使用了`service.name`这个key,则SRPC的service name优先级更高,参考:[OpenTelemetry#resource](https://github.com/open-telemetry/opentelemetry-dotnet/tree/main/src/OpenTelemetry#resource) ### 5. Log和Baggage SRPC提供了`log()`和`baggage()`接口,用户可以添加需要通过链路透传的数据。 ```cpp void log(const RPCLogVector& fields); void baggage(const std::string& key, const std::string& value); ``` 作为Server,我们可以使用`RPCContext`上的接口来添加log: ```cpp 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: ```cpp srpc::SRPCClientTask *task = client.create_Echo_task(...); task->log({{"event", "info"}, {"message", "log by rpc client echo()."}}); ```