feat: add logging module for backend + frontend error reporting

Backend:
- New Logger utility (app/utils/Logger.php) with category-based log files
  (connect/game/bet/error/frontend under runtime/log/)
- Log WebSocket connect/close events (WsConnect, WsClose)
- Log dealer auth success/failure (SpaceConnectService)
- Log all game events: startBet, endBet, changeBoot, opening for all 7 game types
- Log unhandled exceptions (ExceptionHandle)
- Separate SQL/error logs via apart_level, enable realtime_write for Swoole
- Add /log/report POST endpoint for frontend error ingestion

Frontend:
- New error-report.js with window.onerror + unhandledrejection auto-reporting
- Added to all 12 dealer HTML templates
- Bump VERSION_V to v10.1.0
This commit is contained in:
testadmin
2026-05-14 11:28:33 +08:00
parent 710bb45614
commit d77c6beac7
31 changed files with 168 additions and 7 deletions
+4 -1
View File
@@ -6,6 +6,7 @@ namespace app\services\connect;
use app\models\table\Table;
use app\models\table\UserController;
use app\utils\Logger;
use freedom\utils\SocketSession;
use think\Request;
@@ -38,8 +39,8 @@ class SpaceConnectService
$username = trim($event->get('account'));
$userController = UserController::get(['id' => $userId, 'username' => $username, 'login_token' => $loginToken]);
if (!$tableInfo || !$userController){
Logger::warn(Logger::CAT_CONNECT, 'space_auth_fail', ['table_id' => $tableId, 'username' => $username, 'has_table' => !!$tableInfo, 'has_user' => !!$userController]);
$ws->emit('onlineLogin',['status' => false, 'msg' => 'not_table_data']);
//$ws->close();
return;
}
$lastNumberTab = InitTableService::initTable($tableInfo);
@@ -54,7 +55,9 @@ class SpaceConnectService
$round['show_card'] = GetCardService::getCard($tableInfo,$lastNumberTab);
$ws->emit('onlineLogin',['status' => true, 'table_id' => $tableInfo['id'], 'round' => $round]);
SocketSession::saveSocketSession(['table_id' => $tableInfo['id'], 'table_name' => $tableInfo['table_name']],'space');
Logger::info(Logger::CAT_CONNECT, 'space_login_ok', ['table_id' => $tableInfo['id'], 'table_name' => $tableInfo['table_name'], 'username' => $username]);
}else{
Logger::warn(Logger::CAT_CONNECT, 'space_init_fail', ['table_id' => $tableId, 'username' => $username]);
$ws->emit('onlineLogin',['status' => false, 'table_id' => $tableInfo['id'], 'msg' => 'link_server_fail']);
//$ws->close();
}
@@ -11,6 +11,7 @@ use app\services\waybill\WaybillRemindService;
use freedom\utils\CardPosition;
use freedom\utils\RedisUtil;
use freedom\utils\SocketSession;
use app\utils\Logger;
use think\swoole\Websocket;
/**
@@ -32,6 +33,7 @@ class OpeningBaccaratService
//判断结果并推送结果
$res = self::doOpening($event,$tableInfo);
if ($res['status'] == false){
Logger::warn(Logger::CAT_GAME, 'opening_baccarat_fail', ['table_id' => $tableInfo['id'], 'msg' => $res['msg']]);
$ws->emit('openingBaccarat',['status' => false, 'msg' => $res['msg']]);
return;
}
@@ -52,6 +54,7 @@ class OpeningBaccaratService
);
$ws->emit('openingBaccarat',['status' => true, 'table_id' => $tableInfo['id'], 'round' => $round]);
$ws->to(SocketSession::HOUSE_NAME)->emit('openingBaccaratResult',['status' => true, 'table_id' => $tableInfo['id'], 'round' => $round]);
Logger::info(Logger::CAT_GAME, 'opening_baccarat', ['table_id' => $tableInfo['id'], 'opening' => $opening, 'pair' => $pair, 'luck_six' => $luck_six]);
//处理注单
self::doBet($ws,$tableInfo,$lastNumberTabInfo);
//处理好路
@@ -10,6 +10,7 @@ use app\models\user\User;
use app\services\connect\InitTableService;
use freedom\utils\DiceUtil;
use freedom\utils\SocketSession;
use app\utils\Logger;
use think\swoole\Websocket;
/**
@@ -31,6 +32,7 @@ class OpeningDiceService
//判断结果并推送结果
$res = self::doOpening($event,$tableInfo);
if ($res['status'] == false){
Logger::warn(Logger::CAT_GAME, 'opening_dice_fail', ['table_id' => $tableInfo['id'], 'msg' => $res['msg']]);
$ws->emit('openingDice',['status' => false, 'msg' => $res['msg']]);
return;
}
@@ -47,6 +49,7 @@ class OpeningDiceService
);
$ws->emit('openingDice',['status' => true, 'table_id' => $tableInfo['id'], 'round' => $round]);
$ws->to(SocketSession::HOUSE_NAME)->emit('openingDiceResult',['status' => true, 'table_id' => $tableInfo['id'], 'round' => $round]);
Logger::info(Logger::CAT_GAME, 'opening_dice', ['table_id' => $tableInfo['id'], 'result' => $resultArray]);
//处理注单
self::doBet($ws,$tableInfo,$lastNumberTabInfo,$resultArray,$resultParse);
}
@@ -13,6 +13,7 @@ use freedom\utils\CardPosition;
use freedom\utils\RedisUtil;
use freedom\utils\SocketSession;
use think\facade\Env;
use app\utils\Logger;
use think\swoole\Websocket;
/**
@@ -35,6 +36,7 @@ class OpeningDtService
//判断结果并推送结果
$res = self::doOpening($event,$tableInfo);
if ($res['status'] == false){
Logger::warn(Logger::CAT_GAME, 'opening_dt_fail', ['table_id' => $tableInfo['id'], 'msg' => $res['msg']]);
$ws->emit('openingDt',['status' => false, 'msg' => $res['msg']]);
return;
}
@@ -52,6 +54,7 @@ class OpeningDtService
);
$ws->emit('openingDt',['status' => true, 'table_id' => $tableInfo['id'], 'round' => $round]);
$ws->to(SocketSession::HOUSE_NAME)->emit('openingDtResult',['status' => true, 'table_id' => $tableInfo['id'], 'round' => $round]);
Logger::info(Logger::CAT_GAME, 'opening_dt', ['table_id' => $tableInfo['id'], 'opening' => $opening]);
//处理注单
self::doBet($ws,$tableInfo,$lastNumberTabInfo);
//处理好路
@@ -11,6 +11,7 @@ use app\services\connect\InitTableService;
use freedom\utils\CardPositionNn;
use freedom\utils\RedisUtil;
use freedom\utils\SocketSession;
use app\utils\Logger;
use think\swoole\Websocket;
class OpeningNnService
@@ -26,6 +27,7 @@ class OpeningNnService
//判断结果并推送结果
$res = self::doOpening($event,$tableInfo);
if ($res['status'] == false){
Logger::warn(Logger::CAT_GAME, 'opening_nn_fail', ['table_id' => $tableInfo['id'], 'msg' => $res['msg']]);
$ws->emit('openingNn',['status' => false, 'msg' => $res['msg']]);
return;
}
@@ -41,6 +43,7 @@ class OpeningNnService
$round = array_merge($round,$data);
$ws->emit('openingNn',['status' => true, 'table_id' => $tableInfo['id'], 'round' => $round]);
$ws->to(SocketSession::HOUSE_NAME)->emit('openingNnResult',['status' => true, 'table_id' => $tableInfo['id'], 'round' => $round]);
Logger::info(Logger::CAT_GAME, 'opening_nn', ['table_id' => $tableInfo['id'], 'result_banker' => $data['result_banker'], 'win_p1' => $data['win_player_1'], 'win_p2' => $data['win_player_2'], 'win_p3' => $data['win_player_3']]);
//处理注单
self::doBet($ws,$tableInfo,$lastNumberTabInfo,$data);
}
@@ -8,6 +8,7 @@ use app\models\process\Boot;
use app\models\process\NumberTab;
use app\models\user\User;
use app\services\connect\InitTableService;
use app\utils\Logger;
use freedom\utils\RouletteUtil;
use freedom\utils\SocketSession;
use think\swoole\Websocket;
@@ -31,6 +32,7 @@ class OpeningRouletteService
//判断结果并推送结果
$res = self::doOpening($event,$tableInfo);
if ($res['status'] == false){
Logger::warn(Logger::CAT_GAME, 'opening_roulette_fail', ['table_id' => $tableInfo['id'], 'msg' => $res['msg']]);
$ws->emit('openingRoulette',['status' => false,'table_id' => $tableInfo['id'], 'msg' => $res['msg']]);
return;
}
@@ -47,6 +49,7 @@ class OpeningRouletteService
);
$ws->emit('openingRoulette',['status' => true, 'table_id' => $tableInfo['id'], 'round' => $round]);
$ws->to(SocketSession::HOUSE_NAME)->emit('openingRouletteResult',['status' => true, 'table_id' => $tableInfo['id'], 'round' => $round]);
Logger::info(Logger::CAT_GAME, 'opening_roulette', ['table_id' => $tableInfo['id'], 'result' => $round['result'] ?? '']);
//处理注单
self::doBet($ws,$tableInfo,$lastNumberTabInfo,$result,$resultParse);
}
@@ -11,6 +11,7 @@ use app\services\connect\InitTableService;
use freedom\utils\CardPositionTc;
use freedom\utils\RedisUtil;
use freedom\utils\SocketSession;
use app\utils\Logger;
use think\swoole\Websocket;
class OpeningTcService
@@ -26,6 +27,7 @@ class OpeningTcService
//判断结果并推送结果
$res = self::doOpening($event,$tableInfo);
if ($res['status'] == false){
Logger::warn(Logger::CAT_GAME, 'opening_tc_fail', ['table_id' => $tableInfo['id'], 'msg' => $res['msg']]);
$ws->emit('openingTc',['status' => false, 'msg' => $res['msg']]);
return;
}
@@ -41,6 +43,7 @@ class OpeningTcService
$round = array_merge($round,$data);
$ws->emit('openingTc',['status' => true, 'table_id' => $tableInfo['id'], 'round' => $round]);
$ws->to(SocketSession::HOUSE_NAME)->emit('openingTcResult',['status' => true, 'table_id' => $tableInfo['id'], 'round' => $round]);
Logger::info(Logger::CAT_GAME, 'opening_tc', ['table_id' => $tableInfo['id'], 'result_banker' => $data['result_banker'], 'win_p1' => $data['win_player_1'], 'win_p2' => $data['win_player_2'], 'win_p3' => $data['win_player_3']]);
//处理注单
self::doBet($ws,$tableInfo,$lastNumberTabInfo,$data);
}
@@ -10,6 +10,7 @@ use app\models\user\User;
use app\services\connect\InitTableService;
use freedom\utils\SocketSession;
use freedom\utils\ToningUtil;
use app\utils\Logger;
use think\swoole\Websocket;
/**
@@ -31,6 +32,7 @@ class OpeningToningService
//判断结果并推送结果
$res = self::doOpening($event,$tableInfo);
if ($res['status'] == false){
Logger::warn(Logger::CAT_GAME, 'opening_toning_fail', ['table_id' => $tableInfo['id'], 'msg' => $res['msg']]);
$ws->emit('openingToning',['status' => false, 'msg' => $res['msg']]);
return;
}
@@ -46,6 +48,7 @@ class OpeningToningService
);
$ws->emit('openingToning',['status' => true, 'table_id' => $tableInfo['id'], 'round' => $round]);
$ws->to(SocketSession::HOUSE_NAME)->emit('openingToningResult',['status' => true, 'table_id' => $tableInfo['id'], 'round' => $round]);
Logger::info(Logger::CAT_GAME, 'opening_toning', ['table_id' => $tableInfo['id'], 'result' => $result]);
//处理注单
self::doBet($ws,$tableInfo,$lastNumberTabInfo);
}
+3
View File
@@ -6,6 +6,7 @@ namespace app\services\process;
use app\models\process\NumberTab;
use app\services\connect\InitTableService;
use app\utils\Logger;
use freedom\utils\RedisUtil;
use freedom\utils\SocketSession;
@@ -41,7 +42,9 @@ class EndBetService
'number_tab_status' => InitTableService::numberTabStatus($numberTabInfo)
]
]);
Logger::info(Logger::CAT_GAME, 'end_bet', ['table_id' => $tableInfo['id'], 'nt_id' => $numberTabId]);
}else{
Logger::warn(Logger::CAT_GAME, 'end_bet_fail', ['table_id' => $tableInfo['id'], 'msg' => $modelRes['msg']]);
$ws->emit('endBet', ['status' => false, 'msg' => $modelRes['msg']]);
}
}
+3
View File
@@ -6,6 +6,7 @@ namespace app\services\process;
use app\models\process\NumberTab;
use app\services\connect\InitTableService;
use app\utils\Logger;
use freedom\utils\SocketSession;
/**
@@ -44,7 +45,9 @@ class StartBetService
$ws->emit('startBet', $responseData);
//启动倒计时(该处以后会废弃掉)
CountdownService::countdown($numberTabId,$tableInfo,$modelRes['data']);
Logger::info(Logger::CAT_GAME, 'start_bet', ['table_id' => $tableInfo['id'], 'table_name' => $tableInfo['table_name'], 'nt_id' => $numberTabId]);
}else{
Logger::warn(Logger::CAT_GAME, 'start_bet_fail', ['table_id' => $tableInfo['id'], 'msg' => $modelRes['msg']]);
$ws->emit('startBet', ['status' => false, 'msg' => $modelRes['msg']]);
}
}