Swoole-日志落盘处理
1.ws.php
<?php /** * Created by bingxiong. * Date: 5/19/18 * Time: 7:43 PM * Description: */ class Ws{ CONST HOST="0.0.0.0"; CONST PORT=8811; // public $ws = null; CONST CHART_PORT =8812; public function __construct() { // 重启的时候要获取sMembers获取看看key有没有值,有的话要删掉 $this->ws = new swoole_websocket_server(self::HOST,self::PORT); $this->ws->listen(self::HOST,self::CHART_PORT,SWOOLE_SOCK_TCP); $this->ws->set([ 'enable_static_handler' => true, // 'document_root' => "/Users/bingxiong/swoole/hdtocs/thinkphp/public/static", 'worker_num' => 4, 'task_worker_num' => 4, ]); $this->ws->on("workerstart",[$this,'onWorkerStart']); $this->ws->on("request",[$this,'onRequest']); $this->ws->on("open",[$this,'onOpen']); $this->ws->on("message",[$this,'onMessage']); $this->ws->on("task",[$this,'onTask']); $this->ws->on("finish",[$this,'onFinish']); $this->ws->on("close",[$this,'onClose']); $this->ws->start(); } /** * onWorkerStart的回调 * 加载框架文件 * @param $server * @param $worker_id */ public function onWorkerStart($server, $worker_id){ // 定义应用目录 define('APP_PATH', __DIR__ . '/../../../application/'); // 加载框架引导文件 require __DIR__ . '/../../../thinkphp/start.php'; } /** * request的回调 * @param $request * @param $response */ public function onRequest($request,$response){ // print_r($request->server); // 把图标状态设置成404,防止日志中输出 if($request -> server['request_uri'] == '/favicon.ico'){ $response->status(404); $response->end(); return; } // 将swoole中一些特别的用法装换成原生的php $_SERVER =[]; if(isset($request->server)){ foreach ($request->server as $k => $v){ $_SERVER[strtoupper($k)] = $v; } } $_GET = []; if(isset($request->get)){ foreach ($request->get as $k => $v){ $_GET[$k] = $v; } } $_FILES = []; if(isset($request->files)){ foreach ($request->files as $k => $v){ $_FILES[$k] = $v; } } $_POST = []; if(isset($request -> post)){ foreach ($request->server as $k => $v){ $_POST[$k] = $v; } } // 日志落盘 $this->writeLog(); $_POST['http_server'] = $this->ws; // 执行框架中的内容 ob_start(); try { think\Container::get('app', [APP_PATH]) ->run() ->send(); }catch (\Exception $e){ // todo } $res = ob_get_contents(); ob_end_clean(); $response->end($res); } /** * @param $serv * @param $taskId * @param $workerId * @param $data * @return string */ public function onTask($serv,$taskId,$workerId,$data){ // 分发task任务机制,让不同的任务走不通的逻辑 $obj = new app\common\lib\task\Task; $method = $data['method']; $flag = $obj -> $method($data['data'],$serv); return $flag; // 告诉worker进程 } /** * @param $serv * @param $taskId * @param $data */ public function onFinish($serv,$taskId,$data){ echo "taskId:{$taskId}\n"; echo "finish-data-success:{$data}\n"; } /** * 监听ws打开事件 * @param $ws * @param $request */ public function onOpen($ws,$request){ // print_r($ws); \app\common\lib\redis\Predis::getInstance()->sAdd(config('redis.live_game_key'),$request->fd); var_dump($request->fd); } /** * 监听ws消息事件 * @param $ws * @param $frame */ public function onMessage($ws,$frame){ echo "server-push-message:{$frame->data}\n"; $ws->push($frame->fd,"server-push:".date("Y-m-d H:i:s")); } /** * 监听关闭事件 * @param $ws * @param $fd */ public function onClose($ws,$fd){ // fd 删除 \app\common\lib\redis\Predis::getInstance()->sRem(config('redis.live_game_key'),$fd); echo "clientId:{$fd}\n"; } public function writeLog(){ // 获取请求信息 $data = array_merge(['data'=>date("Ymd H:i:s")],$_GET,$_POST,$_SERVER); // 遍历写入信息,因为获取到信息是索引数组 $logs = ""; foreach ($data as $key => $value){ $logs .= $key.":".$value." "; } swoole_async_writefile(APP_PATH.'../runtime/log/'.date("Ym")."/".date("d")."_access.log", $logs.PHP_EOL,function ($filename){ // todo },FILE_APPEND); } } // 直接new来开启服务 new Ws();
说明:
- 使用了swoole异步文件写入来实现高性能日志的写入
- 在onRequest中进行日志的写入,其实就是每次连接成功的时候就获取这次请求的超全局变量信息$_GET, $_POST, $_SERVER然后写入
- 需要注意favicon会被视为一次请求,因此需要在onRequest中把这个请求视为404,查看这个请求的方法是打印request -> server然后找到这个请求的索引是request_uri然后局把它的状态设置为404.