需求背景: 开发没有服务器权限,无法看到日志报错,所有就用了web socket自动加载日志显示到浏览器console终端。
关键字: websocket swoole inotify
浏览器端效果图(右键点击打开新页面):
服务端代码:
<?php
/*
参考文章:
https://my.oschina.net/matyhtf/blog/343508
https://www.swoole.com/
https://blog.csdn.net/beyond__devil/article/details/53771563
要安装两个php扩展模块
apt-get install gcc make php7.0-dev php-pear
pecl install swoole
pecl install inotify
extension=swoole.so
extension=inotify.so
*/
$server = new swoole_websocket_server("0.0.0.0", 9502);
$server->on('open', function($server, $req) {
echo "connection open: {$req->fd}\n";
});
$server->on('message', function($server, $frame) {
$projectName = $frame->data;
$myMonth = date('Ym');
$myDay = date('d');
$file = "/www/{$projectName}/runtime/log/{$myMonth}/{$myDay}.log";
if (! is_file($file)) {
$err_msg = "ERROR: {$file} not exists\n";
} else {
$lastpos = 0;
while (true) {
$str = tail($file,$lastpos);
$server->push($frame->fd, $str);
}
}
});
$server->on('close', function($server, $fd) {
echo "connection close: {$fd}\n";
});
$server->start();
//实时获取新写入的字符串类似linux的 tail -f 命令
function tail($file,&$pos) {
$buf = '';
// get the size of the file
if(!$pos) $pos = filesize($file);
// Open an inotify instance
$fd = inotify_init();
// Watch $file for changes.
$watch_descriptor = inotify_add_watch($fd, $file, IN_ALL_EVENTS);
// Loop forever (breaks are below)
while (true) {
// Read events (inotify_read is blocking!)
$events = inotify_read($fd);
// Loop though the events which occured
foreach ($events as $event=>$evdetails) {
// React on the event type
switch (true) {
// File was modified
case ($evdetails['mask'] & IN_MODIFY):
// Stop watching $file for changes
inotify_rm_watch($fd, $watch_descriptor);
// Close the inotify instance
fclose($fd);
// open the file
$fp = fopen($file,'r');
if (!$fp) return false;
// seek to the last EOF position
fseek($fp,$pos);
// read until EOF
while (!feof($fp)) {
$buf .= fread($fp,8192);
}
// save the new EOF to $pos
$pos = ftell($fp); // (remember: $pos is called by reference)
// close the file pointer
fclose($fp);
// return the new data and leave the function
return $buf;
// be a nice guy and program good code ;-)
break;
// File was moved or deleted
case ($evdetails['mask'] & IN_MOVE):
case ($evdetails['mask'] & IN_MOVE_SELF):
case ($evdetails['mask'] & IN_DELETE):
case ($evdetails['mask'] & IN_DELETE_SELF):
// Stop watching $file for changes
inotify_rm_watch($fd, $watch_descriptor);
// Close the inotify instance
fclose($fd);
// Return a failure
return false;
break;
}
}
}
}
客户端代码:
<!DOCTYPE html>
<html>
<head>
<title>HTML5 WebSocket测试</title>
</head>
<body>
<div>
<input type="button" value="Start" onclick="start()" />
</div>
<div id="messages"></div>
<script type="text/javascript">
var webSocket = new WebSocket('ws://xxx.xxx.xxx:9502');
webSocket.onerror = function(event) {
alert(event.data);
};
//与WebSocket建立连接
webSocket.onopen = function(event) {
document.getElementById('messages').innerHTML = '与服务器端建立连接';
};
//处理服务器返回的信息
webSocket.onmessage = function(event) {
document.getElementById('messages').innerHTML += '<br />'+ event.data;
};
function start() {
//向服务器发送请求
webSocket.send('我是jCuckoo');
}
</script>
</body>
</html>