mirror of
https://gitee.com/ulthon/ulthon_admin.git
synced 2026-07-01 15:32:48 +08:00
增加测试机制;完善DebugMysql日志逻辑;更新debug_log表字段格式;发布新版本
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace think;
|
||||
|
||||
use app\common\command\Test;
|
||||
use app\common\event\AdminLoginSuccess\LogEvent;
|
||||
use app\common\event\AdminLoginType\DemoEvent;
|
||||
use app\common\provider\ExceptionHandle;
|
||||
@@ -10,9 +11,9 @@ use app\common\provider\View;
|
||||
use think\app\Service as AppService;
|
||||
use think\captcha\CaptchaService;
|
||||
use think\facade\App;
|
||||
use think\migration\Service;
|
||||
use think\migration\Service as MigrateService;
|
||||
|
||||
class UlthonAdminService extends \think\Service
|
||||
class UlthonAdminService extends Service
|
||||
{
|
||||
public function boot()
|
||||
{
|
||||
@@ -40,10 +41,14 @@ class UlthonAdminService extends \think\Service
|
||||
$this->app->register(AppService::class);
|
||||
|
||||
// 注册数据库迁移服务
|
||||
$this->app->register(Service::class);
|
||||
$this->app->register(MigrateService::class);
|
||||
|
||||
// 绑定命令行
|
||||
$this->commands([
|
||||
Test::class,
|
||||
]);
|
||||
|
||||
// 绑定标识容器
|
||||
|
||||
$provider_default = [
|
||||
'think\Request' => Request::class,
|
||||
'think\exception\Handle' => ExceptionHandle::class,
|
||||
@@ -68,7 +73,7 @@ class UlthonAdminService extends \think\Service
|
||||
// 多语言加载
|
||||
// \think\middleware\LoadLangPack::class,
|
||||
// Session初始化
|
||||
100 => \think\middleware\SessionInit::class,
|
||||
100 => middleware\SessionInit::class,
|
||||
];
|
||||
|
||||
$this->app->middleware->import($middleware);
|
||||
|
||||
@@ -2,77 +2,90 @@
|
||||
|
||||
namespace think\log\driver;
|
||||
|
||||
use PDO;
|
||||
use think\contract\LogHandlerInterface;
|
||||
use think\facade\App;
|
||||
use PDO;
|
||||
|
||||
class DebugMysql implements LogHandlerInterface
|
||||
class DebugMysql implements LogHandlerInterface
|
||||
{
|
||||
|
||||
protected $enableLog = true;
|
||||
|
||||
protected $config = [];
|
||||
|
||||
/**
|
||||
* @var PDO
|
||||
*/
|
||||
protected $pdo = null;
|
||||
|
||||
protected $file = null;
|
||||
|
||||
protected $fileRescource = null;
|
||||
|
||||
protected $tableName = '';
|
||||
|
||||
protected $reConnectTimes = 0;
|
||||
|
||||
protected $fileLogTimes = 0;
|
||||
|
||||
public $devMode = true;
|
||||
|
||||
/**
|
||||
* 服务器断线标识字符.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $breakMatchStr = [
|
||||
'server has gone away',
|
||||
'no connection to the server',
|
||||
'Lost connection',
|
||||
'is dead or not enabled',
|
||||
'Error while sending',
|
||||
'decryption failed or bad record mac',
|
||||
'server closed the connection unexpectedly',
|
||||
'SSL connection has been closed unexpectedly',
|
||||
'Error writing data to the connection',
|
||||
'Resource deadlock avoided',
|
||||
'failed with errno',
|
||||
'child connection forced to terminate due to client_idle_limit',
|
||||
'query_wait_timeout',
|
||||
'reset by peer',
|
||||
'Physical connection is not usable',
|
||||
'TCP Provider: Error code 0x68',
|
||||
'ORA-03114',
|
||||
'Packets out of order. Expected',
|
||||
'Adaptive Server connection failed',
|
||||
'Communication link failure',
|
||||
'connection is no longer usable',
|
||||
'Login timeout expired',
|
||||
'SQLSTATE[HY000] [2002] Connection refused',
|
||||
'running with the --read-only option so it cannot execute this statement',
|
||||
'The connection is broken and recovery is not possible. The connection is marked by the client driver as unrecoverable. No attempt was made to restore the connection.',
|
||||
'SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Try again',
|
||||
'SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Name or service not known',
|
||||
'SQLSTATE[HY000]: General error: 7 SSL SYSCALL error: EOF detected',
|
||||
'SQLSTATE[HY000] [2002] Connection timed out',
|
||||
'SSL: Connection timed out',
|
||||
'SQLSTATE[HY000]: General error: 1105 The last transaction was aborted due to Seamless Scaling. Please retry.',
|
||||
];
|
||||
|
||||
public function __construct(App $app, $config = [])
|
||||
{
|
||||
if (is_array($config)) {
|
||||
$this->config = array_merge($this->config, $config);
|
||||
}
|
||||
|
||||
$dsn = $this->parseDsn($config);
|
||||
|
||||
try {
|
||||
|
||||
$pdo = $this->createPdo($dsn, $config['username'], $config['password'], $config['params']);
|
||||
|
||||
$this->pdo = $pdo;
|
||||
$this->initConnect();
|
||||
} catch (\Throwable $th) {
|
||||
$this->pdo = null;
|
||||
|
||||
$log_path = App::getRuntimePath() . 'log/' . date('ymd') . '.csv';
|
||||
|
||||
$dirname = dirname($log_path);
|
||||
|
||||
if (!is_dir($dirname)) {
|
||||
mkdir($log_path, 0777, true);
|
||||
}
|
||||
|
||||
$first_line = false;
|
||||
if (!file_exists($log_path)) {
|
||||
$first_line = true;
|
||||
}
|
||||
|
||||
$this->fileRescource = fopen($log_path, 'a');
|
||||
|
||||
if ($first_line) {
|
||||
$fields = [
|
||||
'level',
|
||||
'content',
|
||||
'create_time',
|
||||
'create_time_title',
|
||||
'uid',
|
||||
'app_name',
|
||||
'controller_name',
|
||||
'action_name',
|
||||
];
|
||||
fputcsv($this->fileRescource, $fields);
|
||||
}
|
||||
$this->initFile();
|
||||
}
|
||||
|
||||
|
||||
$this->tableName = $config['prefix'] . 'debug_log';
|
||||
}
|
||||
|
||||
public function save(array $log): bool
|
||||
{
|
||||
|
||||
|
||||
$app_name = app('http')->getName() ?: '';
|
||||
|
||||
$controller_name = '';
|
||||
@@ -81,7 +94,6 @@ class DebugMysql implements LogHandlerInterface
|
||||
if (App::runningInConsole()) {
|
||||
$app_name = 'cli';
|
||||
} else {
|
||||
|
||||
$controller_name = request()->controller();
|
||||
$action_name = request()->action();
|
||||
}
|
||||
@@ -100,7 +112,10 @@ class DebugMysql implements LogHandlerInterface
|
||||
|
||||
foreach ($log as $log_level => $log_list) {
|
||||
foreach ($log_list as $key => $log_item) {
|
||||
|
||||
if (!is_string($log_item)) {
|
||||
$log_item = print_r($log_item, true);
|
||||
}
|
||||
|
||||
$log_data = [
|
||||
'level' => $log_level,
|
||||
'content' => $log_item,
|
||||
@@ -109,30 +124,17 @@ class DebugMysql implements LogHandlerInterface
|
||||
'uid' => $log_key,
|
||||
'app_name' => $app_name,
|
||||
'controller_name' => $controller_name,
|
||||
'action_name' => $action_name
|
||||
'action_name' => $action_name,
|
||||
];
|
||||
|
||||
if (!is_null($this->pdo)) {
|
||||
|
||||
$prepare_name = [];
|
||||
foreach ($log_data as $key => $value) {
|
||||
$prepare_name[] = ':' . $key;
|
||||
try {
|
||||
if (!is_null($this->pdo)) {
|
||||
$this->saveByConnect($log_data);
|
||||
} else {
|
||||
$this->saveByFile($log_data);
|
||||
}
|
||||
|
||||
$data_keys = array_keys($log_data);
|
||||
|
||||
$data_keys_in_sql = join(',', $data_keys);
|
||||
|
||||
$prepare_name_in_sql = join(',', $prepare_name);
|
||||
|
||||
$sql = "INSERT INTO {$this->tableName} ($data_keys_in_sql) VALUES ($prepare_name_in_sql);";
|
||||
|
||||
$stmt = $this->pdo->prepare($sql);
|
||||
|
||||
$stmt->execute($log_data);
|
||||
} else {
|
||||
|
||||
fputcsv($this->fileRescource, $log_data);
|
||||
} catch (\Throwable $th) {
|
||||
$this->saveByFile($log_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -140,9 +142,156 @@ class DebugMysql implements LogHandlerInterface
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function saveByConnect($log_data)
|
||||
{
|
||||
if (is_null($this->pdo)) {
|
||||
$this->saveByFile($log_data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->devLog('save by connect');
|
||||
$prepare_name = [];
|
||||
foreach ($log_data as $key => $value) {
|
||||
$prepare_name[] = ':' . $key;
|
||||
}
|
||||
|
||||
$data_keys = array_keys($log_data);
|
||||
|
||||
$data_keys_in_sql = implode(',', $data_keys);
|
||||
|
||||
$prepare_name_in_sql = implode(',', $prepare_name);
|
||||
|
||||
$sql = "INSERT INTO {$this->tableName} ($data_keys_in_sql) VALUES ($prepare_name_in_sql);";
|
||||
|
||||
try {
|
||||
$stmt = $this->pdo->prepare($sql);
|
||||
$stmt->execute($log_data);
|
||||
} catch (\Exception $th) {
|
||||
if ($this->isBreak($th)) {
|
||||
if ($this->reConnectTimes > 3) {
|
||||
$this->initFile();
|
||||
throw $th;
|
||||
}
|
||||
$this->initConnect();
|
||||
$this->reConnectTimes++;
|
||||
$this->devLog('reconnect ' . $this->reConnectTimes);
|
||||
$this->saveByConnect($log_data);
|
||||
} else {
|
||||
dump($th);
|
||||
$this->saveByFile($log_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function saveByFile($log_data)
|
||||
{
|
||||
$this->devLog('save by file');
|
||||
|
||||
// 如果文件日志超过100条,尝试重新通过数据库连接
|
||||
if ($this->fileLogTimes > 10) {
|
||||
$this->fileLogTimes = 0;
|
||||
$this->initConnect();
|
||||
$this->saveByConnect($log_data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
fputcsv($this->fileRescource, $log_data);
|
||||
$this->fileLogTimes++;
|
||||
} catch (\Throwable $th) {
|
||||
$this->initFile();
|
||||
$this->fileLogTimes++;
|
||||
$this->saveByFile($log_data);
|
||||
}
|
||||
}
|
||||
|
||||
protected function initConnect()
|
||||
{
|
||||
$this->devLog('init connect');
|
||||
|
||||
if (!is_null($this->pdo)) {
|
||||
$this->pdo = null;
|
||||
}
|
||||
|
||||
$this->reConnectTimes = 0;
|
||||
|
||||
$config = $this->config;
|
||||
|
||||
$dsn = $this->parseDsn($config);
|
||||
try {
|
||||
$pdo = $this->createPdo($dsn, $config['username'], $config['password'], $config['params']);
|
||||
$this->pdo = $pdo;
|
||||
} catch (\Throwable $th) {
|
||||
$this->pdo = null;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function initFile()
|
||||
{
|
||||
$this->devLog('init file');
|
||||
|
||||
if (!is_null($this->fileRescource)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$log_path = App::getRuntimePath() . 'log/' . date('ymd') . '.csv';
|
||||
|
||||
$dirname = dirname($log_path);
|
||||
|
||||
if (!is_dir($dirname)) {
|
||||
mkdir($log_path, 0777, true);
|
||||
}
|
||||
|
||||
$first_line = false;
|
||||
if (!file_exists($log_path)) {
|
||||
$first_line = true;
|
||||
}
|
||||
|
||||
$this->fileRescource = fopen($log_path, 'a');
|
||||
|
||||
if ($first_line) {
|
||||
$fields = [
|
||||
'level',
|
||||
'content',
|
||||
'create_time',
|
||||
'create_time_title',
|
||||
'uid',
|
||||
'app_name',
|
||||
'controller_name',
|
||||
'action_name',
|
||||
];
|
||||
fputcsv($this->fileRescource, $fields);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析pdo连接的dsn信息
|
||||
* @access protected
|
||||
* 是否断线
|
||||
*
|
||||
* @param \PDOException|\Exception $e 异常对象
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isBreak($e): bool
|
||||
{
|
||||
$error = $e->getMessage();
|
||||
|
||||
foreach ($this->breakMatchStr as $msg) {
|
||||
if (false !== stripos($error, $msg)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析pdo连接的dsn信息.
|
||||
* @param array $config 连接信息
|
||||
* @return string
|
||||
*/
|
||||
@@ -177,4 +326,11 @@ class DebugMysql implements LogHandlerInterface
|
||||
fclose($this->fileRescource);
|
||||
}
|
||||
}
|
||||
|
||||
protected function devLog($content)
|
||||
{
|
||||
if ($this->devMode) {
|
||||
dump($content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ class Service extends \think\Service
|
||||
|
||||
public function boot()
|
||||
{
|
||||
|
||||
$this->app->bind(FakerGenerator::class, function () {
|
||||
return FakerFactory::create($this->app->config->get('app.faker_locale', 'zh_CN'));
|
||||
});
|
||||
@@ -47,5 +48,6 @@ class Service extends \think\Service
|
||||
SeedRun::class,
|
||||
FactoryCreate::class,
|
||||
]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user