[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信息:
我们可以看到上图client这边的span_id: **04d070f537f17d00**,它在下图server这里变成了parent_span_id: **04d070f537f17d00**:
### 2. Traces上报到Jaeger
打开Jaeger的主页,我们可以找到我们名为**Example**的服务(service)和名为**Echo**的函数(method)。这一个tracing记录上有两个span节点,是由server和client分别上报的。
我们可以在Jaeger看到client所上报的span_id: **04d070f537f17d00**和server所上报的span_id: **00202cf737f17d00**,同时也是能对应上刚才在屏幕看到的id的。
### 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()."}});
```