php项目记录api的req和res日志
dio 2023-05-23 php
# laravel 框架处理
config下logging.php增加配置
'api' => [
'driver' => 'single',
'path' => storage_path('logs/'.date('Y-m').'api_requests.log'),
'level' => 'info',
'days' => 30,
],
增加中间件 Kernel下增加
protected $middleware = [
// \App\Http\Middleware\TrustHosts::class,
\App\Http\Middleware\TrustProxies::class,
\Fruitcake\Cors\HandleCors::class,
\App\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\App\Http\Middleware\EnableCrossRequest::class,
// \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\OperationLog::class,//记录每次请求log es方便查询log
];
中间件代码如下
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Log;
class OperationLog
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
return $next($request);
}
/**
* @param $request
* @param $response
* @
*/
public function terminate($request, $response)
{
$path = $request->path(); //操作的路由
$input = $request->all() ? $request->all() : $request->getContent();
$method = $request->method(); //操作的方法
$loginToken = $request->header('loginToken');
$token = $request->header('token') ? $request->header('token') : $request->bearerToken();
$token = $loginToken ? $loginToken : $token;
$output = $response->getContent();
$start_time = defined('LARAVEL_START') ? LARAVEL_START : microtime(true);
$end_time = microtime(true);
$execution_time = round(($end_time - $start_time) * 1000, 2).'ms';
//记录log
if ($method != 'OPTIONS') {
$out = json_decode($output,true);
$code = $out['code'] ?? 999;
$level = 1;
$code > 200 && $level = '999error';
//记录log 开关,开发、测试环境才会开启记录log入库方便查看
$arr = [
'project' => 'laravel-backend',
'execution_time' => $execution_time,//代码执行时间 稍微有些误差
'path' => $path,
'url' => $request->fullUrl(),
'level' => $level,
'method' => $method,
'ip' => self::getClientIp(),
'input' => $input,
'output' => $out,
'created' => date('Y-m-d H:i:s'),
];
//剔除 换行符号 保证当前log记录为一行 kibana查询为一条记录
self::removeNewlines($arr);
Log::channel('api')->info('laravel-backend',$arr);
// if(env('LOG_RECORD')){
// $log = new \App\Models\OperationLog();
// $log->setAttribute('user_id', getStaffId());
// $log->setAttribute('path', $path);
// $log->setAttribute('level', $level);
// $log->setAttribute('method', $method);
// $log->setAttribute('token', $token);
// $log->setAttribute('ip', getClientIp());
// $log->setAttribute('input', (is_array($input) ? json_encode($input, 320) : $input));
// $log->setAttribute('output', json_encode(json_decode($output, true), 320));
// $log->save();
// }
}
}
public static function removeNewlines(&$arr) {
foreach ($arr as &$value) {
if (is_array($value)) {
self::removeNewlines($value);
} else {
$value = str_replace([" ", "\t", "\n", "\r"], "", $value);
$value = preg_replace('/\s+/', '', $value);
}
}
}
public static function getClientIp()
{
if (getenv('HTTP_CLIENT_IP')) {
$ip = getenv('HTTP_CLIENT_IP');
}
if (getenv('HTTP_X_REAL_IP')) {
$ip = getenv('HTTP_X_REAL_IP');
} elseif (getenv('HTTP_X_FORWARDED_FOR')) {
$ip = getenv('HTTP_X_FORWARDED_FOR');
$ips = explode(',', $ip);
$ip = $ips[0];
} elseif (getenv('REMOTE_ADDR')) {
$ip = getenv('REMOTE_ADDR');
} else {
$ip = '0.0.0.0';
}
return $ip;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# yii2.0 框架处理
添加相关配置
'bootstrap' => ['log','app\common\components\events\AfterRequest'],
log记录配置
//记录每次api请求记录到log文件,然后es那边读取,后面查看log直接在kibana查看
[
// 'class' => app\common\components\ParamsTarget::class,
'class' => 'yii\log\FileTarget',
'categories' => ['yii2.0'],
'logVars' => [],
'levels' => [],
'except' => [
'yii\web\HttpException:404', // 排除此异常的日志记录
],
'maxLogFiles' => 20, // 日志文件的最大数量
'maxFileSize' => 1024 * 1024 * 500, // 每个日志文件的最大大小(单位:字节)
'logFile' => '@runtime/logs/' . date('Y-m') . 'api_requests.log'
],
具体代码
<?php
namespace app\common\components\events;
use Yii;
use yii\base\Event;
use yii\web\Request;
use yii\web\Response;
class AfterRequest extends Event
{
public function init()
{
Yii::$app->on(yii\base\Application::EVENT_AFTER_REQUEST, function ($event) {
$method = Yii::$app->request->method;
$output = Yii::$app->getResponse()->data->raw;//返回数据
$start_time = $_SERVER['REQUEST_TIME_FLOAT'] ?? microtime(true);
$end_time = microtime(true);
$execution_time = round(($end_time - $start_time) * 1000, 2).'ms';
//排除一些 固定数据的路由无需记录
$outRoutes = [
'api/default/district',//省市区
'mch_api/util/districts', //地区列表
'mch_api/store/categorys-all-list', //获取商品全部类目信息
];
$path = Yii::$app->controller->getRoute();
//排除前端 网络测试请求 和前后端不分离请求
if ($method != 'OPTIONS' && !empty($output) && !in_array($path, $outRoutes)) {
//由于前后端不分离可能有很多 页面返回的是null
$output = Yii::$app->getResponse()->data->raw;
$code = null;
if (isset($output['code'])) {
$code = $output['code'];
}
$data = [
'project' => 'yii2.0',
'execution_time' => $execution_time,//执行时间不够准确
'path' => $path,
'url' => Yii::$app->request->getUrl(),
'level' => in_array($code, [0, 200]) ? 1 : '999error',
'method' => $method,
// 'header' => json_encode(Yii::$app->request->headers->toArray(), JSON_UNESCAPED_UNICODE),
'ip' => Yii::$app->request->userIP,
'input' => Yii::$app->request->bodyParams,
'output' => $output,
'created_at' => date('Y-m-d H:i:s'),
];
Yii::$app->log->traceLevel = 0;//排除多于的追踪信息 不然一条请求占用es两行记录
Yii::info(json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE), 'yii2.0');
}
//下方记录数据库的排除,日志查看一次老费劲了,而且数据量大db查看不现实 改用log用es查看
// if(Yii::$app->request->method != 'OPTIONS' && env('LOG_RECORD')){
// $model = new OperationLog();
// $model->user_id = 1;
// $model->user_name = 1;
// $model->project = 'yii';
// $model->path = Yii::$app->controller->getRoute();
// $model->level = 1;
// $model->method = Yii::$app->request->method;
// $model->header = json_encode(Yii::$app->request->headers->toArray(), JSON_UNESCAPED_UNICODE);
// $model->ip = Yii::$app->request->userIP;
// $model->input = json_encode(Yii::$app->request->bodyParams, JSON_UNESCAPED_UNICODE);
// $model->output = json_encode(Yii::$app->getResponse()->data->raw, JSON_UNESCAPED_UNICODE);
// $model->created_at = date('Y-m-d H:i:s');
// $model->updated_at = date('Y-m-d H:i:s');
// $model->save();
//// Yii::info('api接口请求记录:' . stripslashes(json_encode($data, JSON_UNESCAPED_UNICODE)), 'info');
// }
});
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96