之前业务上写日志记录的时候都是同步处理,日志处理模块总是要浪费一些时间的,导致系统整体响应较慢,上 kafka 那种级别的东西又有点杀鸡牛刀,于是打算上 Redis,利用 List 做一下队列,东西不难,记个思路。
前提:
1. 安装Redis 2. 安装 php_redis 扩展
思路:
代码:
\application\common\command\Log.php
<?php
// +----------------------------------------------------------------------
// | Author: Liu Xiaoyu <[email protected]>
// +----------------------------------------------------------------------
// | Date: 2019/10/15 8:16
// +----------------------------------------------------------------------
namespace app\common\command;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use think\Exception;
class Log extends Command
{
protected function configure()
{
$this -> setName('log:start') -> setDescription('Start Log Server By Redis');
}
protected function execute(Input $input, Output $output)
{
$redis = new \Redis();
$redis -> connect('127.0.0.1', 6379);
// 获取 数据库方法
// 我这的目的 后边有个地方 要根据之前传的参数 找对应方法 扔到 redis里存一下, hash 读起来快
if (!$redis -> hLen('coa_method')) {
$method = db('method') -> field('name, en_name, method') -> select();
$hash = [];
foreach ($method as $v) {
$hash[$v['method']] = serialize($v);
}
$redis -> hMSet('coa_method', $hash);
}
while (true) {
try {
// 取出队列头
$task = $redis->lPop('coa_log');
if(!$task) {
// 没有数据 睡3秒, 防止 不断循环 整死了
sleep(3);
continue;
}
$log = unserialize($task);
// dump($log);
// 这个地方是一个小逻辑
for ($i = 0; $i < strlen($log['controller']); $i++) {
echo $log['controller'][$i];
if ( (ord($log['controller'][$i]) >= ord('A')) && (ord($log['controller'][$i]) <= ord('Z')) && $i !== 0) {
// 有大写字符, 插一下
$log['controller'] = substr_replace($log['controller'], '_',$i, 0);
$i++;
}
}
// 获取方法名所对中文
$method_str = $log['module'].'/'.$log['controller'].'/'.$log['action'];
$arr_str = [
'name' => '',
'en_name' => '',
];
$method_str = strtolower($method_str);
if ($redis -> hExists('coa_method', $method_str)) {
$hash_str = $redis -> hGet('coa_method', $method_str);
$arr_str = unserialize($hash_str);
}
$log['cn_name'] = $arr_str['name'];
$log['en_name'] = $arr_str['en_name'];
// save
db('log') -> insert($log);
} catch (\RedisException $exception) {
echo $exception -> getMessage();
}
}
}
}
在 \application\command.php 加入
return [
'LogServer' => 'app\common\command\Log'
];
至此,轮询进程(消费者)已经写完,根目录下执行
php think LogServer
没有反应就对了,因为现在队列里是空的,sleep了,可以在 sleep 那里加上echo 看看 什么反应。
现在开始写 任务
\application\common\behavior\Log.php
<?php
namespace app\common\behavior;
use think\facade\Request;
class Log
{
public function run(Request $request = null)
{
// 获取信息
try {
$userinfo = session('userinfo');
$info = [
'module' => Request::module(),
'controller' => Request::controller(),
'action' => Request::action(),
'param' => serialize(Request::param()),
'username' => $userinfo['username'],
'userid' => $userinfo['id'],
'is_admin' => $userinfo['is_admin'],
'time' => time()
];
// 加入 redis 队列
$redis = new \Redis();
$redis -> connect('127.0.0.1', 6379);
// 完毕
$redis -> rPush('coa_log', serialize($info));
} catch (\RedisException $exception) {
// echo $exception -> getMessage();
}
}
}
\application\tags.php 在 app_begin 这里加上
// 应用开始
'app_begin' => [
'\app\common\behavior\Log',
],
好了,前面开始跑业务吧,看看刚才 php think LogServer 的命令行是不是输出东西了,里面有一些业务逻辑,根据实际更改即可。
代码是在 Win下开发的,linux下同理。