LogService.php 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. <?php
  2. namespace services\common;
  3. use Yii;
  4. use common\models\common\Log;
  5. use common\enums\AppEnum;
  6. use common\enums\MessageLevelEnum;
  7. use common\enums\StatusEnum;
  8. use common\helpers\ArrayHelper;
  9. use common\helpers\DebrisHelper;
  10. use common\queues\LogJob;
  11. use common\helpers\EchantsHelper;
  12. use common\enums\SubscriptionActionEnum;
  13. /**
  14. * Class LogService
  15. * @package services\common
  16. */
  17. class LogService
  18. {
  19. /**
  20. * 丢进队列
  21. *
  22. * @var bool
  23. */
  24. public $queueSwitch = false;
  25. /**
  26. * 不记录的状态码
  27. *
  28. * @var array
  29. */
  30. public $exceptCode = [];
  31. /**
  32. * @param $error_code
  33. * @param $error_msg
  34. * @param $error_data
  35. * @return Log|false|string|null
  36. * @throws \yii\base\InvalidConfigException
  37. */
  38. public function push($error_code, $error_msg, $error_data)
  39. {
  40. $log = $this->initData();
  41. $log->error_code = $error_code;
  42. $log->error_msg = $error_msg;
  43. $log->error_data = $error_data;
  44. try {
  45. // 判断是否开启队列
  46. if ($this->queueSwitch == true) {
  47. $message_id = Yii::$app->queue->push(new LogJob([
  48. 'log' => $log,
  49. ]));
  50. return $message_id;
  51. }
  52. return $this->realCreate($log);
  53. } catch (\Exception $e) {
  54. return false;
  55. }
  56. }
  57. /**
  58. * 日志记录
  59. *
  60. *
  61. * @param $response
  62. * @param bool $showReqId
  63. * @return array
  64. * @throws \yii\base\InvalidConfigException
  65. * @throws \Exception
  66. */
  67. public function record($response, $showReqId = false)
  68. {
  69. $errData = [];
  70. // 判断是否记录日志
  71. if (in_array($this->getLevel($response->statusCode), Yii::$app->params['user.log.level'])) {
  72. if (is_array($response->statusText)) {
  73. $errData = $response->statusText;
  74. $errorMessage = $errData['errorMessage'] ?? '';
  75. $showReqId && $response->data['req_id'] = Yii::$app->params['uuid'];
  76. } else {
  77. $errorMessage = $response->statusText;
  78. }
  79. // 检查是否报错
  80. if (
  81. empty($errData) &&
  82. $response->statusCode >= 300 &&
  83. ($exception = Yii::$app->getErrorHandler()->exception)
  84. ) {
  85. $errData = [
  86. 'type' => get_class($exception),
  87. 'file' => method_exists($exception, 'getFile') ? $exception->getFile() : '',
  88. 'errorMessage' => $exception->getMessage(),
  89. 'line' => $exception->getLine(),
  90. 'stack-trace' => explode("\n", $exception->getTraceAsString()),
  91. ];
  92. $errorMessage = $exception->getMessage();
  93. $showReqId && $response->data['req_id'] = Yii::$app->params['uuid'];
  94. }
  95. // 排除状态码
  96. if (
  97. Yii::$app->params['user.log'] &&
  98. !Yii::$app->request->isOptions &&
  99. !in_array($response->statusCode, ArrayHelper::merge($this->exceptCode, Yii::$app->params['user.log.except.code']))
  100. ) {
  101. $this->push($response->statusCode, $errorMessage, $errData);
  102. }
  103. }
  104. return $errData;
  105. }
  106. /**
  107. * 初始化数据
  108. *
  109. * @return Log
  110. * @throws \yii\base\InvalidConfigException
  111. */
  112. public function initData()
  113. {
  114. $model = new Log();
  115. $model->url = DebrisHelper::getUrl();
  116. $model->app_id = Yii::$app->id;
  117. $model->get_data = Yii::$app->request->get();
  118. $model->post_data = Yii::$app->request->post();
  119. $model->header_data = ArrayHelper::toArray(Yii::$app->request->headers);
  120. $model->method = Yii::$app->request->method;
  121. $model->module = Yii::$app->controller->module->id ?? '';
  122. $model->controller = Yii::$app->controller->id ?? '';
  123. $model->action = Yii::$app->controller->action->id ?? '';
  124. $model->req_id = Yii::$app->params['uuid'];
  125. $model->device = Yii::$app->services->extendDetection->detectVersion();
  126. $model->ip = Yii::$app->services->base->getUserIp();
  127. if (in_array(Yii::$app->id, AppEnum::api())) {
  128. $model->member_id = Yii::$app->user->identity->member_id ?? 0;
  129. } else {
  130. $model->member_id = Yii::$app->user->id ?? 0;
  131. $model->member_name = Yii::$app->user->nickname ?? '';
  132. }
  133. // 插件里面
  134. if (Yii::$app->params['inAddon'] == true) {
  135. $model->addon_name = Yii::$app->params['addon']['name'];
  136. $model->is_addon = StatusEnum::ENABLED;
  137. }
  138. return $model;
  139. }
  140. /**
  141. * 真实写入
  142. *
  143. * @param $data
  144. */
  145. public function realCreate(Log $log)
  146. {
  147. $log->save();
  148. // 记录风控日志
  149. // Yii::$app->services->reportLog->create($log);
  150. // 提醒
  151. $log->error_code >= 500 && Yii::$app->services->notify->sendRemind($log->id, SubscriptionActionEnum::ERROR, 0, [], '/common/log/view?id=' . $log->id);
  152. return $log;
  153. }
  154. /**
  155. * 状态报表统计
  156. *
  157. * @param $type
  158. * @return array
  159. */
  160. public function stat($type)
  161. {
  162. $fields = [];
  163. $codes = [400, 401, 403, 404, 405, 422, 429, 500];
  164. foreach ($codes as $code) {
  165. $fields[$code] = $code . '错误';
  166. }
  167. // 获取时间和格式化
  168. list($time, $format) = EchantsHelper::getFormatTime($type);
  169. // 获取数据
  170. return EchantsHelper::lineOrBarInTime(function ($start_time, $end_time, $formatting) use ($codes) {
  171. $statData = Log::find()
  172. ->select(["from_unixtime(created_at, '$formatting') as time", 'count(id) as count', 'error_code'])
  173. ->andWhere(['between', 'created_at', $start_time, $end_time])
  174. ->andWhere(['status' => StatusEnum::ENABLED])
  175. ->andWhere(['in', 'error_code', $codes])
  176. ->andFilterWhere(['merchant_id' => Yii::$app->services->merchant->getId()])
  177. ->groupBy(['time', 'error_code'])
  178. ->asArray()
  179. ->all();
  180. return EchantsHelper::regroupTimeData($statData, 'error_code');
  181. }, $fields, $time, $format);
  182. }
  183. /**
  184. * 流量报表统计
  185. *
  186. * @param $type
  187. * @return array
  188. */
  189. public function flowStat($type)
  190. {
  191. $fields = [
  192. 'count' => '访问量(PV)',
  193. 'member_id' => '访问人数(UV)',
  194. 'ip' => '访问 IP',
  195. ];
  196. // 获取时间和格式化
  197. list($time, $format) = EchantsHelper::getFormatTime($type);
  198. // 获取数据
  199. return EchantsHelper::lineOrBarInTime(function ($start_time, $end_time, $formatting) {
  200. return Log::find()
  201. ->select(["from_unixtime(created_at, '$formatting') as time", 'count(id) as count', 'count(distinct(ip)) as ip', 'count(distinct(member_id)) as member_id'])
  202. ->andWhere(['between', 'created_at', $start_time, $end_time])
  203. ->andWhere(['status' => StatusEnum::ENABLED])
  204. ->andFilterWhere(['merchant_id' => Yii::$app->services->merchant->getId()])
  205. ->groupBy(['time'])
  206. ->asArray()
  207. ->all();
  208. }, $fields, $time, $format);
  209. }
  210. /**
  211. * 获取报错级别
  212. *
  213. * @param $statusCode
  214. * @return bool|string
  215. */
  216. private function getLevel($statusCode)
  217. {
  218. if ($statusCode < 300) {
  219. return MessageLevelEnum::SUCCESS;
  220. } elseif ($statusCode >= 300 && $statusCode < 400) {
  221. return MessageLevelEnum::INFO;
  222. } elseif ($statusCode >= 400 && $statusCode < 500) {
  223. return MessageLevelEnum::WARNING;
  224. } elseif ($statusCode >= 500) {
  225. return MessageLevelEnum::ERROR;
  226. }
  227. return MessageLevelEnum::ERROR;
  228. }
  229. }
粤ICP备19079148号