[TOC] >[success] 上报成功后在后台查看,需要切换当前项目,默认在默认项目中。 ![](https://img.kancloud.cn/d4/c8/d4c83d59cf73d40507a141abe028444f_756x334.png) >[danger] 可以先查看链路追踪,首页和调用统计需要时间进行分析。 # FPM 应用 <!--### 自动创建应用--> 默认 tracker 客户端安装了扩展和 agent,并发生了请求,就会自动上报,服务端自动生成对应的应用,并上报监控数据。如果在后台关闭了自动创建应用(默认是开启自动创建的),则需要手动创建应用。 <!--### 手动创建应用 在服务端->系统管理->相应项目->应用管理->新增应用 应用名即为您要监控站点的域名,如有端口请加上端口。 >[info] 例如:您想监控的站点域名为`www.test.com`,服务名则填`www.test.com`(注意:域名若带端口,服务名也要带端口) 配置完成后,稍等片刻即可查看对应的监控数据--> # Service 应用(Cli 模式) ## 自动创建应用 如果您的 Cli 应用是 `Swoole` 的 `HttpServer` 那么会在发生请求后(OnRequest)自动生成应用,名称为`host:port` 如果您的 Cli 应用是 `Swoole` 的其他类型`Server` 那么会在发生请求后(onReceive)自动生成应用,名称为`ip:port` >[danger] 当您使用了 Swoole 的多端口监听,自动生成的应用名称只会使用主端口,其他的端口不会生成应用,其他端口的请求拦截到的数据会算到主端口这个应用里面。同时[协程风格的 Swoole 服务端](https://wiki.swoole.com/#/server/co_init)不支持自动创建应用。 <!--### ## 手动创建应用 在服务端->系统管理->相应项目->应用管理->新增应用 应用名即为您要监控的服务名。 >[info] 例如:您想监控服务名为`user_service`的cli常驻进程应用,您的应用类型选择Service,服务名填`user_service`. --> ## 手动创建应用 cli 下有两种需求需要手动创建应用: - 自动创建的应用的**名称**不满足需求 - 不满足自动创建应用的条件,需要手动才能创建应用(例如使用的是 Workerman) 手动创建需要调用 2 个 API: ```php /** * 被调用开始前执行 * @param $func eg. 'App\Login\Weibo::login' * @param $serviceName 应用名称 例如'userService' * @param $serverIp eg. '192.1.1.1' * @return StatsCenter_Tick object */ $tick = \SwooleTracker\Stats::beforeExecRpc($func, $serviceName, $serverIp); /** * 被调用结束后执行 * @param $tick StatsCenter_Tick object * @param $ret true/false * @param $errno 201 * @return void */ \SwooleTracker\Stats::afterExecRpc($tick, $ret, $errno); ``` 微服务框架肯定都有统一的服务入口,在服务入口处(开始)加上`beforeExecRpc()`方法,服务出口处(结束)加上`afterExecRpc()`方法。此时后台可以统计到服务的所有链路信息,例如这次调用的 `mysql` `redis`  等调用都会在`afterExecRpc()`后上报,**这两个 API 除了用来生成应用,还可以用来透传**,下文介绍。 # 透传 TraceId/SpanId 透传的作用是为了分布式 trace,举个例子,浏览器请求机器 A 的 FPM,然后机器 A 的 FPM 调用了机器 B 的 Swoole 服务,正常情况下这会生成 2 个 trace 信息,如果你想让 A=>B 的所有信息合并成一个 trace,一览无余的查看整个链路追踪,就需要把 A 的 TraceId 和 SpanId 透传给服务 B,透传的情况又分为四种: - `FPM/Cli` 调用通过`Curl`调用另外一个`FPM`服务 这种情况什么也不用做,tracker 扩展会自动将 TraceId/SpanId 加到 http 的 header 里面实现透传。 - `FPM/Cli` 通过`Curl`调用另外一个`Cli`的服务 这种情况需要在 Cli 的服务端的服务入口和出口加上两个函数,分别是 `beforeExecRpc` 和 `afterExecRpc`: ```php //伪代码 $traceId = $header['x-swoole-traceid'];//装了tracker扩展的curl请求会自动带上x-swoole-traceid这个header $spanId = $header['x-swoole-spanid'];//同上 //执行开始函数,把traceId和spanId传给这个函数 $tick = \SwooleTracker\Stats::beforeExecRpc($func, $serviceName, $serverIp, $traceId, $spanId); /** * 执行真正的业务逻辑 */ \SwooleTracker\Stats::afterExecRpc($tick, $ret, $errno);//调用结束函数 ``` - `FPM/Cli` 通过 Swoole 的`Http/Client` 调用另外一个`Cli`的服务: 在 RPC **被调用**端我们的做法同上,不再赘述,在 RPC 调用端我们需要做一些工作: ```php //在Rpc调用的入口加上如下代码,将traceId和spanId塞到header中 $client->setHeaders(array_merge( [ 'x-swoole-traceid' => getSwooleTrackerTraceId(), 'x-swoole-spanid' => genSwooleTrackerSpanId(), ], $client->requestHeaders )); /** * 进行rpc请求 */ ``` - `FPM/Cli` 通过 `原生TCP协议` 调用另外一个`Cli`的服务: 这个例子有很多,比如`thrift,grpc,tars`, 还有`自定义的rpc协议`等等,此种情况我们需要在调用端和服务端的入口都进行埋点。 在 Rpc 调用端: ```php //伪代码 $traceId = getSwooleTrackerTraceId();//获取当前traceId $spanId = genSwooleTrackerSpanId();//生成一个新的spaId //开始请求前调用,注意函数名和Rpc服务端的不一样,这里为Req而不是Exec $tick = \SwooleTracker\Stats::beforeReqRpc($func, $serviceName, $serverIp); /** * 进行rpc请求 */ $testClient = new TestClient(); //把 $traceId和 $spanId自己想办法带到服务端 $r = $testClient->client->hello('swoole!'. '|'. $traceId . '|'. $spanid); //rpc请求结束后调用,注意函数名和Rpc服务端的不一样,这里为Req而不是Exec \SwooleTracker\Stats::afterReqRpc($tick, $ret, $errno); ``` 在Rpc服务端: ```php //伪代码 $recv = explode("|", $data); $traceId = $recv[1]; $spanId = $recv[2];//从数据中解析出这两个id,也可以自己改rpc协议,直接加到协议头 //执行开始函数,把traceId和spanId传给这个函数 $tick = \SwooleTracker\Stats::beforeExecRpc($func, $serviceName, $serverIp, $traceId, $spanId); /** * 执行真正的业务逻辑 */ \SwooleTracker\Stats::afterExecRpc($tick, $ret, $errno);//调用结束函数 ``` # 设置应用名称 如果自动生成的应用名称不符合要求,可以通过两种方式进行设置: 1. 手动调用API ```php tracker_set_service_name('your_service_name'); ``` >[danger] Swoole Tracker >= v3.3.0 版本可用。 2. 设置Host 通过使用`CURL`、`Co\Http\Client`等方式进行内部调用时,如果是直接基于 `ip:port` 的方式访问,一定要设置一个`host header`,这样可以让`Tracker`知道是哪个应用,否则会把 `ip:port` 当做应用名称。 - CURL ```php $headers = array('Host: your_service_name'); curl_setopt($ch,CURLOPT_HTTPHEADER, $headers); ``` - Co\Http\Client ```php use Swoole\Coroutine\Http\Client; use function Swoole\Coroutine\run; run(function () { $cli = new Client('127.0.0.1', 9502); $cli->setHeaders(['Host' => 'your_service_name']); }); ```