Skip to content

Commit

Permalink
1、增加 单独监听上报所有进程SQL、Redis信息
Browse files Browse the repository at this point in the history
2、增加 监控上报自定义进程onMessage回调内的异常抛出信息
  • Loading branch information
hsk99 committed Jul 22, 2022
1 parent de43583 commit 3e603e2
Show file tree
Hide file tree
Showing 5 changed files with 322 additions and 30 deletions.
9 changes: 7 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
{
"name": "hsk99/webman-statistic",
"type": "library",
"keywords": [
"webman"
],
"homepage": "http://www.workerman.net/webman",
"license": "MIT",
"homepage": "http://hsk99.com.cn",
"description": "webman-statistic 应用监控插件",
"authors": [
{
"name": "hsk99",
Expand All @@ -11,7 +15,8 @@
}
],
"require": {
"workerman/http-client": "^1.0"
"workerman/http-client": "^1.0",
"phpmyadmin/sql-parser": "^5.5"
},
"autoload": {
"psr-4": {
Expand Down
144 changes: 140 additions & 4 deletions src/Bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,20 @@

namespace Hsk99\WebmanStatistic;

use Hsk99\WebmanStatistic\Statistic;

class Bootstrap implements \Webman\Bootstrap
{
/**
* @var \Workerman\Http\Client
*/
protected static $_instance = null;

/**
* @var string
*/
public static $process = null;

/**
* @author HSK
* @date 2022-06-17 15:33:53
Expand All @@ -20,6 +27,8 @@ class Bootstrap implements \Webman\Bootstrap
public static function start($worker)
{
if ($worker) {
static::$process = $worker->name;

$options = [
'max_conn_per_addr' => 128, // 每个地址最多维持多少并发连接
'keepalive_timeout' => 15, // 连接多长时间不通讯就关闭
Expand All @@ -28,13 +37,18 @@ public static function start($worker)
];
self::$_instance = new \Workerman\Http\Client($options);

// 定时上报数据
\Workerman\Timer::add(config('plugin.hsk99.statistic.app.interval', 30), function () {
\Hsk99\WebmanStatistic\Statistic::report();
Statistic::report();
});

$worker->onWorkerStop = function () {
\Hsk99\WebmanStatistic\Statistic::report();
};
// 执行监听所有进程 SQL、Redis
static::listen($worker);

// 延迟接管进程业务回调,执行监控
\Workerman\Timer::add(1, function () use (&$worker) {
static::monitor($worker);
}, '', false);
}
}

Expand All @@ -48,4 +62,126 @@ public static function instance(): \Workerman\Http\Client
{
return self::$_instance;
}

/**
* SQL、Redis 监听
*
* @author HSK
* @date 2022-07-20 17:22:06
*
* @param \Workerman\Worker $worker
*
* @return void
*/
protected static function listen(\Workerman\Worker $worker)
{
if (class_exists(\think\facade\Db::class)) {
\think\facade\Db::listen(function ($sql, $runtime, $master) {
if ($sql === 'select 1' || !is_numeric($runtime)) {
return;
}
Statistic::sql(trim($sql), $runtime * 1000, ['master' => $master]);
});
}

if (class_exists(\Illuminate\Database\Events\QueryExecuted::class)) {
try {
\support\Db::listen(function (\Illuminate\Database\Events\QueryExecuted $query) {
$sql = trim($query->sql);
if (strtolower($sql) === 'select 1') {
return;
}
$sql = str_replace("?", "%s", $sql);
foreach ($query->bindings as $i => $binding) {
if ($binding instanceof \DateTime) {
$query->bindings[$i] = $binding->format("'Y-m-d H:i:s'");
} else {
if (is_string($binding)) {
$query->bindings[$i] = "'$binding'";
}
}
}
$sql = vsprintf($sql, $query->bindings);
Statistic::sql($sql, $query->time, ['connection' => $query->connectionName]);
});
} catch (\Throwable $e) {
}
}

if (class_exists(\Illuminate\Redis\Events\CommandExecuted::class)) {
foreach (config('redis', []) as $key => $config) {
if (strpos($key, 'redis-queue') !== false) {
continue;
}
try {
\support\Redis::connection($key)->listen(function (\Illuminate\Redis\Events\CommandExecuted $command) {
$parameters = array_map(function ($item) {
if (is_array($item)) {
return json_encode($item, 320);
}
return $item;
}, $command->parameters);
$parameters = implode('\', \'', $parameters);
if ('get' === $command->command && 'ping' === $parameters) {
return;
}
Statistic::redis($command->command, $parameters, $command->time, ['connection' => $command->connectionName]);
});
} catch (\Throwable $e) {
}
}
}
}

/**
* 监控进程
*
* @author HSK
* @date 2022-07-21 13:17:14
*
* @param \Workerman\Worker $worker
*
* @return void
*/
protected static function monitor(\Workerman\Worker $worker)
{
// 接管所有进程 onWorkerStop 回调,上报缓存数据
$oldWorkerStop = $worker->onWorkerStop;
$worker->onWorkerStop = function ($worker) use (&$oldWorkerStop) {
Statistic::report();

try {
if (is_callable($oldWorkerStop)) {
call_user_func($oldWorkerStop, $worker);
}
} catch (\Throwable $exception) {
} catch (\Exception $exception) {
} catch (\Error $exception) {
} finally {
if (isset($exception)) {
echo $exception . PHP_EOL;
}
}
};

// 接管自定义进程 onMessage 回调,监控其异常抛出
if (config('server.listen') !== $worker->getSocketName()) {
$oldMessage = $worker->onMessage;
$worker->onMessage = function ($connection, $message) use (&$oldMessage) {
try {
if (is_callable($oldMessage)) {
call_user_func($oldMessage, $connection, $message);
}
} catch (\Throwable $exception) {
} catch (\Exception $exception) {
} catch (\Error $exception) {
} finally {
if (isset($exception)) {
Statistic::exception($exception);
echo $exception . PHP_EOL;
}
}
};
}
}
}
44 changes: 21 additions & 23 deletions src/Middleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,29 +53,26 @@ public function process(\Webman\Http\Request $request, callable $next): \Webman\
}

if (class_exists(\Illuminate\Database\Events\QueryExecuted::class)) {
foreach (config('database.connections', []) as $key => $config) {
$driver = $config['driver'] ?? 'mysql';
try {
\support\Db::connection($key)->listen(function (\Illuminate\Database\Events\QueryExecuted $query) use ($key, $driver) {
$sql = trim($query->sql);
if (strtolower($sql) === 'select 1') {
return;
}
$sql = str_replace("?", "%s", $sql);
foreach ($query->bindings as $i => $binding) {
if ($binding instanceof \DateTime) {
$query->bindings[$i] = $binding->format("'Y-m-d H:i:s'");
} else {
if (is_string($binding)) {
$query->bindings[$i] = "'$binding'";
}
try {
\support\Db::listen(function (\Illuminate\Database\Events\QueryExecuted $query) {
$sql = trim($query->sql);
if (strtolower($sql) === 'select 1') {
return;
}
$sql = str_replace("?", "%s", $sql);
foreach ($query->bindings as $i => $binding) {
if ($binding instanceof \DateTime) {
$query->bindings[$i] = $binding->format("'Y-m-d H:i:s'");
} else {
if (is_string($binding)) {
$query->bindings[$i] = "'$binding'";
}
}
$log = vsprintf($sql, $query->bindings);
$this->sqlLogs[] = "[driver:$driver] [connection:$key] $log [ RunTime: {$query->time} ms ]";
});
} catch (\Throwable $e) {
}
}
$log = vsprintf($sql, $query->bindings);
$this->sqlLogs[] = "[connection:{$query->connectionName}] $log [ RunTime: {$query->time} ms ]";
});
} catch (\Throwable $e) {
}
}

Expand All @@ -85,7 +82,7 @@ public function process(\Webman\Http\Request $request, callable $next): \Webman\
continue;
}
try {
\support\Redis::connection($key)->listen(function (\Illuminate\Redis\Events\CommandExecuted $command) use ($key) {
\support\Redis::connection($key)->listen(function (\Illuminate\Redis\Events\CommandExecuted $command) {
$parameters = array_map(function ($item) {
if (is_array($item)) {
return json_encode($item, 320);
Expand All @@ -98,7 +95,7 @@ public function process(\Webman\Http\Request $request, callable $next): \Webman\
return;
}

$this->redisLogs[] = "[connection:$key] Redis::{$command->command}('" . $parameters . "') [ RunTime: {$command->time} ms ]";
$this->redisLogs[] = "[connection:{$command->connectionName}] Redis::{$command->command}('" . $parameters . "') [ RunTime: {$command->time} ms ]";
});
} catch (\Throwable $e) {
}
Expand All @@ -110,6 +107,7 @@ public function process(\Webman\Http\Request $request, callable $next): \Webman\

switch (true) {
case method_exists($response, 'exception') && $exception = $response->exception():
\Hsk99\WebmanStatistic\Statistic::exception($exception);
$body = (string)$exception;
break;
case 'application/json' === strtolower($response->getHeader('Content-Type')):
Expand Down
Loading

0 comments on commit 3e603e2

Please sign in to comment.