thinkphp6如何使用中间件记录行为日志
作者:字节舞动 发布时间:2023-06-13 14:43:44
前言
发现本站没有一个靠谱的tp6记录行为日志的教程,于是就整理了一下自己在项目中已经投入使用的行为日志中间件的详细配置步骤供大家参考
提示:先阅读官方中间件教程 https://www.kancloud.cn/manual/thinkphp6_0/1037493
中间件
一、定义中间件
可以通过命令行指令快速生成中间件
php think make:middleware Behavior
这个指令会 app/middleware目录下面生成一个Behavior中间件。
内容如下:
<?php
declare (strict_types = 1);
namespace app\middleware;
use think\facade\Log;
class Behavior
{
/**
* 处理请求
*
* @param \think\Request $request
* @param \Closure $next
* @return Response
*/
public function handle($request, \Closure $next)
{
//start 加入以下内容
$admin = get_admin_info(); //当前登录用户的信息,自己实现
$method = strtolower($request->method());
$is_ajax = $request->isAjax();
$route = $request->pathinfo();
$req = $_REQUEST;
unset($req['s'],$req['_session']);
$req_data = $req ? json_encode($req) : '';
$data = [
'admin_id' => $admin['id'],//操作人id
'admin_user' => $admin['user'],//操作人用户名
'route' => $route,//操作的路由地址
'method' => $method,//get/post
'req_tp' => $is_ajax ? 'ajax' : 'normal',
'req_data' => $req_data, //get/post的数据
'ip' => getIp(),
'create_time' => time()
];
//end
return $next($request);
}
}
二、使用日志通道暂存行为日志
不建议将行为日志实时写入数据库给数据库造成不必要的压力. 我们先写入log文件缓存,定时存入数据库
提示:先阅读官方日志处理教程 https://www.kancloud.cn/manual/thinkphp6_0/1037616
日志处理
1.修改log配置文件
打开config/log.php ,在’channels’ => [] 最后加入一个记录行为日志的单独通道:
// 其它日志通道配置
//行为日志
'behavior' => [
'path' => runtime_path().'behavior', //日志存放目录
'type' => 'File',
'single' => 'b', //单一文件日志:文件名
'file_size' => 1024*1024*10, //日志文件大小限制(超出会生成多个文件
'max_files' => 30, //文件最大数量
'realtime_write' => false, // 关闭实时写入
],
2.注册全局中间件
打开app/middleware.php ,注册个行为日志全局中间件
<?php
// 全局中间件定义文件
return [
// 全局请求缓存
// \think\middleware\CheckRequestCache::class,
// 多语言加载
// \think\middleware\LoadLangPack::class,
// Session初始化
// \think\middleware\SessionInit::class
// 行为日志
\app\middleware\Behavior::class,
];
3.测试能否成功生成日志
随便访问一个本项目页面,例如:http://www.tp6.com/index/index/test?a=1&b=2,看能否生成以下文件.
打开文件,数据已写入
{“time”:“2022-04-16T21:38:48+08:00”,“type”:“info”,“msg”:"{“admin_id”:888,“admin_user”:“fanchen”,“route”:“index\/index\/test”,“method”:“get”,“req_tp”:“normal”,“req_data”:"{\“a\”:\“1\”,\“b\”:\“2\”}",“ip”:“127.0.0.1”,“create_time”:1650116328}"}
三、使用定时任务将日志内容定时写入数据库
1.新建一个api方法
要求定时任务可以访问到
/**
* 定时任务服务器定时将用户行为日志插入到数据库
* @return void
*/
public function sync_behavior_log()
{
$path = runtime_path() . 'behavior/b.log';
$b_file = file_get_contents($path);
$b_arr = explode(PHP_EOL, $b_file);
$d = [];
foreach ($b_arr as $b) {
$data = json_decode($b, true);
if (!empty($data['msg'])) {
$d[] = json_decode($data['msg'], true);
}
}
if ($d) {
try {
Db::name('log_behavior')->insertAll($d); //批量插入数据库
file_put_contents($path, ''); //清空文件日志
echo '采集用户行为日志成功' . count($d);
} catch (DbException $e) {
echo ($e->getMessage());
}
}
}
2.新建行为日志数据表log_behavior
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for log_behavior
-- ----------------------------
DROP TABLE IF EXISTS `log_behavior`;
CREATE TABLE `log_behavior` (
`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID',
`admin_id` int(11) NOT NULL DEFAULT 0 COMMENT '用户id',
`admin_user` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '用户名',
`route` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '模块名称',
`method` enum('delete','put','post','get') CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT 'get' COMMENT '请求方式 1get 2post 3put 4delete',
`req_data` varchar(300) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '请求数据',
`ip` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '用户ip',
`create_time` int(11) NOT NULL DEFAULT 0 COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `uid`(`admin_id`) USING BTREE,
INDEX `admin_user`(`admin_user`) USING BTREE,
INDEX `route`(`route`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3902195 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '行为日志' ROW_FORMAT = Compact;
SET FOREIGN_KEY_CHECKS = 1;
3.新建定时任务
新建定时任务,定时访问步骤1的sync_behavior_log地址就行了, 建议5分钟1次
至此, 有用户访问时,数据表就会每隔一段时间就批量插入行为日志数据了
总结
写得比较简单粗暴, 有些地方需要自己实现, 比如获取登录用户信息
来源:https://blog.csdn.net/zc745317309/article/details/124219664


猜你喜欢
- 一、介绍线程是什么?线程有啥用?线程和进程的区别是什么?线程是操作系统能够进行运算调度的最小单位。被包含在进程中,是进程中的实际运作单位。一
- 下午有个朋友问json 数据怎么分页 就捣鼓了一个东东出来下面直接代码:<!DOCTYPE html PUBLIC "-//
- bootstrap 中的bootstrapValidator可以对前端的数据进行验证,但是有的时候我们需要动态的添加验证,这样需要我们动态的
- 要读懂这些代码主要是要了解ASP中操作二进制数据的对象ADODB.Stream!本程序主要用的就是Adodb.Stream,如果你有这个基础
- 一、概述音频时域波形具有以下特征:音调,响度,质量。我们在进行数据增强时,最好只做一些小改动,使得增强数据和源数据存在较小差异即可,切记不能
- # -*- coding: utf-8 -*-import sysimport MySQLdbreload(sys)sys.setdefau
- Map 类型先看例子 m1:func main() { m := make(map[int]int) mdMap(m) fmt.Printl
- 本文实例总结了JS常见简单正则表达式验证功能。分享给大家供大家参考,具体如下:下面都是一些比较常用简单的验证,像那些特殊的复杂的情况这里不进
- 创建时间序列函数pd.date_range()根据指定的范围,生成时间序列DatetimeIndex,每隔元素的类型为Timestamp。该
- 原文:Five quick JavaScript tips真是五个很quick的小提示:1.只在<form>元素上使用submi
- 看lifesinger的《由Kimi找茬想到的》,我想到的:1、 我不同意将“合并付款”定调在“很多卖家都需要”。这个“很多”在卖家里面大概
- 最近写了一个软件屡屡打包不能正常运行,而直接在cmd命令行窗口运行却都能正常输出,没有任何报错,一开始怀疑程序里面sys.args[1]使用
- 两个JS之间的函数互相调用这个问题是我在工作中用到的一个方法 因为要做封装所以想到能不能在一个js中引用另一个js中的function这样的
- Django2.0 通过URL访问上传的文件(pdf、picture等)Django是一个成熟的web框架,基于python实现,有很多的优
- 如果是在Oracle10g之前,删除一个表空间中的数据文件后,其文件在数据库数据字典中会仍然存在,除非你删除表空间,否则文件信息不会清除。但
- 很多开发人员对于IIS和ASP.NET的安装等问题困扰,特此做下面的小总结,请大家多交流!iis 坏了修复办法!一般IIS运行不了ASP.N
- SOA 服务用消息进行通信,该消息通常使用XML Schema来定义(也叫做XSD, XML Schema Definition)。消费者和
- 本文实例讲述了go语言使用pipe读取子进程标准输出的方法。分享给大家供大家参考。具体如下:其核心代码如下:cmd := exec.Comm
- 1.引言甘特图已经拥有 100 多年的历史,这种可视化图表对项目管理非常有用。Henry Gantt 为了分析已经完成的项目创建了甘特图,他
- 前言大家在使用pymysql的时候,通过fetchall()或fetchone()可以获得查询结果,但这个返回数据是不包含字段信息的(不如p