[TOC]
>[success] 上報成功后在后臺查看,需要切換當前項目,默認在默認項目中。

>[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']);
});
```