diff --git a/.gitignore b/.gitignore index 7ee1f598..e82650a2 100644 --- a/.gitignore +++ b/.gitignore @@ -10,8 +10,10 @@ *.log logs/*.txt +api_log.db d_log/*.txt d_log/*.zip +d_log/*.db sess_* */logs/*.txt */logs/*/*.txt diff --git a/f_install/sql/api_log.sql b/f_install/sql/api_log.sql new file mode 100644 index 00000000..4cc67f63 --- /dev/null +++ b/f_install/sql/api_log.sql @@ -0,0 +1,17 @@ +CREATE TABLE IF NOT EXISTS "api_log" ( + "id" INTEGER NOT NULL, + "user_id" INTEGER NOT NULL, + "ip" TEXT NOT NULL, + "date" TEXT NOT NULL, + "path" TEXT NOT NULL, + "arg" TEXT, + "aux" TEXT, + PRIMARY KEY("id" AUTOINCREMENT) +); +CREATE INDEX IF NOT EXISTS "by_date" ON "api_log" ( + "date" DESC +); +CREATE INDEX IF NOT EXISTS "by_user" ON "api_log" ( + "user_id" ASC, + "date" DESC +); diff --git a/src/sammo/APIHelper.php b/src/sammo/APIHelper.php index 3eaf3817..a4cf7a25 100644 --- a/src/sammo/APIHelper.php +++ b/src/sammo/APIHelper.php @@ -34,15 +34,42 @@ class APIHelper $input = []; } + if(class_exists('\\sammo\\UniqueConst')){ + $serverID = UniqueConst::$serverID; + $logPath = "{$rootPath}/logs/{$serverID}/api_log.db"; + } + else{ + $realYearMonth = date('Y_m'); + $logPath = "{$rootPath}/d_log/{$realYearMonth}_api_log.db"; + } + $logDB = FileDB::db($logPath, __DIR__.'/../../f_install/sql/api_log.sql'); + $ip = $_SERVER['REMOTE_ADDR'] ?? 'local'; + $date = date('Y-m-d H:i:s'); + //NOTE: array_merge([], {})의 상황이 가능함. $actionArgs = array_merge($input, $eParams); + $filteredArgs = $actionArgs; + try { $obj = buildAPIExecutorClass($actionPath, $rootPath, $actionArgs); $validateResult = $obj->validateArgs(); if ($validateResult !== null) { + $logDB->insert('api_log', [ + 'user_id' => 0, + 'ip' => $ip, + 'date' => $date, + 'path' => $actionPath, + 'arg' => JSON::encode($filteredArgs), + 'aux' => JSON::encode([ + 'result'=>false, + 'state'=>'validate', + 'reason'=>$validateResult + ]), + ]); Json::dieWithReason($validateResult); } + $filteredArgs = $obj->getFilteredArgs(); $sessionMode = $obj->getRequiredSessionMode(); if ($sessionMode === BaseAPI::NO_SESSION) { @@ -66,6 +93,18 @@ class APIHelper $result = $obj->launch($session, $modifiedSince, $reqEtags); if (is_string($result)) { + $logDB->insert('api_log', [ + 'user_id' => $session->userID, + 'ip' => $ip, + 'date' => $date, + 'path' => $actionPath, + 'arg' => JSON::encode($filteredArgs), + 'aux' => JSON::encode([ + 'result'=>false, + 'state'=>'launch', + 'reason'=>$validateResult + ]), + ]); Json::dieWithReason($result); } @@ -82,28 +121,117 @@ class APIHelper $lastModifiedUnixTime = Util::toInt(TimeUtil::DateTimeToSeconds($cache->lastModified, true)); $modifiedSinceUnixTime = Util::toInt(TimeUtil::DateTimeToSeconds($modifiedSince)); if($lastModifiedUnixTime === $modifiedSinceUnixTime){ + $logDB->insert('api_log', [ + 'user_id' => $session->userID, + 'ip' => $ip, + 'date' => $date, + 'path' => $actionPath, + 'arg' => JSON::encode($filteredArgs), + 'aux' => JSON::encode([ + 'result'=>true, + 'state'=>'cache_not_modified', + ]), + ]); WebUtil::dieWithNotModified(); } } if ($reqEtags !== null && $reqEtags === $cache->etag) { + $logDB->insert('api_log', [ + 'user_id' => $session->userID, + 'ip' => $ip, + 'date' => $date, + 'path' => $actionPath, + 'arg' => JSON::encode($filteredArgs), + 'aux' => JSON::encode([ + 'result'=>true, + 'state'=>'cache_not_modified', + ]), + ]); WebUtil::dieWithNotModified(); } } if ($result === null) { + $logDB->insert('api_log', [ + 'user_id' => $session->userID, + 'ip' => $ip, + 'date' => $date, + 'path' => $actionPath, + 'arg' => JSON::encode($filteredArgs), + 'aux' => JSON::encode([ + 'result'=>true, + 'state'=>'success_simple', + 'set_cache'=>$setCache, + ]), + ]); Json::die([ 'result' => true, 'reason' => 'success' ], $setCache ? 0 : Json::NO_CACHE); } + $logDB->insert('api_log', [ + 'user_id' => $session->userID, + 'ip' => $ip, + 'date' => $date, + 'path' => $actionPath, + 'arg' => JSON::encode($filteredArgs), + 'aux' => JSON::encode([ + 'result'=>true, + 'state'=>'success_complex', + 'set_cache'=>$setCache, + ]), + ]); Json::die($result, $setCache ? 0 : Json::NO_CACHE); } catch (\Exception $e) { - Json::dieWithReason($e->getMessage()."\n".$e->getTraceAsString()); + $errMsg = $e->getMessage(); + $errTrace = $e->getTraceAsString(); + $logDB->insert('api_log', [ + 'user_id' => $session->userID, + 'ip' => $ip, + 'date' => $date, + 'path' => $actionPath, + 'arg' => JSON::encode($filteredArgs), + 'aux' => JSON::encode([ + 'result'=>false, + 'state'=>'error_exception', + 'errMsg'=>$errMsg, + 'errTrace'=>$errTrace, + ]), + ]); + Json::dieWithReason("{$errMsg}\n{$errTrace}"); } catch (\Throwable $e) { logExceptionByCustomHandler($e, false); - Json::dieWithReason($e->getMessage()."\n".$e->getTraceAsString()); + $errMsg = $e->getMessage(); + $errTrace = $e->getTraceAsString(); + $logDB->insert('api_log', [ + 'user_id' => $session->userID, + 'ip' => $ip, + 'date' => $date, + 'path' => $actionPath, + 'arg' => JSON::encode($filteredArgs), + 'aux' => JSON::encode([ + 'result'=>false, + 'state'=>'error_throwable', + 'errMsg'=>$errMsg, + 'errTrace'=>$errTrace, + ]), + ]); + Json::dieWithReason("{$errMsg}\n{$errTrace}"); } catch (mixed $e) { - Json::dieWithReason(strval($e)); + $errStr = strval($e); + $logDB->insert('api_log', [ + 'user_id' => $session->userID, + 'ip' => $ip, + 'date' => $date, + 'path' => $actionPath, + 'arg' => JSON::encode($filteredArgs), + 'aux' => JSON::encode([ + 'result'=>false, + 'state'=>'error_mixed', + 'errMsg'=>$errStr, + ]), + ]); + Json::dieWithReason($errStr); } } }