为什么是追踪?
hyperf官网有用链追踪,需要配合其他第三方应用,有些应用怎么简单怎么部署,能不能用日志来实现追踪?
当然可以,通过上下文+封装Log类+接口统一响应
原理
- 上下文设置会话追踪ID
- 封装Log类输出日志统一带上会话追踪ID
- 接口统一响应返回会话追踪ID方便后续查找
封装Log
<?php
declare(strict_types=1);
namespace App;
use Hyperf\Logger\LoggerFactory;
use Hyperf\Context\ApplicationContext;
class Log
{
public static function get(string $name = 'app')
{
return ApplicationContext::getContainer()->get(LoggerFactory::class)->get($name);
}
/**
* 生成追踪ID
* @return void
*/
private static function newTraceId()
{
Context::set('trace_id' , uniqid());
}
// TODO 是否需要增加设置追踪ID的方法,用于队列追踪或其他应用调用链路追踪
/**
* 获取追踪ID
* @return mixed
*/
public static function getCxtTraceId()
{
$traceId = Context::get('trace_id');
if(empty($traceId)){
self::newTraceId();
}
return $traceId;
}
/**
* 获取日志前缀包含追踪ID
* @return string
*/
private static function getSuffix()
{
$traceId = self::getCxtTraceId();
return ' traceId=' . $traceId.' |';
}
/**
* 输出日志
* @param $message
* @return mixed
*/
public static function info($message='')
{
$message = self::getSuffix().$message;
return self::get()->info($message);
}
}
接口统一响应
<?php
declare(strict_types=1);
namespace App\Controller;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Contract\ResponseInterface;
use Psr\Container\ContainerInterface;
use App\Log;
use Hyperf\Di\Annotation\Inject;
abstract class AbstractController
{
/**
* @Inject
* @var ContainerInterface
*/
protected $container;
/**
* @Inject
* @var RequestInterface
*/
protected $request;
/**
* @Inject
* @var ResponseInterface
*/
protected $response;
protected function success($data = [])
{
return $this->response->json([
'code' => 0,
'data' => $data,
'trace_id' => Log::getCxtTraceId()
]);
}
protected function fail($code, $message = '')
{
return $this->response->json([
'code' => $code,
'message' => $message,
'trace_id' => Log::getCxtTraceId()
]);
}
}
其他
- 异常捕捉
- 中间件捕捉
- 是否可以直接全局修改Response的响应结果